Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/dns/_immutable_ctx.py: 88%
40 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
3# This implementation of the immutable decorator requires python >=
4# 3.7, and is significantly more storage efficient when making classes
5# with slots immutable. It's also faster.
7import contextvars
8import inspect
10_in__init__ = contextvars.ContextVar("_immutable_in__init__", default=False)
13class _Immutable:
14 """Immutable mixin class"""
16 # We set slots to the empty list to say "we don't have any attributes".
17 # We do this so that if we're mixed in with a class with __slots__, we
18 # don't cause a __dict__ to be added which would waste space.
20 __slots__ = ()
22 def __setattr__(self, name, value):
23 if _in__init__.get() is not self:
24 raise TypeError("object doesn't support attribute assignment")
25 else:
26 super().__setattr__(name, value)
28 def __delattr__(self, name):
29 if _in__init__.get() is not self:
30 raise TypeError("object doesn't support attribute assignment")
31 else:
32 super().__delattr__(name)
35def _immutable_init(f):
36 def nf(*args, **kwargs):
37 previous = _in__init__.set(args[0])
38 try:
39 # call the actual __init__
40 f(*args, **kwargs)
41 finally:
42 _in__init__.reset(previous)
44 nf.__signature__ = inspect.signature(f)
45 return nf
48def immutable(cls):
49 if _Immutable in cls.__mro__:
50 # Some ancestor already has the mixin, so just make sure we keep
51 # following the __init__ protocol.
52 cls.__init__ = _immutable_init(cls.__init__)
53 if hasattr(cls, "__setstate__"):
54 cls.__setstate__ = _immutable_init(cls.__setstate__)
55 ncls = cls
56 else:
57 # Mixin the Immutable class and follow the __init__ protocol.
58 class ncls(_Immutable, cls):
59 # We have to do the __slots__ declaration here too!
60 __slots__ = ()
62 @_immutable_init
63 def __init__(self, *args, **kwargs):
64 super().__init__(*args, **kwargs)
66 if hasattr(cls, "__setstate__"):
68 @_immutable_init
69 def __setstate__(self, *args, **kwargs):
70 super().__setstate__(*args, **kwargs)
72 # make ncls have the same name and module as cls
73 ncls.__name__ = cls.__name__
74 ncls.__qualname__ = cls.__qualname__
75 ncls.__module__ = cls.__module__
76 return ncls