Source code for asyncutils.properties

 1from asyncutils._internal.compat import Placeholder, partial
 2from asyncutils._internal.helpers import LoopMixinBase, subscriptable
 3from asyncutils._internal.submodules import properties_all as __all__
 4from _collections import deque
 5from weakref import WeakKeyDictionary as W
 6import asyncutils as A, abc
 7n = 'None'
 8class D(W):
 9    def __init__(self, d, /): super().__init__(); self.c, self.v = bool, d
10    def __set_name__(self, o, n, /, _=frozenset(('__doc__', '__module__', '__name__'))):
11        if n not in _: raise TypeError
12        self.c = o
13    def __get__(self, o, t=None, /):
14        if not (t is None or issubclass(t, self.c)): raise TypeError
15        return self.v if o is None else self.get(o)
16    def __str__(self, _=n, /): return _ if (v := self.v) is None else v
17    def __repr__(self, _=n, /): return _ if (v := self.v) is None else repr(v)
18    __set__, __delete__ = W.__setitem__, W.__delitem__
[docs] 19@subscriptable 20class AsyncPropertyBase(LoopMixinBase, metaclass=type('AsyncPropertyMeta', (abc.ABCMeta,), {'__prepare__': classmethod(lambda c, n, b, _=D, /, **k: (p := c.__base__.__prepare__(n, b, **k)).update(__doc__=_(None), __name__=_(n)) or p), '__new__': lambda m, n, b, d, _=D, /, **k: d.__setitem__('__module__', _('asyncutils.properties')) or m.__base__.__new__(m, n, b, d, **k)})): 21 __slots__ = '__cls', '__deleted', '__hide', '__lock', '__queue', '__strict', '__weakref__', 'fdel', 'fget', 'fset' 22 def __new__(cls, fget=None, *a, **k): # ty: ignore[invalid-assignment] 23 if fget is None: return partial(cls, Placeholder, *a, **k) if a else partial(cls, **k) 24 (_ := object.__new__(cls))._setup(fget, *a, **k); return _ 25 _repr_helper = staticmethod(repr)
[docs] 26 def _setup(self, f, /, fset=None, fdel=None, *, _='<unknown>', doc=None, strict=True, hide=False): self.fget, self.fset, self.fdel, self.__doc__, self.__module__, self.__deleted, self.__strict, self.__hide, self.__queue, self.__lock = f, fset, fdel, getattr(f, '__doc__', None) if doc is None else doc, getattr(f, '__module__', _), set(), strict, hide, deque(), self._lock_factory()
[docs] 27 def __get__(self, o, _=None, /): 28 if o is None: self.__check_hidden(); return self 29 self.__check_unbound() 30 if self.fget is None: return self.__get_helper('asyncutils.properties.AsyncPropertyBase: unreadable attribute') 31 if o in self.__deleted: return self.__get_helper('asyncutils.properties.AsyncPropertyBase: cannot get deleted attribute') 32 return self.__get(o)
[docs] 33 def __set__(self, o, v, /): 34 if o is None: return self.__check_hidden() 35 self.__check_unbound() 36 if (f := self.fset) is None: return self.__set_helper('asyncutils.properties.AsyncPropertyBase: immutable attribute', v) 37 if o in self.__deleted: return self.__set_helper('asyncutils.properties.AsyncPropertyBase: cannot set deleted attribute', v) 38 self.__queue.append(self.__helper(f, 'set', o, v))
[docs] 39 def __delete__(self, o, /): 40 if o is None: return self.__check_hidden() 41 self.__check_unbound() 42 if (f := self.fdel) is None: 43 if self.__strict: raise AttributeError('asyncutils.properties.AsyncPropertyBase: undeletable attribute', name=self.__name__) 44 return self.__deleted.add(o) 45 self.__queue.append(self.__helper(f, 'delete', o))
[docs] 46 def __set_name__(self, /, *_): self.__cls, self.__name__ = _
47 def __repr__(self): return f'asyncutils.properties.{type(self).__name__}({", ".join(map(self._repr_helper, (self.fget, self.fset, self.fdel)))}, doc={self.__doc__!r}, strict={self.__strict}, hide={self.__hide})'
[docs] 48 def __reduce__(self): 49 if self.__hide: raise TypeError('asyncutils.properties.AsyncPropertyBase: cannot pickle hidden property') 50 return f'{self.__cls.__name__}.{self.__name__}'
51 def __check_hidden(self): 52 if self.__hide: raise AttributeError(name=self.__name__, obj=self.__cls) 53 def __check_unbound(self): 54 if not hasattr(self, '_AsyncPropertyBase__cls'): raise TypeError(f'{self!r} is not bound to a class') 55 def __get_helper(self, m, /): 56 if self.__strict or self.__hide: raise AttributeError(m, name=self.__name__) 57 return self
[docs] 58 @abc.abstractmethod 59 def _wrap_aw(self, _, /): raise NotImplementedError
60 async def __get(self, o, /): 61 p = (q := self.__queue).popleft 62 async with self.__lock: 63 while q: 64 if await p() is not None and self.__strict: raise TypeError('setter or deleter returned non-None value') 65 return await self.fget(o) 66 def __helper(self, f, c, /, *a): 67 try: return self._wrap_aw(f(*a)) 68 except A.CRITICAL: raise A.Critical 69 except BaseException as e: raise AttributeError(f'failed to {c} attribute {self.__name__}') from e 70 def __set_helper(self, m, v, /): 71 if self.__strict: raise AttributeError(m, name=self.__name__) 72 setattr(self.__cls, self.__name__, v)
[docs] 73 def getter(self, f, /): return type(self)(f, self.fset, self.fdel, doc=self.__doc__, strict=self.__strict, hide=self.__hide)
[docs] 74 def setter(self, f, /): return type(self)(self.fget, f, self.fdel, doc=self.__doc__, strict=self.__strict, hide=self.__hide)
[docs] 75 def deleter(self, f, /): return type(self)(self.fget, self.fset, f, doc=self.__doc__, strict=self.__strict, hide=self.__hide)
[docs] 76 def __getattr__(self, n, /): 77 if (f := self.fget) is None: raise AttributeError(name=n, obj=self) 78 return getattr(f, n)
[docs] 79 def __init_subclass__(cls, /, *, lock_factory=None, **_): 80 if not isinstance(cls.__dict__.get('__slots__'), tuple): raise TypeError('subclass of asyncutils.properties.AsyncPropertyBase must define tuple __slots__') 81 if lock_factory is not None: cls._lock_factory = lock_factory 82 elif getattr(cls, '_lock_factory', None) is None: raise TypeError('asyncutils.properties.AsyncPropertyBase subclasses must specify lock_factory') 83 super().__init_subclass__(**_)
[docs] 84class LazyAsyncProperty(AsyncPropertyBase, lock_factory=__import__('asyncio').Lock): __slots__, _wrap_aw = (), staticmethod(A.wrap_in_coro)
[docs] 85class ConcurrentAsyncProperty(AsyncPropertyBase, lock_factory=staticmethod(lambda _=A.anullcontext, /: _)): __slots__, _wrap_aw = (), LoopMixinBase.make
[docs] 86class RWLockedAsyncProperty(ConcurrentAsyncProperty): 87 __slots__, _repr_helper = (), staticmethod(lambda v, _=n, /: _ if v is None else repr(v.__wrapped__))
[docs] 88 def _setup(self, f, /, fset=None, fdel=None, *, policy=A.RWLock, **k): w = (f := policy.lock(f)).writer; super()._setup(f, None if fset is None else w(fset), None if fdel is None else w(fdel), **k)
89del abc, n, W, D