Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/dns/immutable.py: 27%
41 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-02 06:07 +0000
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-02 06:07 +0000
1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
3import collections.abc
4from typing import Any, Callable
6from dns._immutable_ctx import immutable
9@immutable
10class Dict(collections.abc.Mapping): # lgtm[py/missing-equals]
11 def __init__(
12 self,
13 dictionary: Any,
14 no_copy: bool = False,
15 map_factory: Callable[[], collections.abc.MutableMapping] = dict,
16 ):
17 """Make an immutable dictionary from the specified dictionary.
19 If *no_copy* is `True`, then *dictionary* will be wrapped instead
20 of copied. Only set this if you are sure there will be no external
21 references to the dictionary.
22 """
23 if no_copy and isinstance(dictionary, collections.abc.MutableMapping):
24 self._odict = dictionary
25 else:
26 self._odict = map_factory()
27 self._odict.update(dictionary)
28 self._hash = None
30 def __getitem__(self, key):
31 return self._odict.__getitem__(key)
33 def __hash__(self): # pylint: disable=invalid-hash-returned
34 if self._hash is None:
35 h = 0
36 for key in sorted(self._odict.keys()):
37 h ^= hash(key)
38 object.__setattr__(self, "_hash", h)
39 # this does return an int, but pylint doesn't figure that out
40 return self._hash
42 def __len__(self):
43 return len(self._odict)
45 def __iter__(self):
46 return iter(self._odict)
49def constify(o: Any) -> Any:
50 """
51 Convert mutable types to immutable types.
52 """
53 if isinstance(o, bytearray):
54 return bytes(o)
55 if isinstance(o, tuple):
56 try:
57 hash(o)
58 return o
59 except Exception:
60 return tuple(constify(elt) for elt in o)
61 if isinstance(o, list):
62 return tuple(constify(elt) for elt in o)
63 if isinstance(o, dict):
64 cdict = dict()
65 for k, v in o.items():
66 cdict[k] = constify(v)
67 return Dict(cdict, True)
68 return o