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

1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license 

2 

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. 

6 

7import contextvars 

8import inspect 

9 

10_in__init__ = contextvars.ContextVar("_immutable_in__init__", default=False) 

11 

12 

13class _Immutable: 

14 """Immutable mixin class""" 

15 

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. 

19 

20 __slots__ = () 

21 

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) 

27 

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) 

33 

34 

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) 

43 

44 nf.__signature__ = inspect.signature(f) 

45 return nf 

46 

47 

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__ = () 

61 

62 @_immutable_init 

63 def __init__(self, *args, **kwargs): 

64 super().__init__(*args, **kwargs) 

65 

66 if hasattr(cls, "__setstate__"): 

67 

68 @_immutable_init 

69 def __setstate__(self, *args, **kwargs): 

70 super().__setstate__(*args, **kwargs) 

71 

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