Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/blinker/_utilities.py: 45%
78 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
1from __future__ import annotations
3import asyncio
4import inspect
5import sys
6import typing as t
7from functools import partial
8from weakref import ref
10from blinker._saferef import BoundMethodWeakref
12IdentityType = t.Union[t.Tuple[int, int], str, int]
15class _symbol:
16 def __init__(self, name):
17 """Construct a new named symbol."""
18 self.__name__ = self.name = name
20 def __reduce__(self):
21 return symbol, (self.name,)
23 def __repr__(self):
24 return self.name
27_symbol.__name__ = "symbol"
30class symbol:
31 """A constant symbol.
33 >>> symbol('foo') is symbol('foo')
34 True
35 >>> symbol('foo')
36 foo
38 A slight refinement of the MAGICCOOKIE=object() pattern. The primary
39 advantage of symbol() is its repr(). They are also singletons.
41 Repeated calls of symbol('name') will all return the same instance.
43 """
45 symbols = {} # type: ignore[var-annotated]
47 def __new__(cls, name):
48 try:
49 return cls.symbols[name]
50 except KeyError:
51 return cls.symbols.setdefault(name, _symbol(name))
54def hashable_identity(obj: object) -> IdentityType:
55 if hasattr(obj, "__func__"):
56 return (id(obj.__func__), id(obj.__self__)) # type: ignore[attr-defined]
57 elif hasattr(obj, "im_func"):
58 return (id(obj.im_func), id(obj.im_self)) # type: ignore[attr-defined]
59 elif isinstance(obj, (int, str)):
60 return obj
61 else:
62 return id(obj)
65WeakTypes = (ref, BoundMethodWeakref)
68class annotatable_weakref(ref):
69 """A weakref.ref that supports custom instance attributes."""
71 receiver_id: t.Optional[IdentityType]
72 sender_id: t.Optional[IdentityType]
75def reference( # type: ignore[no-untyped-def]
76 object, callback=None, **annotations
77) -> annotatable_weakref:
78 """Return an annotated weak ref."""
79 if callable(object):
80 weak = callable_reference(object, callback)
81 else:
82 weak = annotatable_weakref(object, callback)
83 for key, value in annotations.items():
84 setattr(weak, key, value)
85 return weak # type: ignore[no-any-return]
88def callable_reference(object, callback=None):
89 """Return an annotated weak ref, supporting bound instance methods."""
90 if hasattr(object, "im_self") and object.im_self is not None:
91 return BoundMethodWeakref(target=object, on_delete=callback)
92 elif hasattr(object, "__self__") and object.__self__ is not None:
93 return BoundMethodWeakref(target=object, on_delete=callback)
94 return annotatable_weakref(object, callback)
97class lazy_property:
98 """A @property that is only evaluated once."""
100 def __init__(self, deferred):
101 self._deferred = deferred
102 self.__doc__ = deferred.__doc__
104 def __get__(self, obj, cls):
105 if obj is None:
106 return self
107 value = self._deferred(obj)
108 setattr(obj, self._deferred.__name__, value)
109 return value
112def is_coroutine_function(func: t.Any) -> bool:
113 # Python < 3.8 does not correctly determine partially wrapped
114 # coroutine functions are coroutine functions, hence the need for
115 # this to exist. Code taken from CPython.
116 if sys.version_info >= (3, 8):
117 return asyncio.iscoroutinefunction(func)
118 else:
119 # Note that there is something special about the AsyncMock
120 # such that it isn't determined as a coroutine function
121 # without an explicit check.
122 try:
123 from unittest.mock import AsyncMock # type: ignore[attr-defined]
125 if isinstance(func, AsyncMock):
126 return True
127 except ImportError:
128 # Not testing, no asynctest to import
129 pass
131 while inspect.ismethod(func):
132 func = func.__func__
133 while isinstance(func, partial):
134 func = func.func
135 if not inspect.isfunction(func):
136 return False
138 if func.__code__.co_flags & inspect.CO_COROUTINE:
139 return True
141 acic = asyncio.coroutines._is_coroutine # type: ignore[attr-defined]
142 return getattr(func, "_is_coroutine", None) is acic