class_docstr: A hasher that can hash objects with cycles.
class_docstr_tok: ["A","hasher","that","can","hash","objects","with","cycles","."]
docstr: Hash objects to bytes, including code with dependencies.
  
  Python's built in `hash` does not produce consistent results across
  runs.
docstr_tok: ["Hash","objects","to","bytes",",","including","code","with","dependencies",".","Python","'s","built","in","`","hash","`","does","not","produce","consistent","results","across","runs","."]
code: def _to_bytes(self, obj: Any) -> bytes:
      """Hash objects to bytes, including code with dependencies.
  
      Python's built in `hash` does not produce consistent results across
      runs.
      """
  
      h = hashlib.new("md5", **HASHLIB_KWARGS)
  
      if isinstance(obj, unittest.mock.Mock):
          # Mock objects can appear to be infinitely
          # deep, so we don't try to hash them at all.
          return self.to_bytes(id(obj))
  
      elif isinstance(obj, bytes) or isinstance(obj, bytearray):
          return obj
  
      elif type_util.get_fqn_type(obj) in self._hash_funcs:
          # Escape hatch for unsupported objects
          hash_func = self._hash_funcs[type_util.get_fqn_type(obj)]
          try:
              output = hash_func(obj)
          except Exception as ex:
              raise UserHashError(
                  ex,
                  obj,
                  hash_func=hash_func,
                  cache_type=self.cache_type,
              ) from ex
          return self.to_bytes(output)
  
      elif isinstance(obj, str):
          return obj.encode()
  
      elif isinstance(obj, float):
          return _float_to_bytes(obj)
  
      elif isinstance(obj, int):
          return _int_to_bytes(obj)
  
      elif isinstance(obj, uuid.UUID):
          return obj.bytes
  
      elif isinstance(obj, datetime.datetime):
          return obj.isoformat().encode()
  
      elif isinstance(obj, (list, tuple)):
          for item in obj:
              self.update(h, item)
          return h.digest()
  
      elif isinstance(obj, dict):
          for item in obj.items():
              self.update(h, item)
          return h.digest()
  
      elif obj is None:
          return b"0"
  
      elif obj is True:
          return b"1"
  
      elif obj is False:
          return b"0"
  
      elif dataclasses.is_dataclass(obj):
          return self.to_bytes(dataclasses.asdict(obj))
  
      elif isinstance(obj, Enum):
          return str(obj).encode()
  
      elif type_util.is_type(obj, "pandas.core.series.Series"):
          import pandas as pd
  
          self.update(h, obj.size)
          self.update(h, obj.dtype.name)
  
          if len(obj) >= _PANDAS_ROWS_LARGE:
              obj = obj.sample(n=_PANDAS_SAMPLE_SIZE, random_state=0)
  
          try:
              self.update(
                  h, pd.util.hash_pandas_object(obj).values.tobytes()
              )
              return h.digest()
          except TypeError:
              # Use pickle if pandas cannot hash the object for example if
              # it contains unhashable objects.
              return b"%s" % pickle.dumps(obj, pickle.HIGHEST_PROTOCOL)
  
      elif type_util.is_type(obj, "pandas.core.frame.DataFrame"):
          import pandas as pd
  
          self.update(h, obj.shape)
  
          if len(obj) >= _PANDAS_ROWS_LARGE:
              obj = obj.sample(n=_PANDAS_SAMPLE_SIZE, random_state=0)
          try:
              column_hash_bytes = self.to_bytes(
                  pd.util.hash_pandas_object(obj.dtypes)
              )
              self.update(h, column_hash_bytes)
              values_hash_bytes = self.to_bytes(
                  pd.util.hash_pandas_object(obj)
              )
              self.update(h, values_hash_bytes)
              return h.digest()
          except TypeError:
              # Use pickle if pandas cannot hash the object for example if
              # it contains unhashable objects.
              return b"%s" % pickle.dumps(obj, pickle.HIGHEST_PROTOCOL)
  
      elif type_util.is_type(obj, "numpy.ndarray"):
          self.update(h, obj.shape)
          self.update(h, str(obj.dtype))
  
          if obj.size >= _NP_SIZE_LARGE:
              import numpy as np
  
              state = np.random.RandomState(0)
              obj = state.choice(obj.flat, size=_NP_SAMPLE_SIZE)
  
          self.update(h, obj.tobytes())
          return h.digest()
      elif type_util.is_type(obj, "PIL.Image.Image"):
          import numpy as np
  
          # we don't just hash the results of obj.tobytes() because we want to use
          # the sampling logic for numpy data
          np_array = np.frombuffer(obj.tobytes(), dtype="uint8")
          return self.to_bytes(np_array)
  
      elif inspect.isbuiltin(obj):
          return bytes(obj.__name__.encode())
  
      elif type_util.is_type(
          obj, "builtins.mappingproxy"
      ) or type_util.is_type(obj, "builtins.dict_items"):
          return self.to_bytes(dict(obj))
  
      elif type_util.is_type(obj, "builtins.getset_descriptor"):
          return bytes(obj.__qualname__.encode())
  
      elif isinstance(obj, UploadedFile):
          # UploadedFile is a BytesIO (thus IOBase) but has a name.
          # It does not have a timestamp so this must come before
          # temporary files
          self.update(h, obj.name)
          self.update(h, obj.tell())
          self.update(h, obj.getvalue())
          return h.digest()
  
      elif hasattr(obj, "name") and (
          isinstance(obj, io.IOBase)
          # Handle temporary files used during testing
          or isinstance(obj, tempfile._TemporaryFileWrapper)
      ):
          # Hash files as name + last modification date + offset.
          # NB: we're using hasattr("name") to differentiate between
          # on-disk and in-memory StringIO/BytesIO file representations.
          # That means that this condition must come *before* the next
          # condition, which just checks for StringIO/BytesIO.
          obj_name = getattr(
              obj, "name", "wonthappen"
          )  # Just to appease MyPy.
          self.update(h, obj_name)
          self.update(h, os.path.getmtime(obj_name))
          self.update(h, obj.tell())
          return h.digest()
  
      elif isinstance(obj, Pattern):
          return self.to_bytes([obj.pattern, obj.flags])
  
      elif isinstance(obj, io.StringIO) or isinstance(obj, io.BytesIO):
          # Hash in-memory StringIO/BytesIO by their full contents
          # and seek position.
          self.update(h, obj.tell())
          self.update(h, obj.getvalue())
          return h.digest()
  
      elif type_util.is_type(obj, "numpy.ufunc"):
          # For numpy.remainder, this returns remainder.
          return bytes(obj.__name__.encode())
  
      elif inspect.ismodule(obj):
          # TODO: Figure out how to best show this kind of warning to the
          # user. In the meantime, show nothing. This scenario is too common,
          # so the current warning is quite annoying...
          # st.warning(('Streamlit does not support hashing modules. '
          #             'We did not hash `%s`.') % obj.__name__)
          # TODO: Hash more than just the name for internal modules.
          return self.to_bytes(obj.__name__)
  
      elif inspect.isclass(obj):
          # TODO: Figure out how to best show this kind of warning to the
          # user. In the meantime, show nothing. This scenario is too common,
          # (e.g. in every "except" statement) so the current warning is
          # quite annoying...
          # st.warning(('Streamlit does not support hashing classes. '
          #             'We did not hash `%s`.') % obj.__name__)
          # TODO: Hash more than just the name of classes.
          return self.to_bytes(obj.__name__)
  
      elif isinstance(obj, functools.partial):
          # The return value of functools.partial is not a plain function:
          # it's a callable object that remembers the original function plus
          # the values you pickled into it. So here we need to special-case it.
          self.update(h, obj.args)
          self.update(h, obj.func)
          self.update(h, obj.keywords)
          return h.digest()
  
      else:
          # As a last resort, hash the output of the object's __reduce__ method
          try:
              reduce_data = obj.__reduce__()
          except Exception as ex:
              raise UnhashableTypeError() from ex
  
          for item in reduce_data:
              self.update(h, item)
          return h.digest()
  
imports: import collections
  import dataclasses
  import datetime
  import functools
  import hashlib
  import inspect
  import io
  import os
  import pickle
  import struct
  import sys
  import tempfile
  import threading
  import unittest.mock
  import uuid
  import weakref
  from enum import Enum
  from typing import Any, Callable, Dict, List, Optional, Pattern, Type, Union
  from streamlit import type_util, util
  from streamlit.errors import StreamlitAPIException
  from streamlit.runtime.caching.cache_errors import UnhashableTypeError
  from streamlit.runtime.caching.cache_type import CacheType
  from streamlit.runtime.uploaded_file_manager import UploadedFile
  from streamlit.util import HASHLIB_KWARGS
label_desc: Use image node_id 5 for calling the _CacheFuncHasher obj's underlying member method code with example usage: obj._to_bytes(obj) and returns: self, obj, self, obj, _float_to_bytes, _int_to_bytes, obj, obj, h, h, bytes, bytes, bytes, self, str, h, unknown, h, h, unknown, self, bytes, self, bytes, h, h, self, h, bytes, self, self, h, h