diff options
Diffstat (limited to 'hrc')
| -rw-r--r-- | hrc/__init__.py | 2 | ||||
| -rw-r--r-- | hrc/dependencies.py | 118 | ||||
| -rw-r--r-- | hrc/exceptions.py | 22 | ||||
| -rw-r--r-- | hrc/rule/__init__.py | 16 | ||||
| -rw-r--r-- | hrc/utils.py | 8 |
5 files changed, 149 insertions, 17 deletions
diff --git a/hrc/__init__.py b/hrc/__init__.py index ba4efed..29021d3 100644 --- a/hrc/__init__.py +++ b/hrc/__init__.py @@ -1,7 +1,7 @@ from .LibCore import * # noqa: F403 from . import rule # noqa: F401 -from . import core # noqa: F401 +from .core import Core # noqa: F401 from . import log # noqa: F401 from . import exceptions # noqa: F401 from . import config # noqa: F401 diff --git a/hrc/dependencies.py b/hrc/dependencies.py index e69de29..3a662fd 100644 --- a/hrc/dependencies.py +++ b/hrc/dependencies.py @@ -0,0 +1,118 @@ +import inspect +from contextlib import AsyncExitStack, asynccontextmanager, contextmanager +from typing import ( + Any, + AsyncContextManager, + AsyncGenerator, + Callable, + ContextManager, + Dict, + Generator, + Optional, + Type, + TypeVar, + Union, + cast, +) + +from .utils import get_annotations, sync_ctx_manager_wrapper + +_T = TypeVar("_T") +Dependency = Union[ + # Class + Type[Union[_T, AsyncContextManager[_T], ContextManager[_T]]], + # GeneratorContextManager + Callable[[], AsyncGenerator[_T, None]], + Callable[[], Generator[_T, None, None]], +] + + +__all__ = ["Depends"] + + +class InnerDepends: + + dependency: Optional[Dependency[Any]] + use_cache: bool + + def __init__( + self, dependency: Optional[Dependency[Any]] = None, *, use_cache: bool = True + ) -> None: + self.dependency = dependency + self.use_cache = use_cache + + def __repr__(self) -> str: + attr = getattr(self.dependency, "__name__", type(self.dependency).__name__) + cache = "" if self.use_cache else ", use_cache=False" + return f"InnerDepends({attr}{cache})" + + +def Depends( # noqa: N802 # pylint: disable=invalid-name + dependency: Optional[Dependency[_T]] = None, *, use_cache: bool = True +) -> _T: + + return InnerDepends(dependency=dependency, use_cache=use_cache) # type: ignore + + +async def solve_dependencies( + dependent: Dependency[_T], + *, + use_cache: bool, + stack: AsyncExitStack, + dependency_cache: Dict[Dependency[Any], Any], +) -> _T: + if use_cache and dependent in dependency_cache: + return dependency_cache[dependent] + + if isinstance(dependent, type): + # type of dependent is Type[T] + values: Dict[str, Any] = {} + ann = get_annotations(dependent) + for name, sub_dependent in inspect.getmembers( + dependent, lambda x: isinstance(x, InnerDepends) + ): + assert isinstance(sub_dependent, InnerDepends) + if sub_dependent.dependency is None: + dependent_ann = ann.get(name, None) + if dependent_ann is None: + raise TypeError("can not solve dependent") + sub_dependent.dependency = dependent_ann + values[name] = await solve_dependencies( + sub_dependent.dependency, + use_cache=sub_dependent.use_cache, + stack=stack, + dependency_cache=dependency_cache, + ) + depend_obj = cast( + Union[_T, AsyncContextManager[_T], ContextManager[_T]], + dependent.__new__(dependent), # pyright: ignore[reportGeneralTypeIssues] + ) + for key, value in values.items(): + setattr(depend_obj, key, value) + depend_obj.__init__() # type: ignore[misc] # pylint: disable=unnecessary-dunder-call + + if isinstance(depend_obj, AsyncContextManager): + depend = await stack.enter_async_context( + depend_obj # pyright: ignore[reportUnknownArgumentType] + ) + elif isinstance(depend_obj, ContextManager): + depend = await stack.enter_async_context( + sync_ctx_manager_wrapper( + depend_obj # pyright: ignore[reportUnknownArgumentType] + ) + ) + else: + depend = depend_obj + elif inspect.isasyncgenfunction(dependent): + # type of dependent is Callable[[], AsyncGenerator[T, None]] + cm = asynccontextmanager(dependent)() + depend = cast(_T, await stack.enter_async_context(cm)) + elif inspect.isgeneratorfunction(dependent): + # type of dependent is Callable[[], Generator[T, None, None]] + cm = sync_ctx_manager_wrapper(contextmanager(dependent)()) + depend = cast(_T, await stack.enter_async_context(cm)) + else: + raise TypeError("dependent is not a class or generator function") + + dependency_cache[dependent] = depend + return depend
\ No newline at end of file diff --git a/hrc/exceptions.py b/hrc/exceptions.py index e69de29..c71118f 100644 --- a/hrc/exceptions.py +++ b/hrc/exceptions.py @@ -0,0 +1,22 @@ +class EventException(BaseException): + ... + + +class SkipException(EventException): + ... + + +class StopException(EventException): + ... + + +class CoreException(Exception): + ... # noqa: N818 + + +class GetEventTimeout(CoreException): + ... + + +class LoadModuleError(CoreException): + ... diff --git a/hrc/rule/__init__.py b/hrc/rule/__init__.py index a41c81d..bbd2cfe 100644 --- a/hrc/rule/__init__.py +++ b/hrc/rule/__init__.py @@ -155,11 +155,11 @@ class Rule(ABC, Generic[EventT, StateT, ConfigT]): """ raise NotImplementedError - -def aliases(names, ignore_case=False): - def decorator(func): - func._aliases = names - func._ignore_case = ignore_case - return func - - return decorator + @staticmethod + def aliases(names, ignore_case=False): + def decorator(func): + func._aliases = names + func._ignore_case = ignore_case + return func + + return decorator diff --git a/hrc/utils.py b/hrc/utils.py index 480b105..e85cea4 100644 --- a/hrc/utils.py +++ b/hrc/utils.py @@ -82,14 +82,6 @@ class ModulePathFinder(MetaPathFinder): def is_config_class(config_class: Any) -> TypeGuard[Type[ConfigModel]]: - """Determine whether an object is a configuration class. - - Args: - config_class: The object to be judged. - - Returns: - Returns whether it is a configuration class. - """ return ( inspect.isclass(config_class) and issubclass(config_class, ConfigModel) |
