nonebot2/nonebot/handler.py

126 lines
4.0 KiB
Python
Raw Normal View History

2021-11-12 20:55:59 +08:00
"""
事件处理函数
============
该模块实现事件处理函数的封装以实现动态参数等功能
"""
from contextlib import AsyncExitStack
2021-11-19 18:18:53 +08:00
from typing import Any, Dict, List, Type, Callable, Optional
2021-11-13 19:38:01 +08:00
2021-12-06 20:34:14 +08:00
from nonebot.utils import get_name, run_sync, is_coroutine_callable
from nonebot.dependencies import (
Param,
Dependent,
DependsWrapper,
get_dependent,
solve_dependencies,
get_parameterless_sub_dependant,
)
2021-11-12 20:55:59 +08:00
class Handler:
"""事件处理器类。支持依赖注入。"""
2021-11-12 20:55:59 +08:00
def __init__(
self,
call: Callable[..., Any],
*,
name: Optional[str] = None,
dependencies: Optional[List[DependsWrapper]] = None,
allow_types: Optional[List[Type[Param]]] = None,
):
"""
:说明:
装饰一个函数为事件处理器
:参数:
* ``call: Callable[..., Any]``: 事件处理函数
* ``name: Optional[str]``: 事件处理器名称默认为函数名
* ``dependencies: Optional[List[DependsWrapper]]``: 额外的非参数依赖注入
* ``allow_types: Optional[List[Type[Param]]]``: 允许的参数类型
"""
self.call = call
2021-11-12 20:55:59 +08:00
"""
2021-11-19 18:18:53 +08:00
:类型: ``Callable[..., Any]``
2021-11-12 20:55:59 +08:00
:说明: 事件处理函数
"""
self.name = get_name(call) if name is None else name
"""
:类型: ``str``
:说明: 事件处理函数名
"""
self.allow_types = allow_types or []
"""
:类型: ``List[Type[Param]]``
:说明: 事件处理器允许的参数类型
"""
2021-11-12 20:55:59 +08:00
self.dependencies = dependencies or []
"""
:类型: ``List[DependsWrapper]``
:说明: 事件处理器的额外依赖
"""
self.sub_dependents: Dict[Callable[..., Any], Dependent] = {}
2021-11-13 19:38:01 +08:00
if dependencies:
for depends in dependencies:
self.cache_dependent(depends)
self.dependent = get_dependent(call=call, allow_types=self.allow_types)
2021-11-12 20:55:59 +08:00
2021-11-14 18:51:23 +08:00
def __repr__(self) -> str:
return f"<Handler {self.name}({', '.join(map(str, self.dependent.params))})>"
2021-11-14 18:51:23 +08:00
def __str__(self) -> str:
return repr(self)
async def __call__(
self,
*,
_stack: Optional[AsyncExitStack] = None,
_dependency_cache: Optional[Dict[Callable[..., Any], Any]] = None,
**params,
) -> Any:
2021-11-21 15:46:48 +08:00
values, _ = await solve_dependencies(
2021-11-19 18:18:53 +08:00
_dependent=self.dependent,
_stack=_stack,
_sub_dependents=[
self.sub_dependents[dependency.dependency] # type: ignore
2021-11-13 19:38:01 +08:00
for dependency in self.dependencies
],
2021-11-19 18:18:53 +08:00
_dependency_cache=_dependency_cache,
**params,
)
2021-11-13 19:38:01 +08:00
2021-12-06 20:34:14 +08:00
if is_coroutine_callable(self.call):
return await self.call(**values)
2021-11-13 19:38:01 +08:00
else:
return await run_sync(self.call)(**values)
2021-11-13 19:38:01 +08:00
def cache_dependent(self, dependency: DependsWrapper):
2021-11-13 19:38:01 +08:00
if not dependency.dependency:
raise ValueError(f"{dependency} has no dependency")
if dependency.dependency in self.sub_dependents:
2021-11-13 19:38:01 +08:00
raise ValueError(f"{dependency} is already in dependencies")
2021-11-15 21:44:24 +08:00
sub_dependant = get_parameterless_sub_dependant(
depends=dependency, allow_types=self.allow_types
)
self.sub_dependents[dependency.dependency] = sub_dependant
2021-11-13 19:38:01 +08:00
def prepend_dependency(self, dependency: DependsWrapper):
2021-11-13 19:38:01 +08:00
self.cache_dependent(dependency)
self.dependencies.insert(0, dependency)
def append_dependency(self, dependency: DependsWrapper):
2021-11-13 19:38:01 +08:00
self.cache_dependent(dependency)
self.dependencies.append(dependency)
def remove_dependency(self, dependency: DependsWrapper):
2021-11-13 19:38:01 +08:00
if not dependency.dependency:
raise ValueError(f"{dependency} has no dependency")
if dependency.dependency in self.sub_dependents:
del self.sub_dependents[dependency.dependency]
2021-11-13 19:38:01 +08:00
if dependency in self.dependencies:
self.dependencies.remove(dependency)