Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/blinker/_utilities.py: 55%

55 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-22 06:29 +0000

1from __future__ import annotations 

2 

3import typing as t 

4from weakref import ref 

5 

6from blinker._saferef import BoundMethodWeakref 

7 

8IdentityType = t.Union[t.Tuple[int, int], str, int] 

9 

10 

11class _symbol: 

12 def __init__(self, name): 

13 """Construct a new named symbol.""" 

14 self.__name__ = self.name = name 

15 

16 def __reduce__(self): 

17 return symbol, (self.name,) 

18 

19 def __repr__(self): 

20 return self.name 

21 

22 

23_symbol.__name__ = "symbol" 

24 

25 

26class symbol: 

27 """A constant symbol. 

28 

29 >>> symbol('foo') is symbol('foo') 

30 True 

31 >>> symbol('foo') 

32 foo 

33 

34 A slight refinement of the MAGICCOOKIE=object() pattern. The primary 

35 advantage of symbol() is its repr(). They are also singletons. 

36 

37 Repeated calls of symbol('name') will all return the same instance. 

38 

39 """ 

40 

41 symbols = {} # type: ignore[var-annotated] 

42 

43 def __new__(cls, name): 

44 try: 

45 return cls.symbols[name] 

46 except KeyError: 

47 return cls.symbols.setdefault(name, _symbol(name)) 

48 

49 

50def hashable_identity(obj: object) -> IdentityType: 

51 if hasattr(obj, "__func__"): 

52 return (id(obj.__func__), id(obj.__self__)) # type: ignore[attr-defined] 

53 elif hasattr(obj, "im_func"): 

54 return (id(obj.im_func), id(obj.im_self)) # type: ignore[attr-defined] 

55 elif isinstance(obj, (int, str)): 

56 return obj 

57 else: 

58 return id(obj) 

59 

60 

61WeakTypes = (ref, BoundMethodWeakref) 

62 

63 

64class annotatable_weakref(ref): 

65 """A weakref.ref that supports custom instance attributes.""" 

66 

67 receiver_id: t.Optional[IdentityType] 

68 sender_id: t.Optional[IdentityType] 

69 

70 

71def reference( # type: ignore[no-untyped-def] 

72 object, callback=None, **annotations 

73) -> annotatable_weakref: 

74 """Return an annotated weak ref.""" 

75 if callable(object): 

76 weak = callable_reference(object, callback) 

77 else: 

78 weak = annotatable_weakref(object, callback) 

79 for key, value in annotations.items(): 

80 setattr(weak, key, value) 

81 return weak # type: ignore[no-any-return] 

82 

83 

84def callable_reference(object, callback=None): 

85 """Return an annotated weak ref, supporting bound instance methods.""" 

86 if hasattr(object, "im_self") and object.im_self is not None: 

87 return BoundMethodWeakref(target=object, on_delete=callback) 

88 elif hasattr(object, "__self__") and object.__self__ is not None: 

89 return BoundMethodWeakref(target=object, on_delete=callback) 

90 return annotatable_weakref(object, callback) 

91 

92 

93class lazy_property: 

94 """A @property that is only evaluated once.""" 

95 

96 def __init__(self, deferred): 

97 self._deferred = deferred 

98 self.__doc__ = deferred.__doc__ 

99 

100 def __get__(self, obj, cls): 

101 if obj is None: 

102 return self 

103 value = self._deferred(obj) 

104 setattr(obj, self._deferred.__name__, value) 

105 return value