179 lines
7.4 KiB
Python
179 lines
7.4 KiB
Python
import asyncio
|
|
import copy
|
|
from contextvars import ContextVar # noqa # contextvars not understood as stdlib
|
|
from typing import Any, Callable, Dict, Optional # noqa # contextvars not understood as stdlib
|
|
|
|
|
|
class TaskLocal:
|
|
"""An object local to the current task."""
|
|
|
|
__slots__ = ('_storage',)
|
|
|
|
def __init__(self) -> None:
|
|
# Note as __setattr__ is overidden below, use the object __setattr__
|
|
object.__setattr__(self, '_storage', ContextVar('storage'))
|
|
|
|
def __getattr__(self, name: str) -> Any:
|
|
values = self._storage.get({})
|
|
try:
|
|
return values[name]
|
|
except KeyError:
|
|
raise AttributeError(name)
|
|
|
|
def __setattr__(self, name: str, value: Any) -> None:
|
|
values = self._storage.get({})
|
|
values[name] = value
|
|
self._storage.set(values)
|
|
|
|
def __delattr__(self, name: str) -> None:
|
|
values = self._storage.get({})
|
|
try:
|
|
del values[name]
|
|
self._storage.set(values)
|
|
except KeyError:
|
|
raise AttributeError(name)
|
|
|
|
@staticmethod
|
|
def _task_identity() -> int:
|
|
loop = asyncio.get_event_loop()
|
|
if loop.is_running():
|
|
task = asyncio.current_task()
|
|
task_id = id(task)
|
|
return task_id
|
|
else:
|
|
return 0
|
|
|
|
|
|
class LocalStack:
|
|
|
|
def __init__(self) -> None:
|
|
self._task_local = TaskLocal()
|
|
|
|
def push(self, value: Any) -> None:
|
|
stack = getattr(self._task_local, 'stack', None)
|
|
if stack is None:
|
|
self._task_local.stack = stack = []
|
|
stack.append(value)
|
|
|
|
def pop(self) -> Any:
|
|
stack = getattr(self._task_local, 'stack', None)
|
|
if stack is None or stack == []:
|
|
return None
|
|
else:
|
|
return stack.pop()
|
|
|
|
@property
|
|
def top(self) -> Any:
|
|
try:
|
|
return self._task_local.stack[-1]
|
|
except (AttributeError, IndexError):
|
|
return None
|
|
|
|
|
|
class LocalProxy:
|
|
"""Proxy to a task local object."""
|
|
__slots__ = ('__dict__', '__local', '__wrapped__')
|
|
|
|
def __init__(self, local: Callable, name: Optional[str]=None) -> None:
|
|
# Note as __setattr__ is overidden below, use the object __setattr__
|
|
object.__setattr__(self, '__LocalProxy_local', local)
|
|
object.__setattr__(self, '__wrapped__', local)
|
|
object.__setattr__(self, "__name__", name)
|
|
|
|
def _get_current_object(self) -> Any:
|
|
return object.__getattribute__(self, '__LocalProxy_local')()
|
|
|
|
@property
|
|
def __dict__(self) -> Dict[str, Any]: # type: ignore
|
|
try:
|
|
return self._get_current_object().__dict__
|
|
except RuntimeError:
|
|
raise AttributeError('__dict__')
|
|
|
|
def __repr__(self) -> str:
|
|
try:
|
|
obj = self._get_current_object()
|
|
except RuntimeError:
|
|
return '<%s unbound>' % self.__class__.__name__
|
|
return repr(obj)
|
|
|
|
def __bool__(self) -> bool:
|
|
try:
|
|
return bool(self._get_current_object())
|
|
except RuntimeError:
|
|
return False
|
|
|
|
def __dir__(self) -> Any:
|
|
try:
|
|
return dir(self._get_current_object())
|
|
except RuntimeError:
|
|
return []
|
|
|
|
def __getattr__(self, name: Any) -> Any:
|
|
if name == '__members__':
|
|
return dir(self._get_current_object())
|
|
return getattr(self._get_current_object(), name)
|
|
|
|
def __setitem__(self, key: Any, value: Any) -> Any:
|
|
self._get_current_object()[key] = value
|
|
|
|
def __delitem__(self, key: Any) -> Any:
|
|
del self._get_current_object()[key]
|
|
|
|
async def __aiter__(self) -> Any:
|
|
async for x in self._get_current_object():
|
|
yield x
|
|
|
|
__setattr__ = lambda x, n, v: setattr(x._get_current_object(), n, v) # type: ignore # noqa: E731, E501
|
|
__delattr__ = lambda x, n: delattr(x._get_current_object(), n) # type: ignore # noqa: E731
|
|
__str__ = lambda x: str(x._get_current_object()) # type: ignore # noqa: E731
|
|
__lt__ = lambda x, o: x._get_current_object() < o # noqa: E731
|
|
__le__ = lambda x, o: x._get_current_object() <= o # noqa: E731
|
|
__eq__ = lambda x, o: x._get_current_object() == o # type: ignore # noqa: E731
|
|
__ne__ = lambda x, o: x._get_current_object() != o # type: ignore # noqa: E731
|
|
__gt__ = lambda x, o: x._get_current_object() > o # noqa: E731
|
|
__ge__ = lambda x, o: x._get_current_object() >= o # noqa: E731
|
|
__hash__ = lambda x: hash(x._get_current_object()) # type: ignore # noqa: E731
|
|
__call__ = lambda x, *a, **kw: x._get_current_object()(*a, **kw) # noqa: E731
|
|
__len__ = lambda x: len(x._get_current_object()) # noqa: E731
|
|
__getitem__ = lambda x, i: x._get_current_object()[i] # noqa: E731
|
|
__iter__ = lambda x: iter(x._get_current_object()) # noqa: E731
|
|
__contains__ = lambda x, i: i in x._get_current_object() # noqa: E731
|
|
__add__ = lambda x, o: x._get_current_object() + o # noqa: E731
|
|
__sub__ = lambda x, o: x._get_current_object() - o # noqa: E731
|
|
__mul__ = lambda x, o: x._get_current_object() * o # noqa: E731
|
|
__floordiv__ = lambda x, o: x._get_current_object() // o # noqa: E731
|
|
__mod__ = lambda x, o: x._get_current_object() % o # noqa: E731
|
|
__divmod__ = lambda x, o: x._get_current_object().__divmod__(o) # noqa: E731
|
|
__pow__ = lambda x, o: x._get_current_object() ** o # noqa: E731
|
|
__lshift__ = lambda x, o: x._get_current_object() << o # noqa: E731
|
|
__rshift__ = lambda x, o: x._get_current_object() >> o # noqa: E731
|
|
__and__ = lambda x, o: x._get_current_object() & o # noqa: E731
|
|
__xor__ = lambda x, o: x._get_current_object() ^ o # noqa: E731
|
|
__or__ = lambda x, o: x._get_current_object() | o # noqa: E731
|
|
__div__ = lambda x, o: x._get_current_object().__div__(o) # noqa: E731
|
|
__truediv__ = lambda x, o: x._get_current_object().__truediv__(o) # noqa: E731
|
|
__neg__ = lambda x: -(x._get_current_object()) # noqa: E731
|
|
__pos__ = lambda x: +(x._get_current_object()) # noqa: E731
|
|
__abs__ = lambda x: abs(x._get_current_object()) # noqa: E731
|
|
__invert__ = lambda x: ~(x._get_current_object()) # noqa: E731
|
|
__complex__ = lambda x: complex(x._get_current_object()) # noqa: E731
|
|
__int__ = lambda x: int(x._get_current_object()) # noqa: E731
|
|
__float__ = lambda x: float(x._get_current_object()) # noqa: E731
|
|
__oct__ = lambda x: oct(x._get_current_object()) # noqa: E731
|
|
__hex__ = lambda x: hex(x._get_current_object()) # noqa: E731
|
|
__index__ = lambda x: x._get_current_object().__index__() # noqa: E731
|
|
__coerce__ = lambda x, o: x._get_current_object().__coerce__(x, o) # noqa: E731
|
|
__enter__ = lambda x: x._get_current_object().__enter__() # noqa: E731
|
|
__exit__ = lambda x, *a, **kw: x._get_current_object().__exit__(*a, **kw) # noqa: E731
|
|
__radd__ = lambda x, o: o + x._get_current_object() # noqa: E731
|
|
__rsub__ = lambda x, o: o - x._get_current_object() # noqa: E731
|
|
__rmul__ = lambda x, o: o * x._get_current_object() # noqa: E731
|
|
__rdiv__ = lambda x, o: o / x._get_current_object() # noqa: E731
|
|
__rtruediv__ = __rdiv__
|
|
__rfloordiv__ = lambda x, o: o // x._get_current_object() # noqa: E731
|
|
__rmod__ = lambda x, o: o % x._get_current_object() # noqa: E731
|
|
__rdivmod__ = lambda x, o: x._get_current_object().__rdivmod__(o) # noqa: E731
|
|
__copy__ = lambda x: copy.copy(x._get_current_object()) # noqa: E731
|
|
__deepcopy__ = lambda x, memo: copy.deepcopy(x._get_current_object(), memo) # noqa: E731
|