class_docstr: Make sure user-visible error messages look correct.
  
  These errors are a little annoying to test, but they're important! So we
  are testing them word-for-word as much as possible. Even though this
  *feels* like an antipattern, it isn't: we're making sure the codepaths
  that pull useful debug info from the code are working.
  
  TODO: parameterize these tests for both memo + singleton
class_docstr_tok: ["Make","sure","user-visible","error","messages","look","correct",".","These","errors","are","a","little","annoying","to","test",",","but","they","'re","important","!","So","we","are","testing","them","word-for-word","as","much","as","possible",".","Even","though","this","*","feels","*","like","an","antipattern",",","it","is","n't",":","we","'re","making","sure","the","codepaths","that","pull","useful","debug","info","from","the","code","are","working",".","TODO",":","parameterize","these","tests","for","both","memo","+","singleton"]
code: def test_unhashable_type(self):
      @st.cache_data
      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.cache_data
  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)
  
file_path: streamlit/lib/tests/streamlit/runtime/caching/cache_errors_test.py
imports: import threading
  from parameterized import parameterized
  import streamlit
  from streamlit.elements import exception
  from streamlit.proto.Exception_pb2 import Exception
  from streamlit.runtime.caching.cache_errors import UnevaluatedDataFrameError, UnhashableParamError, UnserializableReturnValueError, get_return_value_type
  from streamlit.runtime.caching.cache_utils import UNEVALUATED_DATAFRAME_TYPES
  from tests import testutil
  from tests.delta_generator_test_case import DeltaGeneratorTestCase
  from tests.streamlit import pyspark_mocks, snowpark_mocks
label_desc: Use image node_id 1 for calling the CacheErrorsTest obj's underlying member method code with example usage: obj.test_unhashable_type() and returns: str