def test_markdown_flag(self): """Test that ExceptionProtos for StreamlitAPIExceptions (and subclasses) have the "message_is_markdown" flag set. """ proto = ExceptionProto() exception.marshall(proto, RuntimeError("oh no!")) self.assertFalse(proto.message_is_markdown) proto = ExceptionProto() exception.marshall(proto, StreamlitAPIException("oh no!")) self.assertTrue(proto.message_is_markdown) proto = ExceptionProto() exception.marshall(proto, errors.DuplicateWidgetID("oh no!")) self.assertTrue(proto.message_is_markdown)
def test_unhashable_type(self): @st.experimental_memo def unhashable_type_func(lock: threading.Lock): return str(lock) with self.assertRaises(UnhashableParamError) as cm: unhashable_type_func(threading.Lock()) ep = ExceptionProto() exception.marshall(ep, cm.exception) self.assertEqual(ep.type, "UnhashableParamError") expected_message = """ Cannot hash argument 'lock' (of type `_thread.lock`) in 'unhashable_type_func'. To address this, you can tell Streamlit not to hash this argument by adding a leading underscore to the argument's name in the function signature: ``` @st.experimental_memo def unhashable_type_func(_lock, ...): ... ``` """ self.assertEqual(testutil.normalize_md(expected_message), testutil.normalize_md(ep.message)) # Stack trace doesn't show in test :( # self.assertNotEqual(len(ep.stack_trace), 0) self.assertEqual(ep.message_is_markdown, True) self.assertEqual(ep.is_warning, False)
def test_unhashable_type(self): @st.cache def unhashable_type_func(): return threading.Lock() with self.assertRaises(hashing.UnhashableTypeError) as cm: unhashable_type_func() ep = ExceptionProto() exception.marshall(ep, cm.exception) self.assertEqual(ep.type, "UnhashableTypeError") self.assertTrue( normalize_md(ep.message).startswith( normalize_md( """ Cannot hash object of type `_thread.lock`, found in the return value of `unhashable_type_func()`. While caching the return value of `unhashable_type_func()`, Streamlit encountered an object of type `_thread.lock`, which it does not know how to hash. To address this, please try helping Streamlit understand how to hash that type by passing the `hash_funcs` argument into `@st.cache`. For example: ``` @st.cache(hash_funcs={_thread.lock: my_hash_func}) def my_func(...): ... ``` If you don't know where the object of type `_thread.lock` is coming from, try looking at the hash chain below for an object that you do recognize, then pass that to `hash_funcs` instead: ``` Object of type _thread.lock: """ ) ) ) # Stack trace doesn't show in test :( # self.assertNotEqual(len(ep.stack_trace), 0) self.assertEqual(ep.message_is_markdown, True) self.assertEqual(ep.is_warning, False)
def test_user_hash_error(self): class MyObj(object): pass def bad_hash_func(x): x += 10 # Throws a TypeError since x has type MyObj. return x @st.cache(hash_funcs={MyObj: bad_hash_func}) def user_hash_error_func(x): pass with self.assertRaises(hashing.UserHashError) as cm: my_obj = MyObj() user_hash_error_func(my_obj) ep = ExceptionProto() exception.marshall(ep, cm.exception) self.assertEqual(ep.type, "TypeError") self.assertTrue( normalize_md(ep.message).startswith( normalize_md( """ unsupported operand type(s) for +=: 'MyObj' and 'int' This error is likely due to a bug in `bad_hash_func()`, which is a user-defined hash function that was passed into the `@st.cache` decorator of `user_hash_error_func()`. `bad_hash_func()` failed when hashing an object of type `caching_test.CacheErrorsTest.test_user_hash_error.<locals>.MyObj`. If you don't know where that object is coming from, try looking at the hash chain below for an object that you do recognize, then pass that to `hash_funcs` instead: ``` Object of type caching_test.CacheErrorsTest.test_user_hash_error.<locals>.MyObj: <caching_test.CacheErrorsTest.test_user_hash_error.<locals>.MyObj object at """ ) ) ) # Stack trace doesn't show in test :( # self.assertNotEqual(len(ep.stack_trace), 0) self.assertEqual(ep.message_is_markdown, True) self.assertEqual(ep.is_warning, False)
def exception(self, exception): """Display an exception. Parameters ---------- exception : Exception The exception to display. Example ------- >>> e = RuntimeError('This is an exception of type RuntimeError') >>> st.exception(e) """ exception_proto = ExceptionProto() marshall(exception_proto, exception) return self.dg._enqueue("exception", exception_proto)
def test_uncaught_app_exception(self): err = None try: st.format("http://not_an_image.png", width=-1) except Exception as e: err = UncaughtAppException(e) self.assertIsNotNone(err) # Marshall it. proto = ExceptionProto() exception.marshall(proto, err) for line in proto.stack_trace: # assert message that could contain secret information in the stack trace assert "module 'streamlit' has no attribute 'format'" not in line assert proto.message == _GENERIC_UNCAUGHT_EXCEPTION_TEXT assert proto.type == "AttributeError"
def exception(self, exception: BaseException) -> "DeltaGenerator": """Display an exception. Parameters ---------- exception : Exception The exception to display. Example ------- >>> e = RuntimeError('This is an exception of type RuntimeError') >>> st.exception(e) """ exception_proto = ExceptionProto() marshall(exception_proto, exception) dg = self.dg._enqueue("exception", exception_proto) return cast("DeltaGenerator", dg)
def test_strip_streamlit_stack_entries(self): """Test that StreamlitAPIExceptions don't include Streamlit entries in the stack trace. """ # Create a StreamlitAPIException. err = None try: st.image("http://not_an_image.png", width=-1) except StreamlitAPIException as e: err = e self.assertIsNotNone(err) # Marshall it. proto = ExceptionProto() exception.marshall(proto, err) # The streamlit package should not appear in any stack entry. streamlit_dir = os.path.dirname(st.__file__) streamlit_dir = os.path.join(os.path.realpath(streamlit_dir), "") for line in proto.stack_trace: self.assertNotIn(streamlit_dir, line, "Streamlit stack entry not stripped")