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))

def freeze(data_structure):
    """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))
    """
    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)