1
Fork 0
mirror of https://github.com/Steffo99/async-chain.git synced 2024-11-23 13:34:22 +00:00
async-chain/async_chain/chain.py

131 lines
3.5 KiB
Python
Raw Normal View History

2021-06-14 02:32:00 +00:00
from __future__ import annotations
2021-06-13 18:42:02 +00:00
import inspect
import typing as t
import abc
class Chain(metaclass=abc.ABCMeta):
2021-06-14 02:32:00 +00:00
__slots__ = []
2021-06-13 18:42:02 +00:00
2021-06-14 02:32:00 +00:00
def __getattr__(self, item) -> ChainGetAttr:
2021-06-13 18:42:02 +00:00
return ChainGetAttr(previous=self, item=item)
2021-06-14 02:32:00 +00:00
def __getitem__(self, item) -> ChainGetItem:
2021-06-13 18:42:02 +00:00
return ChainGetItem(previous=self, item=item)
2021-06-14 02:32:00 +00:00
def __call__(self, *args, **kwargs) -> ChainCall:
2021-06-13 18:42:02 +00:00
return ChainCall(previous=self, args=args, kwargs=kwargs)
def __await__(self):
return self.__evaluate__().__await__()
@abc.abstractmethod
2021-06-14 02:32:00 +00:00
def __repr__(self) -> str:
2021-06-13 18:42:02 +00:00
raise NotImplementedError()
@abc.abstractmethod
2021-06-14 02:32:00 +00:00
def __display__(self) -> str:
2021-06-13 18:42:02 +00:00
raise NotImplementedError()
@abc.abstractmethod
2021-06-14 02:32:00 +00:00
async def __evaluate__(self) -> t.Any:
2021-06-13 18:42:02 +00:00
raise NotImplementedError()
2021-06-14 02:39:43 +00:00
StartingType = t.TypeVar("StartingType")
2021-06-13 18:42:02 +00:00
class ChainStart(Chain):
2021-06-14 02:32:00 +00:00
__slots__ = ("__start__",)
2021-06-14 02:39:43 +00:00
def __init__(self, start: StartingType):
2021-06-13 18:42:02 +00:00
super().__init__()
2021-06-14 02:39:43 +00:00
self.__start__: StartingType = start
2021-06-13 18:42:02 +00:00
2021-06-14 02:39:43 +00:00
def __repr__(self) -> str:
2021-06-13 18:42:02 +00:00
return f"<Chain {self.__display__()}>"
2021-06-14 02:39:43 +00:00
def __display__(self) -> str:
2021-06-13 18:42:02 +00:00
return f"{self.__start__!r}"
2021-06-14 02:39:43 +00:00
async def __evaluate__(self) -> StartingType:
2021-06-13 18:42:02 +00:00
return self.__start__
class ChainNode(Chain, metaclass=abc.ABCMeta):
2021-06-14 02:32:00 +00:00
__slots__ = ("__previous__",)
2021-06-13 18:42:02 +00:00
def __init__(self, previous: Chain):
super().__init__()
self.__previous__: Chain = previous
2021-06-14 02:39:43 +00:00
def __repr__(self) -> str:
2021-06-13 18:42:02 +00:00
return f"<Chain {self.__display__()}>"
class ChainGetAttr(ChainNode):
2021-06-14 02:32:00 +00:00
__slots__ = ("__item__",)
2021-06-13 18:42:02 +00:00
def __init__(self, previous: Chain, item: str):
super().__init__(previous=previous)
2021-06-14 02:32:00 +00:00
self.__item__: str = item
2021-06-13 18:42:02 +00:00
2021-06-14 02:39:43 +00:00
def __display__(self) -> str:
2021-06-14 02:32:00 +00:00
return f"{self.__previous__.__display__()}.{self.__item__!s}"
2021-06-13 18:42:02 +00:00
2021-06-14 02:39:43 +00:00
async def __evaluate__(self) -> t.Any:
2021-06-13 18:42:02 +00:00
previous = await self.__previous__.__evaluate__()
2021-06-14 02:32:00 +00:00
current = getattr(previous, self.__item__)
2021-06-13 18:42:02 +00:00
if inspect.isawaitable(current):
return await current
else:
return current
class ChainGetItem(ChainNode):
2021-06-14 02:32:00 +00:00
__slots__ = ("__item__",)
2021-06-13 18:42:02 +00:00
def __init__(self, previous: Chain, item: t.Any):
super().__init__(previous=previous)
2021-06-14 02:32:00 +00:00
self.__item__: t.Any = item
2021-06-13 18:42:02 +00:00
2021-06-14 02:39:43 +00:00
def __display__(self) -> str:
2021-06-14 02:32:00 +00:00
return f"{self.__previous__.__display__()}[{self.__item__!r}]"
2021-06-13 18:42:02 +00:00
2021-06-14 02:39:43 +00:00
async def __evaluate__(self) -> t.Any:
2021-06-13 18:42:02 +00:00
previous = await self.__previous__.__evaluate__()
2021-06-14 02:32:00 +00:00
current = previous[self.__item__]
2021-06-13 18:42:02 +00:00
if inspect.isawaitable(current):
return await current
else:
return current
class ChainCall(ChainNode):
2021-06-14 02:32:00 +00:00
__slots__ = ("__args__", "__kwargs__",)
2021-06-14 02:39:43 +00:00
def __init__(self, previous: Chain, args: t.Collection[t.Any], kwargs: t.Mapping[str, t.Any]):
2021-06-13 18:42:02 +00:00
super().__init__(previous=previous)
2021-06-14 02:39:43 +00:00
self.__args__: t.Collection[t.Any] = args
self.__kwargs__: t.Mapping[str, t.Any] = kwargs
2021-06-13 18:42:02 +00:00
2021-06-14 02:39:43 +00:00
def __display__(self) -> str:
2021-06-14 02:32:00 +00:00
args = map(lambda a: f"{a!r}", self.__args__)
kwargs = map(lambda k, v: f"{k!s}={v!r}", self.__kwargs__)
2021-06-14 02:39:43 +00:00
allargs: str = ", ".join([*args, *kwargs])
2021-06-13 18:42:02 +00:00
return f"{self.__previous__.__display__()}({allargs})"
2021-06-14 02:39:43 +00:00
async def __evaluate__(self) -> t.Any:
2021-06-13 18:42:02 +00:00
previous = await self.__previous__.__evaluate__()
2021-06-14 02:32:00 +00:00
current = previous(*self.__args__, **self.__kwargs__)
2021-06-13 18:42:02 +00:00
if inspect.isawaitable(current):
return await current
else:
return current