| |
|
|
| import collections.abc |
| from typing import Any, Callable |
|
|
| from dns._immutable_ctx import immutable |
|
|
|
|
| @immutable |
| class Dict(collections.abc.Mapping): |
| def __init__( |
| self, |
| dictionary: Any, |
| no_copy: bool = False, |
| map_factory: Callable[[], collections.abc.MutableMapping] = dict, |
| ): |
| """Make an immutable dictionary from the specified dictionary. |
| |
| If *no_copy* is `True`, then *dictionary* will be wrapped instead |
| of copied. Only set this if you are sure there will be no external |
| references to the dictionary. |
| """ |
| if no_copy and isinstance(dictionary, collections.abc.MutableMapping): |
| self._odict = dictionary |
| else: |
| self._odict = map_factory() |
| self._odict.update(dictionary) |
| self._hash = None |
|
|
| def __getitem__(self, key): |
| return self._odict.__getitem__(key) |
|
|
| def __hash__(self): |
| if self._hash is None: |
| h = 0 |
| for key in sorted(self._odict.keys()): |
| h ^= hash(key) |
| object.__setattr__(self, "_hash", h) |
| |
| return self._hash |
|
|
| def __len__(self): |
| return len(self._odict) |
|
|
| def __iter__(self): |
| return iter(self._odict) |
|
|
|
|
| def constify(o: Any) -> Any: |
| """ |
| Convert mutable types to immutable types. |
| """ |
| if isinstance(o, bytearray): |
| return bytes(o) |
| if isinstance(o, tuple): |
| try: |
| hash(o) |
| return o |
| except Exception: |
| return tuple(constify(elt) for elt in o) |
| if isinstance(o, list): |
| return tuple(constify(elt) for elt in o) |
| if isinstance(o, dict): |
| cdict = dict() |
| for k, v in o.items(): |
| cdict[k] = constify(v) |
| return Dict(cdict, True) |
| return o |
|
|