code: def freeze(data_structure):
      
      def freeze_helper(data_structure):
          # We don't freeze primitive types
          if isinstance(data_structure, _primitive_types):
              return data_structure
          was_dict = False
          if (
              hasattr(data_structure, "__slots__") and
              not isinstance(data_structure, (Meta, IDD, WasDict))
          ):
              data_structure = tuple(object_to_items(data_structure))
              was_dict = True
          else:
              # Dictize if possible (support objects)
              try:
                  data_structure = data_structure.__dict__
                  was_dict = True
              except:
                  pass
              # Itemize if needed
              try:
                  data_structure = data_structure.items()
              except:
                  pass
          tlen = -1
          # If item has a length we freeze it
          try:
              tlen = len(data_structure)
          except:  # pragma: no cover
              pass
          if tlen != -1:
              # Well there are classes out in the wild that answer to len
              # but have no indexer.
              try:
                  if was_dict:
                      return WasDict([
                          freeze_helper(x) for x in data_structure
                      ])
                  else:
                      return tuple([
                          freeze_helper(x) for x in data_structure
                      ])
              except:  # pragma: no cover
                  pass
          return data_structure  # pragma: no cover
      return freeze_helper(data_structure)
docs: Freeze tries to convert any data-structure in a hierarchy of tuples.
      Tuples are comparable/sortable/hashable, you can use this with
      with recursive_sort(). freeze has no recursion detection.
  
      :param   data_structure: The structure to convert.
  
      >>> recursive_sort(freeze(_TestClass(True)))
      (('a', 'huhu'), ('sub', (('a', 'slot'), ('b', (1, (1, 2, 3), 2, 3)))))
      >>> dump((None, (None, None)))
      (None, (None, None))