v0.165.0
 1from typing import Any
 2
 3from plain.utils.itercompat import is_iterable
 4
 5
 6def make_hashable(value: Any) -> Any:
 7    """
 8    Attempt to make value hashable or raise a TypeError if it fails.
 9
10    The returned value should generate the same hash for equal values.
11    """
12    if isinstance(value, dict):
13        return tuple(
14            [
15                (key, make_hashable(nested_value))
16                for key, nested_value in sorted(value.items())
17            ]
18        )
19    # Try hash to avoid converting a hashable iterable (e.g. string, frozenset)
20    # to a tuple.
21    try:
22        hash(value)
23    except TypeError:
24        if is_iterable(value):
25            return tuple(map(make_hashable, value))
26        # Non-hashable, non-iterable.
27        raise
28    return value