aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/hrc
diff options
context:
space:
mode:
Diffstat (limited to 'hrc')
-rw-r--r--hrc/__init__.py2
-rw-r--r--hrc/dependencies.py118
-rw-r--r--hrc/exceptions.py22
-rw-r--r--hrc/rule/__init__.py16
-rw-r--r--hrc/utils.py8
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)