♻️ rewrite dependency injection system

This commit is contained in:
yanyongyu 2021-12-12 18:19:08 +08:00
parent 6b5a5e53eb
commit 66ba25494a
17 changed files with 728 additions and 733 deletions

4
nonebot/consts.py Normal file
View File

@ -0,0 +1,4 @@
RECEIVE_KEY = "_receive_{id}"
ARG_KEY = "_arg_{key}"
ARG_STR_KEY = "{key}"
REJECT_TARGET = "_current_target"

View File

@ -5,227 +5,170 @@
该模块实现了依赖注入的定义与处理 该模块实现了依赖注入的定义与处理
""" """
import abc
import inspect import inspect
from itertools import chain from typing import Any, Dict, List, Type, Generic, TypeVar, Callable, Optional
from typing import Any, Dict, List, Type, Tuple, Callable, Optional, cast
from contextlib import AsyncExitStack, contextmanager, asynccontextmanager
from pydantic import BaseConfig from pydantic import BaseConfig
from pydantic.schema import get_annotation_from_field_info from pydantic.schema import get_annotation_from_field_info
from pydantic.fields import Required, Undefined, ModelField from pydantic.fields import Required, FieldInfo, Undefined, ModelField
from nonebot.log import logger from nonebot.log import logger
from .models import Param as Param
from .utils import get_typed_signature from .utils import get_typed_signature
from .models import Dependent as Dependent
from nonebot.exception import SkippedException from nonebot.exception import SkippedException
from .models import DependsWrapper as DependsWrapper from nonebot.utils import run_sync, is_coroutine_callable
from nonebot.typing import T_Handler, T_DependencyCache
from nonebot.utils import (
CacheLock,
run_sync,
is_gen_callable,
run_sync_ctx_manager,
is_async_gen_callable,
is_coroutine_callable,
)
cache_lock = CacheLock() T = TypeVar("T", bound="Dependent")
R = TypeVar("R")
class Param(abc.ABC, FieldInfo):
@classmethod
def _check_param(
cls, dependent: "Dependent", name: str, param: inspect.Parameter
) -> Optional["Param"]:
return None
@classmethod
def _check_parameterless(
cls, dependent: "Dependent", value: Any
) -> Optional["Param"]:
return None
@abc.abstractmethod
async def _solve(self, **kwargs: Any) -> Any:
raise NotImplementedError
class CustomConfig(BaseConfig): class CustomConfig(BaseConfig):
arbitrary_types_allowed = True arbitrary_types_allowed = True
def get_param_sub_dependent( class Dependent(Generic[R]):
*, param: inspect.Parameter, allow_types: Optional[List[Type[Param]]] = None def __init__(
) -> Dependent: self,
depends: DependsWrapper = param.default *,
if depends.dependency: call: Callable[..., Any],
dependency = depends.dependency params: Optional[List[ModelField]] = None,
else: parameterless: Optional[List[Param]] = None,
dependency = param.annotation allow_types: Optional[List[Type[Param]]] = None,
return get_sub_dependant( ) -> None:
depends=depends, dependency=dependency, name=param.name, allow_types=allow_types self.call = call
) self.params = params or []
self.parameterless = parameterless or []
self.allow_types = allow_types or []
async def __call__(self, **kwargs: Any) -> R:
values = await self.solve(**kwargs)
def get_parameterless_sub_dependant( if is_coroutine_callable(self.call):
*, depends: DependsWrapper, allow_types: Optional[List[Type[Param]]] = None return await self.call(**values)
) -> Dependent:
assert callable(
depends.dependency
), "A parameter-less dependency must have a callable dependency"
return get_sub_dependant(
depends=depends, dependency=depends.dependency, allow_types=allow_types
)
def get_sub_dependant(
*,
depends: DependsWrapper,
dependency: T_Handler,
name: Optional[str] = None,
allow_types: Optional[List[Type[Param]]] = None,
) -> Dependent:
sub_dependant = get_dependent(
call=dependency, name=name, use_cache=depends.use_cache, allow_types=allow_types
)
return sub_dependant
def get_dependent(
*,
call: T_Handler,
name: Optional[str] = None,
use_cache: bool = True,
allow_types: Optional[List[Type[Param]]] = None,
) -> Dependent:
signature = get_typed_signature(call)
params = signature.parameters
dependent = Dependent(
call=call, name=name, allow_types=allow_types, use_cache=use_cache
)
for param_name, param in params.items():
if isinstance(param.default, DependsWrapper):
sub_dependent = get_param_sub_dependent(
param=param, allow_types=allow_types
)
dependent.dependencies.append(sub_dependent)
continue
default_value = Required
if param.default != param.empty:
default_value = param.default
if isinstance(default_value, Param):
field_info = default_value
default_value = field_info.default
else: else:
for allow_type in dependent.allow_types: return await run_sync(self.call)(**values)
if allow_type._check(param_name, param):
field_info = allow_type(default_value) def parse_param(self, name: str, param: inspect.Parameter) -> Param:
break for allow_type in self.allow_types:
field_info = allow_type._check_param(self, name, param)
if field_info:
return field_info
else:
raise ValueError(
f"Unknown parameter {name} for function {self.call} with type {param.annotation}"
)
def parse_parameterless(self, value: Any) -> Param:
for allow_type in self.allow_types:
field_info = allow_type._check_parameterless(self, value)
if field_info:
return field_info
else:
raise ValueError(
f"Unknown parameterless {value} for function {self.call} with type {type(value)}"
)
def prepend_parameterless(self, value: Any) -> None:
self.parameterless.insert(0, self.parse_parameterless(value))
def append_parameterless(self, value: Any) -> None:
self.parameterless.append(self.parse_parameterless(value))
@classmethod
def parse(
cls: Type[T],
*,
call: Callable[..., Any],
parameterless: Optional[List[Any]] = None,
allow_types: Optional[List[Type[Param]]] = None,
) -> T:
signature = get_typed_signature(call)
params = signature.parameters
dependent = cls(
call=call,
allow_types=allow_types,
)
parameterless_params = [
dependent.parse_parameterless(param) for param in (parameterless or [])
]
dependent.parameterless.extend(parameterless_params)
for param_name, param in params.items():
default_value = Required
if param.default != param.empty:
default_value = param.default
if isinstance(default_value, Param):
field_info = default_value
default_value = field_info.default
else: else:
raise ValueError( field_info = dependent.parse_param(param_name, param)
f"Unknown parameter {param_name} for function {call} with type {param.annotation}" default_value = field_info.default
annotation: Any = Any
required = default_value == Required
if param.annotation != param.empty:
annotation = param.annotation
annotation = get_annotation_from_field_info(
annotation, field_info, param_name
)
dependent.params.append(
ModelField(
name=param_name,
type_=annotation,
class_validators=None,
model_config=CustomConfig,
default=None if required else default_value,
required=required,
field_info=field_info,
) )
annotation: Any = Any
required = default_value == Required
if param.annotation != param.empty:
annotation = param.annotation
annotation = get_annotation_from_field_info(annotation, field_info, param_name)
dependent.params.append(
ModelField(
name=param_name,
type_=annotation,
class_validators=None,
model_config=CustomConfig,
default=None if required else default_value,
required=required,
field_info=field_info,
) )
)
return dependent return dependent
async def solve(
self,
**params: Any,
) -> Dict[str, Any]:
values: Dict[str, Any] = {}
async def solve_dependencies( for field in self.params:
*, field_info = field.field_info
_dependent: Dependent, assert isinstance(field_info, Param), "Params must be subclasses of Param"
_stack: Optional[AsyncExitStack] = None, value = await field_info._solve(**params)
_sub_dependents: Optional[List[Dependent]] = None, if value == Undefined:
_dependency_cache: Optional[T_DependencyCache] = None, value = field.get_default()
**params: Any, _, errs_ = field.validate(value, values, loc=(str(field_info), field.alias))
) -> Tuple[Dict[str, Any], T_DependencyCache]: if errs_:
values: Dict[str, Any] = {} logger.debug(
dependency_cache = {} if _dependency_cache is None else _dependency_cache f"{field_info} "
f"type {type(value)} not match depends {self.call} "
# usual dependency f"annotation {field._type_display()}, ignored"
for field in _dependent.params: )
field_info = field.field_info raise SkippedException(field, value)
assert isinstance(field_info, Param), "Params must be subclasses of Param"
value = field_info._solve(**params)
if value == Undefined:
value = field.get_default()
_, errs_ = field.validate(value, values, loc=(str(field_info), field.alias))
if errs_:
logger.debug(
f"{field_info} "
f"type {type(value)} not match depends {_dependent.call} "
f"annotation {field._type_display()}, ignored"
)
raise SkippedException(field, value)
else:
values[field.name] = value
# solve sub dependencies
sub_dependent: Dependent
for sub_dependent in chain(_sub_dependents or tuple(), _dependent.dependencies):
sub_dependent.call = cast(Callable[..., Any], sub_dependent.call)
sub_dependent.cache_key = cast(Callable[..., Any], sub_dependent.cache_key)
call = sub_dependent.call
# solve sub dependency with current cache
solved_result = await solve_dependencies(
_dependent=sub_dependent, _dependency_cache=dependency_cache, **params
)
sub_values, sub_dependency_cache = solved_result
# update cache?
# dependency_cache.update(sub_dependency_cache)
# run dependency function
async with cache_lock:
if sub_dependent.use_cache and sub_dependent.cache_key in dependency_cache:
solved = dependency_cache[sub_dependent.cache_key]
elif is_gen_callable(call) or is_async_gen_callable(call):
assert isinstance(
_stack, AsyncExitStack
), "Generator dependency should be called in context"
if is_gen_callable(call):
cm = run_sync_ctx_manager(contextmanager(call)(**sub_values))
else:
cm = asynccontextmanager(call)(**sub_values)
solved = await _stack.enter_async_context(cm)
elif is_coroutine_callable(call):
solved = await call(**sub_values)
else: else:
solved = await run_sync(call)(**sub_values) values[field.name] = value
# parameter dependency for param in self.parameterless:
if sub_dependent.name is not None: await param._solve(**params)
values[sub_dependent.name] = solved
# save current dependency to cache
if sub_dependent.cache_key not in dependency_cache:
dependency_cache[sub_dependent.cache_key] = solved
return values, dependency_cache return values
def Depends(dependency: Optional[T_Handler] = None, *, use_cache: bool = True) -> Any:
"""
:说明:
参数依赖注入装饰器
:参数:
* ``dependency: Optional[Callable[..., Any]] = None``: 依赖函数默认为参数的类型注释
* ``use_cache: bool = True``: 是否使用缓存默认为 ``True``
.. code-block:: python
def depend_func() -> Any:
return ...
def depend_gen_func():
try:
yield ...
finally:
...
async def handler(param_name: Any = Depends(depend_func), gen: Any = Depends(depend_gen_func)):
...
"""
return DependsWrapper(dependency=dependency, use_cache=use_cache)

View File

@ -1,52 +0,0 @@
import abc
import inspect
from typing import Any, List, Type, Optional
from pydantic.fields import FieldInfo, ModelField
from nonebot.utils import get_name
from nonebot.typing import T_Handler
class Param(abc.ABC, FieldInfo):
@classmethod
@abc.abstractmethod
def _check(cls, name: str, param: inspect.Parameter) -> bool:
raise NotImplementedError
@abc.abstractmethod
def _solve(self, **kwargs: Any) -> Any:
raise NotImplementedError
class DependsWrapper:
def __init__(
self, dependency: Optional[T_Handler] = None, *, use_cache: bool = True
) -> None:
self.dependency = dependency
self.use_cache = use_cache
def __repr__(self) -> str:
dep = get_name(self.dependency)
cache = "" if self.use_cache else ", use_cache=False"
return f"{self.__class__.__name__}({dep}{cache})"
class Dependent:
def __init__(
self,
*,
call: Optional[T_Handler] = None,
name: Optional[str] = None,
params: Optional[List[ModelField]] = None,
allow_types: Optional[List[Type[Param]]] = None,
dependencies: Optional[List["Dependent"]] = None,
use_cache: bool = True,
) -> None:
self.call = call
self.name = name
self.params = params or []
self.allow_types = allow_types or []
self.dependencies = dependencies or []
self.use_cache = use_cache
self.cache_key = self.call

View File

@ -1,13 +1,11 @@
import inspect import inspect
from typing import Any, Dict from typing import Any, Dict, Callable
from loguru import logger from loguru import logger
from pydantic.typing import ForwardRef, evaluate_forwardref from pydantic.typing import ForwardRef, evaluate_forwardref
from nonebot.typing import T_Handler
def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
def get_typed_signature(call: T_Handler) -> inspect.Signature:
signature = inspect.signature(call) signature = inspect.signature(call)
globalns = getattr(call, "__globals__", {}) globalns = getattr(call, "__globals__", {})
typed_params = [ typed_params = [

View File

@ -1,125 +0,0 @@
"""
事件处理函数
============
该模块实现事件处理函数的封装以实现动态参数等功能
"""
from contextlib import AsyncExitStack
from typing import Any, Dict, List, Type, Callable, Optional
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,
)
class Handler:
"""事件处理器类。支持依赖注入。"""
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
"""
:类型: ``Callable[..., Any]``
:说明: 事件处理函数
"""
self.name = get_name(call) if name is None else name
"""
:类型: ``str``
:说明: 事件处理函数名
"""
self.allow_types = allow_types or []
"""
:类型: ``List[Type[Param]]``
:说明: 事件处理器允许的参数类型
"""
self.dependencies = dependencies or []
"""
:类型: ``List[DependsWrapper]``
:说明: 事件处理器的额外依赖
"""
self.sub_dependents: Dict[Callable[..., Any], Dependent] = {}
if dependencies:
for depends in dependencies:
self.cache_dependent(depends)
self.dependent = get_dependent(call=call, allow_types=self.allow_types)
def __repr__(self) -> str:
return f"<Handler {self.name}({', '.join(map(str, self.dependent.params))})>"
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:
values, _ = await solve_dependencies(
_dependent=self.dependent,
_stack=_stack,
_sub_dependents=[
self.sub_dependents[dependency.dependency] # type: ignore
for dependency in self.dependencies
],
_dependency_cache=_dependency_cache,
**params,
)
if is_coroutine_callable(self.call):
return await self.call(**values)
else:
return await run_sync(self.call)(**values)
def cache_dependent(self, dependency: DependsWrapper):
if not dependency.dependency:
raise ValueError(f"{dependency} has no dependency")
if dependency.dependency in self.sub_dependents:
raise ValueError(f"{dependency} is already in dependencies")
sub_dependant = get_parameterless_sub_dependant(
depends=dependency, allow_types=self.allow_types
)
self.sub_dependents[dependency.dependency] = sub_dependant
def prepend_dependency(self, dependency: DependsWrapper):
self.cache_dependent(dependency)
self.dependencies.insert(0, dependency)
def append_dependency(self, dependency: DependsWrapper):
self.cache_dependent(dependency)
self.dependencies.append(dependency)
def remove_dependency(self, dependency: DependsWrapper):
if not dependency.dependency:
raise ValueError(f"{dependency} has no dependency")
if dependency.dependency in self.sub_dependents:
del self.sub_dependents[dependency.dependency]
if dependency in self.dependencies:
self.dependencies.remove(dependency)

View File

@ -17,6 +17,7 @@ from typing import (
List, List,
Type, Type,
Union, Union,
TypeVar,
Callable, Callable,
NoReturn, NoReturn,
Optional, Optional,
@ -25,9 +26,10 @@ from typing import (
from nonebot import params from nonebot import params
from nonebot.rule import Rule from nonebot.rule import Rule
from nonebot.log import logger from nonebot.log import logger
from nonebot.handler import Handler from nonebot.utils import CacheDict
from nonebot.dependencies import DependsWrapper from nonebot.dependencies import Dependent
from nonebot.permission import USER, Permission from nonebot.permission import USER, Permission
from nonebot.consts import ARG_KEY, ARG_STR_KEY, RECEIVE_KEY, REJECT_TARGET
from nonebot.adapters import ( from nonebot.adapters import (
Bot, Bot,
Event, Event,
@ -35,6 +37,14 @@ from nonebot.adapters import (
MessageSegment, MessageSegment,
MessageTemplate, MessageTemplate,
) )
from nonebot.typing import (
Any,
T_State,
T_Handler,
T_ArgsParser,
T_TypeUpdater,
T_PermissionUpdater,
)
from nonebot.exception import ( from nonebot.exception import (
PausedException, PausedException,
StopPropagation, StopPropagation,
@ -42,19 +52,12 @@ from nonebot.exception import (
FinishedException, FinishedException,
RejectedException, RejectedException,
) )
from nonebot.typing import (
T_State,
T_Handler,
T_ArgsParser,
T_TypeUpdater,
T_StateFactory,
T_DependencyCache,
T_PermissionUpdater,
)
if TYPE_CHECKING: if TYPE_CHECKING:
from nonebot.plugin import Plugin from nonebot.plugin import Plugin
T = TypeVar("T")
matchers: Dict[int, List[Type["Matcher"]]] = defaultdict(list) matchers: Dict[int, List[Type["Matcher"]]] = defaultdict(list)
""" """
:类型: ``Dict[int, List[Type[Matcher]]]`` :类型: ``Dict[int, List[Type[Matcher]]]``
@ -63,7 +66,7 @@ matchers: Dict[int, List[Type["Matcher"]]] = defaultdict(list)
current_bot: ContextVar[Bot] = ContextVar("current_bot") current_bot: ContextVar[Bot] = ContextVar("current_bot")
current_event: ContextVar[Event] = ContextVar("current_event") current_event: ContextVar[Event] = ContextVar("current_event")
current_state: ContextVar[T_State] = ContextVar("current_state") current_state: ContextVar[T_State] = ContextVar("current_state")
current_handler: ContextVar[Handler] = ContextVar("current_handler") current_handler: ContextVar[Dependent] = ContextVar("current_handler")
class MatcherMeta(type): class MatcherMeta(type):
@ -131,7 +134,7 @@ class Matcher(metaclass=MatcherMeta):
:类型: ``Permission`` :类型: ``Permission``
:说明: 事件响应器触发权限 :说明: 事件响应器触发权限
""" """
handlers: List[Handler] = [] handlers: List[Dependent[Any]] = []
""" """
:类型: ``List[Handler]`` :类型: ``List[Handler]``
:说明: 事件响应器拥有的事件处理函数列表 :说明: 事件响应器拥有的事件处理函数列表
@ -163,23 +166,24 @@ class Matcher(metaclass=MatcherMeta):
:说明: 事件响应器默认状态 :说明: 事件响应器默认状态
""" """
_default_parser: Optional[T_ArgsParser] = None _default_parser: Optional[Dependent[None]] = None
""" """
:类型: ``Optional[T_ArgsParser]`` :类型: ``Optional[Dependent]``
:说明: 事件响应器默认参数解析函数 :说明: 事件响应器默认参数解析函数
""" """
_default_type_updater: Optional[T_TypeUpdater] = None _default_type_updater: Optional[Dependent[str]] = None
""" """
:类型: ``Optional[T_TypeUpdater]`` :类型: ``Optional[Dependent]``
:说明: 事件响应器类型更新函数 :说明: 事件响应器类型更新函数
""" """
_default_permission_updater: Optional[T_PermissionUpdater] = None _default_permission_updater: Optional[Dependent[Permission]] = None
""" """
:类型: ``Optional[T_PermissionUpdater]`` :类型: ``Optional[Dependent]``
:说明: 事件响应器权限更新函数 :说明: 事件响应器权限更新函数
""" """
HANDLER_PARAM_TYPES = [ HANDLER_PARAM_TYPES = [
params.DependParam,
params.BotParam, params.BotParam,
params.EventParam, params.EventParam,
params.StateParam, params.StateParam,
@ -207,9 +211,7 @@ class Matcher(metaclass=MatcherMeta):
type_: str = "", type_: str = "",
rule: Optional[Rule] = None, rule: Optional[Rule] = None,
permission: Optional[Permission] = None, permission: Optional[Permission] = None,
handlers: Optional[ handlers: Optional[List[Union[T_Handler, Dependent[Any]]]] = None,
Union[List[T_Handler], List[Handler], List[Union[T_Handler, Handler]]]
] = None,
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = False, block: bool = False,
@ -259,8 +261,10 @@ class Matcher(metaclass=MatcherMeta):
"permission": permission or Permission(), "permission": permission or Permission(),
"handlers": [ "handlers": [
handler handler
if isinstance(handler, Handler) if isinstance(handler, Dependent)
else Handler(handler, allow_types=cls.HANDLER_PARAM_TYPES) else Dependent[Any].parse(
call=handler, allow_types=cls.HANDLER_PARAM_TYPES
)
for handler in handlers for handler in handlers
] ]
if handlers if handlers
@ -286,7 +290,7 @@ class Matcher(metaclass=MatcherMeta):
bot: Bot, bot: Bot,
event: Event, event: Event,
stack: Optional[AsyncExitStack] = None, stack: Optional[AsyncExitStack] = None,
dependency_cache: Optional[Dict[Callable[..., Any], Any]] = None, dependency_cache: Optional[CacheDict[T_Handler, Any]] = None,
) -> bool: ) -> bool:
""" """
:说明: :说明:
@ -314,7 +318,7 @@ class Matcher(metaclass=MatcherMeta):
event: Event, event: Event,
state: T_State, state: T_State,
stack: Optional[AsyncExitStack] = None, stack: Optional[AsyncExitStack] = None,
dependency_cache: Optional[Dict[Callable[..., Any], Any]] = None, dependency_cache: Optional[CacheDict[T_Handler, Any]] = None,
) -> bool: ) -> bool:
""" """
:说明: :说明:
@ -347,7 +351,9 @@ class Matcher(metaclass=MatcherMeta):
* ``func: T_ArgsParser``: 参数解析函数 * ``func: T_ArgsParser``: 参数解析函数
""" """
cls._default_parser = func cls._default_parser = Dependent[None].parse(
call=func, allow_types=cls.HANDLER_PARAM_TYPES
)
return func return func
@classmethod @classmethod
@ -361,7 +367,9 @@ class Matcher(metaclass=MatcherMeta):
* ``func: T_TypeUpdater``: 响应事件类型更新函数 * ``func: T_TypeUpdater``: 响应事件类型更新函数
""" """
cls._default_type_updater = func cls._default_type_updater = Dependent[str].parse(
call=func, allow_types=cls.HANDLER_PARAM_TYPES
)
return func return func
@classmethod @classmethod
@ -375,22 +383,26 @@ class Matcher(metaclass=MatcherMeta):
* ``func: T_PermissionUpdater``: 会话权限更新函数 * ``func: T_PermissionUpdater``: 会话权限更新函数
""" """
cls._default_permission_updater = func cls._default_permission_updater = Dependent[Permission].parse(
call=func, allow_types=cls.HANDLER_PARAM_TYPES
)
return func return func
@classmethod @classmethod
def append_handler( def append_handler(
cls, handler: T_Handler, dependencies: Optional[List[DependsWrapper]] = None cls, handler: T_Handler, parameterless: Optional[List[Any]] = None
) -> Handler: ) -> Dependent[Any]:
handler_ = Handler( handler_ = Dependent[Any].parse(
handler, dependencies=dependencies, allow_types=cls.HANDLER_PARAM_TYPES call=handler,
parameterless=parameterless,
allow_types=cls.HANDLER_PARAM_TYPES,
) )
cls.handlers.append(handler_) cls.handlers.append(handler_)
return handler_ return handler_
@classmethod @classmethod
def handle( def handle(
cls, dependencies: Optional[List[DependsWrapper]] = None cls, parameterless: Optional[List[Any]] = None
) -> Callable[[T_Handler], T_Handler]: ) -> Callable[[T_Handler], T_Handler]:
""" """
:说明: :说明:
@ -399,18 +411,18 @@ class Matcher(metaclass=MatcherMeta):
:参数: :参数:
* ``dependencies: Optional[List[DependsWrapper]]``: 非参数类型依赖列表 * ``parameterless: Optional[List[Any]]``: 非参数类型依赖列表
""" """
def _decorator(func: T_Handler) -> T_Handler: def _decorator(func: T_Handler) -> T_Handler:
cls.append_handler(func, dependencies=dependencies) cls.append_handler(func, parameterless=parameterless)
return func return func
return _decorator return _decorator
@classmethod @classmethod
def receive( def receive(
cls, dependencies: Optional[List[DependsWrapper]] = None cls, id: str = "", parameterless: Optional[List[Any]] = None
) -> Callable[[T_Handler], T_Handler]: ) -> Callable[[T_Handler], T_Handler]:
""" """
:说明: :说明:
@ -419,28 +431,30 @@ class Matcher(metaclass=MatcherMeta):
:参数: :参数:
* ``dependencies: Optional[List[DependsWrapper]]``: 非参数类型依赖列表 * ``parameterless: Optional[List[Any]]``: 非参数类型依赖列表
""" """
async def _receive(state: T_State) -> Union[None, NoReturn]: async def _receive(event: Event, matcher: "Matcher") -> Union[None, NoReturn]:
if state.get(_receive): if matcher.get_receive(id):
return return
state[_receive] = True if matcher.get_target() == RECEIVE_KEY.format(id=id):
del state["_current_key"] matcher.set_receive(id, event)
return
matcher.set_target(RECEIVE_KEY.format(id=id))
raise RejectedException raise RejectedException
_dependencies = [DependsWrapper(_receive), *(dependencies or [])] parameterless = [params.Depends(_receive), *(parameterless or [])]
def _decorator(func: T_Handler) -> T_Handler: def _decorator(func: T_Handler) -> T_Handler:
if cls.handlers and cls.handlers[-1].call is func: if cls.handlers and cls.handlers[-1].call is func:
func_handler = cls.handlers[-1] func_handler = cls.handlers[-1]
for depend in reversed(_dependencies): for depend in reversed(parameterless):
func_handler.prepend_dependency(depend) func_handler.prepend_parameterless(depend)
else: else:
cls.append_handler( cls.append_handler(
func, func,
dependencies=_dependencies if cls.handlers else dependencies, parameterless=parameterless if cls.handlers else parameterless,
) )
return func return func
@ -453,7 +467,7 @@ class Matcher(metaclass=MatcherMeta):
key: str, key: str,
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None, prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
args_parser: Optional[T_ArgsParser] = None, args_parser: Optional[T_ArgsParser] = None,
dependencies: Optional[List[DependsWrapper]] = None, parameterless: Optional[List[Any]] = None,
) -> Callable[[T_Handler], T_Handler]: ) -> Callable[[T_Handler], T_Handler]:
""" """
:说明: :说明:
@ -465,51 +479,31 @@ class Matcher(metaclass=MatcherMeta):
* ``key: str``: 参数名 * ``key: str``: 参数名
* ``prompt: Optional[Union[str, Message, MessageSegment, MessageFormatter]]``: 在参数不存在时向用户发送的消息 * ``prompt: Optional[Union[str, Message, MessageSegment, MessageFormatter]]``: 在参数不存在时向用户发送的消息
* ``args_parser: Optional[T_ArgsParser]``: 可选参数解析函数空则使用默认解析函数 * ``args_parser: Optional[T_ArgsParser]``: 可选参数解析函数空则使用默认解析函数
* ``dependencies: Optional[List[DependsWrapper]]``: 非参数类型依赖列表 * ``parameterless: Optional[List[Any]]``: 非参数类型依赖列表
""" """
async def _key_getter(bot: Bot, event: Event, state: T_State): async def _key_getter(event: Event, matcher: "Matcher"):
if state.get(f"_{key}_prompted"): if matcher.get_arg(key):
return return
if matcher.get_target() == ARG_KEY.format(key=key):
state["_current_key"] = key matcher.set_arg(key, event)
state[f"_{key}_prompted"] = True
if key not in state:
if prompt is not None:
if isinstance(prompt, MessageTemplate):
_prompt = prompt.format(**state)
else:
_prompt = prompt
await bot.send(event=event, message=_prompt)
raise RejectedException
else:
state[f"_{key}_parsed"] = True
async def _key_parser(bot: Bot, event: Event, state: T_State):
if key in state and state.get(f"_{key}_parsed"):
return return
matcher.set_target(ARG_KEY.format(key=key))
raise RejectedException
parser = args_parser or cls._default_parser _parameterless = [
if parser: params.Depends(_key_getter),
await parser(bot, event, state) *(parameterless or []),
else:
state[key] = str(event.get_message())
state[f"_{key}_parsed"] = True
_dependencies = [
DependsWrapper(_key_getter),
DependsWrapper(_key_parser),
*(dependencies or []),
] ]
def _decorator(func: T_Handler) -> T_Handler: def _decorator(func: T_Handler) -> T_Handler:
if cls.handlers and cls.handlers[-1].call is func: if cls.handlers and cls.handlers[-1].call is func:
func_handler = cls.handlers[-1] func_handler = cls.handlers[-1]
for depend in reversed(_dependencies): for depend in reversed(_parameterless):
func_handler.prepend_dependency(depend) func_handler.prepend_parameterless(depend)
else: else:
cls.append_handler(func, dependencies=_dependencies) cls.append_handler(func, parameterless=_parameterless)
return func return func
@ -609,8 +603,6 @@ class Matcher(metaclass=MatcherMeta):
bot = current_bot.get() bot = current_bot.get()
event = current_event.get() event = current_event.get()
state = current_state.get() state = current_state.get()
if "_current_key" in state and f"_{state['_current_key']}_parsed" in state:
del state[f"_{state['_current_key']}_parsed"]
if isinstance(prompt, MessageTemplate): if isinstance(prompt, MessageTemplate):
_prompt = prompt.format(**state) _prompt = prompt.format(**state)
else: else:
@ -619,6 +611,28 @@ class Matcher(metaclass=MatcherMeta):
await bot.send(event=event, message=_prompt, **kwargs) await bot.send(event=event, message=_prompt, **kwargs)
raise RejectedException raise RejectedException
def get_receive(self, id: str, default: T = None) -> Union[Event, T]:
return self.state.get(RECEIVE_KEY.format(id=id), default)
def set_receive(self, id: str, event: Event) -> None:
self.state[RECEIVE_KEY.format(id=id)] = event
def get_arg(self, key: str, default: T = None) -> Union[Event, T]:
return self.state.get(ARG_KEY.format(key=key), default)
def get_arg_str(self, key: str, default: T = None) -> Union[str, T]:
return self.state.get(ARG_STR_KEY.format(key=key), default)
def set_arg(self, key: str, event: Event) -> None:
self.state[ARG_KEY.format(key=key)] = event
self.state[ARG_STR_KEY.format(key=key)] = str(event.get_message())
def set_target(self, target: str) -> None:
self.state[REJECT_TARGET] = target
def get_target(self, default: T = None) -> Union[str, T]:
return self.state.get(REJECT_TARGET, default)
def stop_propagation(self): def stop_propagation(self):
""" """
:说明: :说明:
@ -631,13 +645,13 @@ class Matcher(metaclass=MatcherMeta):
updater = self.__class__._default_type_updater updater = self.__class__._default_type_updater
if not updater: if not updater:
return "message" return "message"
return await updater(bot, event, self.state, self.type) return await updater(bot=bot, event=event, state=self.state, matcher=self)
async def update_permission(self, bot: Bot, event: Event) -> Permission: async def update_permission(self, bot: Bot, event: Event) -> Permission:
updater = self.__class__._default_permission_updater updater = self.__class__._default_permission_updater
if not updater: if not updater:
return USER(event.get_session_id(), perm=self.permission) return USER(event.get_session_id(), perm=self.permission)
return await updater(bot, event, self.state, self.permission) return await updater(bot=bot, event=event, state=self.state, matcher=self)
async def simple_run( async def simple_run(
self, self,
@ -645,7 +659,7 @@ class Matcher(metaclass=MatcherMeta):
event: Event, event: Event,
state: T_State, state: T_State,
stack: Optional[AsyncExitStack] = None, stack: Optional[AsyncExitStack] = None,
dependency_cache: Optional[T_DependencyCache] = None, dependency_cache: Optional[CacheDict[T_Handler, Any]] = None,
): ):
b_t = current_bot.set(bot) b_t = current_bot.set(bot)
e_t = current_event.set(event) e_t = current_event.set(event)
@ -664,8 +678,8 @@ class Matcher(metaclass=MatcherMeta):
bot=bot, bot=bot,
event=event, event=event,
state=self.state, state=self.state,
_stack=stack, stack=stack,
_dependency_cache=dependency_cache, dependency_cache=dependency_cache,
) )
except SkippedException as e: except SkippedException as e:
logger.debug( logger.debug(
@ -687,7 +701,7 @@ class Matcher(metaclass=MatcherMeta):
event: Event, event: Event,
state: T_State, state: T_State,
stack: Optional[AsyncExitStack] = None, stack: Optional[AsyncExitStack] = None,
dependency_cache: Optional[T_DependencyCache] = None, dependency_cache: Optional[CacheDict[T_Handler, Any]] = None,
): ):
try: try:
await self.simple_run(bot, event, state, stack, dependency_cache) await self.simple_run(bot, event, state, stack, dependency_cache)

View File

@ -22,9 +22,9 @@ from typing import (
from nonebot import params from nonebot import params
from nonebot.log import logger from nonebot.log import logger
from nonebot.rule import TrieRule from nonebot.rule import TrieRule
from nonebot.handler import Handler from nonebot.dependencies import Dependent
from nonebot.utils import escape_tag
from nonebot.matcher import Matcher, matchers from nonebot.matcher import Matcher, matchers
from nonebot.utils import CacheDict, escape_tag
from nonebot.exception import ( from nonebot.exception import (
NoLogException, NoLogException,
StopPropagation, StopPropagation,
@ -33,7 +33,7 @@ from nonebot.exception import (
) )
from nonebot.typing import ( from nonebot.typing import (
T_State, T_State,
T_DependencyCache, T_Handler,
T_RunPreProcessor, T_RunPreProcessor,
T_RunPostProcessor, T_RunPostProcessor,
T_EventPreProcessor, T_EventPreProcessor,
@ -43,18 +43,20 @@ from nonebot.typing import (
if TYPE_CHECKING: if TYPE_CHECKING:
from nonebot.adapters import Bot, Event from nonebot.adapters import Bot, Event
_event_preprocessors: Set[Handler] = set() _event_preprocessors: Set[Dependent[None]] = set()
_event_postprocessors: Set[Handler] = set() _event_postprocessors: Set[Dependent[None]] = set()
_run_preprocessors: Set[Handler] = set() _run_preprocessors: Set[Dependent[None]] = set()
_run_postprocessors: Set[Handler] = set() _run_postprocessors: Set[Dependent[None]] = set()
EVENT_PCS_PARAMS = [ EVENT_PCS_PARAMS = [
params.DependParam,
params.BotParam, params.BotParam,
params.EventParam, params.EventParam,
params.StateParam, params.StateParam,
params.DefaultParam, params.DefaultParam,
] ]
RUN_PREPCS_PARAMS = [ RUN_PREPCS_PARAMS = [
params.DependParam,
params.MatcherParam, params.MatcherParam,
params.BotParam, params.BotParam,
params.EventParam, params.EventParam,
@ -62,6 +64,7 @@ RUN_PREPCS_PARAMS = [
params.DefaultParam, params.DefaultParam,
] ]
RUN_POSTPCS_PARAMS = [ RUN_POSTPCS_PARAMS = [
params.DependParam,
params.MatcherParam, params.MatcherParam,
params.ExceptionParam, params.ExceptionParam,
params.BotParam, params.BotParam,
@ -77,7 +80,9 @@ def event_preprocessor(func: T_EventPreProcessor) -> T_EventPreProcessor:
事件预处理装饰一个函数使它在每次接收到事件并分发给各响应器之前执行 事件预处理装饰一个函数使它在每次接收到事件并分发给各响应器之前执行
""" """
_event_preprocessors.add(Handler(func, allow_types=EVENT_PCS_PARAMS)) _event_preprocessors.add(
Dependent[None].parse(call=func, allow_types=EVENT_PCS_PARAMS)
)
return func return func
@ -87,7 +92,9 @@ def event_postprocessor(func: T_EventPostProcessor) -> T_EventPostProcessor:
事件后处理装饰一个函数使它在每次接收到事件并分发给各响应器之后执行 事件后处理装饰一个函数使它在每次接收到事件并分发给各响应器之后执行
""" """
_event_postprocessors.add(Handler(func, allow_types=EVENT_PCS_PARAMS)) _event_postprocessors.add(
Dependent[None].parse(call=func, allow_types=EVENT_PCS_PARAMS)
)
return func return func
@ -97,7 +104,9 @@ def run_preprocessor(func: T_RunPreProcessor) -> T_RunPreProcessor:
运行预处理装饰一个函数使它在每次事件响应器运行前执行 运行预处理装饰一个函数使它在每次事件响应器运行前执行
""" """
_run_preprocessors.add(Handler(func, allow_types=RUN_PREPCS_PARAMS)) _run_preprocessors.add(
Dependent[None].parse(call=func, allow_types=RUN_PREPCS_PARAMS)
)
return func return func
@ -107,7 +116,9 @@ def run_postprocessor(func: T_RunPostProcessor) -> T_RunPostProcessor:
运行后处理装饰一个函数使它在每次事件响应器运行后执行 运行后处理装饰一个函数使它在每次事件响应器运行后执行
""" """
_run_postprocessors.add(Handler(func, allow_types=RUN_POSTPCS_PARAMS)) _run_postprocessors.add(
Dependent[None].parse(call=func, allow_types=RUN_POSTPCS_PARAMS)
)
return func return func
@ -125,7 +136,7 @@ async def _check_matcher(
event: "Event", event: "Event",
state: T_State, state: T_State,
stack: Optional[AsyncExitStack] = None, stack: Optional[AsyncExitStack] = None,
dependency_cache: Optional[T_DependencyCache] = None, dependency_cache: Optional[CacheDict[T_Handler, Any]] = None,
) -> None: ) -> None:
if Matcher.expire_time and datetime.now() > Matcher.expire_time: if Matcher.expire_time and datetime.now() > Matcher.expire_time:
try: try:
@ -160,7 +171,7 @@ async def _run_matcher(
event: "Event", event: "Event",
state: T_State, state: T_State,
stack: Optional[AsyncExitStack] = None, stack: Optional[AsyncExitStack] = None,
dependency_cache: Optional[T_DependencyCache] = None, dependency_cache: Optional[CacheDict[T_Handler, Any]] = None,
) -> None: ) -> None:
logger.info(f"Event will be handled by {Matcher}") logger.info(f"Event will be handled by {Matcher}")
@ -174,8 +185,8 @@ async def _run_matcher(
bot=bot, bot=bot,
event=event, event=event,
state=state, state=state,
_stack=stack, stack=stack,
_dependency_cache=dependency_cache, dependency_cache=dependency_cache,
) )
), ),
_run_preprocessors, _run_preprocessors,
@ -216,8 +227,8 @@ async def _run_matcher(
bot=bot, bot=bot,
event=event, event=event,
state=state, state=state,
_stack=stack, stack=stack,
_dependency_cache=dependency_cache, dependency_cache=dependency_cache,
) )
), ),
_run_postprocessors, _run_postprocessors,
@ -264,7 +275,7 @@ async def handle_event(bot: "Bot", event: "Event") -> None:
logger.opt(colors=True).success(log_msg) logger.opt(colors=True).success(log_msg)
state: Dict[Any, Any] = {} state: Dict[Any, Any] = {}
dependency_cache: T_DependencyCache = {} dependency_cache: CacheDict[T_Handler, Any] = CacheDict()
async with AsyncExitStack() as stack: async with AsyncExitStack() as stack:
coros = list( coros = list(
@ -274,8 +285,8 @@ async def handle_event(bot: "Bot", event: "Event") -> None:
bot=bot, bot=bot,
event=event, event=event,
state=state, state=state,
_stack=stack, stack=stack,
_dependency_cache=dependency_cache, dependency_cache=dependency_cache,
) )
), ),
_event_preprocessors, _event_preprocessors,
@ -336,8 +347,8 @@ async def handle_event(bot: "Bot", event: "Event") -> None:
bot=bot, bot=bot,
event=event, event=event,
state=state, state=state,
_stack=stack, stack=stack,
_dependency_cache=dependency_cache, dependency_cache=dependency_cache,
) )
), ),
_event_postprocessors, _event_postprocessors,

View File

@ -1,20 +1,160 @@
import inspect import inspect
from typing import Any, Dict, Optional from typing import Any, List, Type, Callable, Optional, cast
from contextlib import AsyncExitStack, contextmanager, asynccontextmanager
from pydantic.fields import Undefined from pydantic.fields import Required, Undefined
from nonebot.typing import T_State
from nonebot.dependencies import Param
from nonebot.adapters import Bot, Event from nonebot.adapters import Bot, Event
from nonebot.utils import generic_check_issubclass from nonebot.typing import T_State, T_Handler
from nonebot.dependencies import Param, Dependent
from nonebot.utils import (
CacheDict,
get_name,
run_sync,
is_gen_callable,
run_sync_ctx_manager,
is_async_gen_callable,
is_coroutine_callable,
generic_check_issubclass,
)
class DependsInner:
def __init__(
self,
dependency: Optional[T_Handler] = None,
*,
use_cache: bool = True,
) -> None:
self.dependency = dependency
self.use_cache = use_cache
def __repr__(self) -> str:
dep = get_name(self.dependency)
cache = "" if self.use_cache else ", use_cache=False"
return f"{self.__class__.__name__}({dep}{cache})"
def Depends(
dependency: Optional[T_Handler] = None,
*,
use_cache: bool = True,
) -> Any:
"""
:说明:
参数依赖注入装饰器
:参数:
* ``dependency: Optional[Callable[..., Any]] = None``: 依赖函数默认为参数的类型注释
* ``use_cache: bool = True``: 是否使用缓存默认为 ``True``
* ``allow_types: Optional[List[Type[Param]]] = None``: 允许的参数类型默认为 ``None``
.. code-block:: python
def depend_func() -> Any:
return ...
def depend_gen_func():
try:
yield ...
finally:
...
async def handler(param_name: Any = Depends(depend_func), gen: Any = Depends(depend_gen_func)):
...
"""
return DependsInner(dependency, use_cache=use_cache)
class DependParam(Param):
@classmethod
def _check_param(
cls,
dependent: Dependent,
name: str,
param: inspect.Parameter,
) -> Optional["DependParam"]:
if isinstance(param.default, DependsInner):
dependency: T_Handler
if param.default.dependency is None:
assert param.annotation is not param.empty, "Dependency cannot be empty"
dependency = param.annotation
else:
dependency = param.default.dependency
dependent = Dependent[Any].parse(
call=dependency,
allow_types=dependent.allow_types,
)
return cls(Required, use_cache=param.default.use_cache, dependent=dependent)
@classmethod
def _check_parameterless(
cls, dependent: "Dependent", value: Any
) -> Optional["Param"]:
if isinstance(value, DependsInner):
assert value.dependency, "Dependency cannot be empty"
dependent = Dependent[Any].parse(
call=value.dependency, allow_types=dependent.allow_types
)
return cls(Required, use_cache=value.use_cache, dependent=dependent)
async def _solve(
self,
stack: Optional[AsyncExitStack] = None,
dependency_cache: Optional[CacheDict[T_Handler, Any]] = None,
**kwargs: Any,
) -> Any:
use_cache: bool = self.extra["use_cache"]
dependency_cache = CacheDict() if dependency_cache is None else dependency_cache
sub_dependent: Dependent = self.extra["dependent"]
sub_dependent.call = cast(Callable[..., Any], sub_dependent.call)
call = sub_dependent.call
# solve sub dependency with current cache
sub_values = await sub_dependent.solve(
stack=stack,
dependency_cache=dependency_cache,
**kwargs,
)
# run dependency function
async with dependency_cache:
if use_cache and call in dependency_cache:
solved = dependency_cache[call]
elif is_gen_callable(call) or is_async_gen_callable(call):
assert isinstance(
stack, AsyncExitStack
), "Generator dependency should be called in context"
if is_gen_callable(call):
cm = run_sync_ctx_manager(contextmanager(call)(**sub_values))
else:
cm = asynccontextmanager(call)(**sub_values)
solved = await stack.enter_async_context(cm)
elif is_coroutine_callable(call):
return await call(**sub_values)
else:
return await run_sync(call)(**sub_values)
# save current dependency to cache
if call not in dependency_cache:
dependency_cache[call] = solved
return solved
class BotParam(Param): class BotParam(Param):
@classmethod @classmethod
def _check(cls, name: str, param: inspect.Parameter) -> bool: def _check_param(
return generic_check_issubclass(param.annotation, Bot) or ( cls, dependent: Dependent, name: str, param: inspect.Parameter
param.annotation == param.empty and name == "bot" ) -> Optional["BotParam"]:
) if param.default == param.empty and (
generic_check_issubclass(param.annotation, Bot)
or (param.annotation == param.empty and name == "bot")
):
return cls(Required)
def _solve(self, bot: Bot, **kwargs: Any) -> Any: def _solve(self, bot: Bot, **kwargs: Any) -> Any:
return bot return bot
@ -22,22 +162,34 @@ class BotParam(Param):
class EventParam(Param): class EventParam(Param):
@classmethod @classmethod
def _check(cls, name: str, param: inspect.Parameter) -> bool: def _check_param(
return generic_check_issubclass(param.annotation, Event) or ( cls, dependent: Dependent, name: str, param: inspect.Parameter
param.annotation == param.empty and name == "event" ) -> Optional["EventParam"]:
) if param.default == param.empty and (
generic_check_issubclass(param.annotation, Event)
or (param.annotation == param.empty and name == "event")
):
return cls(Required)
def _solve(self, event: Event, **kwargs: Any) -> Any: def _solve(self, event: Event, **kwargs: Any) -> Any:
return event return event
# FIXME: may detect error param class StateInner:
...
def State() -> Any:
return StateInner()
class StateParam(Param): class StateParam(Param):
@classmethod @classmethod
def _check(cls, name: str, param: inspect.Parameter) -> bool: def _check_param(
return generic_check_issubclass(param.annotation, Dict) or ( cls, dependent: Dependent, name: str, param: inspect.Parameter
param.annotation == param.empty and name == "state" ) -> Optional["StateParam"]:
) if isinstance(param.default, StateInner):
return cls(Required)
def _solve(self, state: T_State, **kwargs: Any) -> Any: def _solve(self, state: T_State, **kwargs: Any) -> Any:
return state return state
@ -45,21 +197,27 @@ class StateParam(Param):
class MatcherParam(Param): class MatcherParam(Param):
@classmethod @classmethod
def _check(cls, name: str, param: inspect.Parameter) -> bool: def _check_param(
return generic_check_issubclass(param.annotation, Matcher) or ( cls, dependent: Dependent, name: str, param: inspect.Parameter
) -> Optional["MatcherParam"]:
if generic_check_issubclass(param.annotation, Matcher) or (
param.annotation == param.empty and name == "matcher" param.annotation == param.empty and name == "matcher"
) ):
return cls(Required)
def _solve(self, matcher: Optional["Matcher"] = None, **kwargs: Any) -> Any: def _solve(self, matcher: "Matcher", **kwargs: Any) -> Any:
return matcher return matcher
class ExceptionParam(Param): class ExceptionParam(Param):
@classmethod @classmethod
def _check(cls, name: str, param: inspect.Parameter) -> bool: def _check_param(
return generic_check_issubclass(param.annotation, Exception) or ( cls, dependent: Dependent, name: str, param: inspect.Parameter
) -> Optional["ExceptionParam"]:
if generic_check_issubclass(param.annotation, Exception) or (
param.annotation == param.empty and name == "exception" param.annotation == param.empty and name == "exception"
) ):
return cls(Required)
def _solve(self, exception: Optional[Exception] = None, **kwargs: Any) -> Any: def _solve(self, exception: Optional[Exception] = None, **kwargs: Any) -> Any:
return exception return exception
@ -67,8 +225,11 @@ class ExceptionParam(Param):
class DefaultParam(Param): class DefaultParam(Param):
@classmethod @classmethod
def _check(cls, name: str, param: inspect.Parameter) -> bool: def _check_param(
return param.default != param.empty cls, dependent: Dependent, name: str, param: inspect.Parameter
) -> Optional["DefaultParam"]:
if param.default != param.empty:
return cls(param.default)
def _solve(self, **kwargs: Any) -> Any: def _solve(self, **kwargs: Any) -> Any:
return Undefined return Undefined

View File

@ -13,6 +13,7 @@ import asyncio
from contextlib import AsyncExitStack from contextlib import AsyncExitStack
from typing import ( from typing import (
Any, Any,
Set,
Dict, Dict,
Tuple, Tuple,
Union, Union,
@ -23,10 +24,11 @@ from typing import (
) )
from nonebot import params from nonebot import params
from nonebot.handler import Handler from nonebot.utils import CacheDict
from nonebot.adapters import Bot, Event from nonebot.adapters import Bot, Event
from nonebot.dependencies import Dependent
from nonebot.exception import SkippedException from nonebot.exception import SkippedException
from nonebot.typing import T_PermissionChecker from nonebot.typing import T_Handler, T_PermissionChecker
async def _run_coro_with_catch(coro: Coroutine[Any, Any, Any]): async def _run_coro_with_catch(coro: Coroutine[Any, Any, Any]):
@ -54,19 +56,26 @@ class Permission:
__slots__ = ("checkers",) __slots__ = ("checkers",)
HANDLER_PARAM_TYPES = [params.BotParam, params.EventParam, params.DefaultParam] HANDLER_PARAM_TYPES = [
params.DependParam,
params.BotParam,
params.EventParam,
params.DefaultParam,
]
def __init__(self, *checkers: Union[T_PermissionChecker, Handler]) -> None: def __init__(self, *checkers: Union[T_PermissionChecker, Dependent[bool]]) -> None:
""" """
:参数: :参数:
* ``*checkers: Union[T_PermissionChecker, Handler]``: PermissionChecker * ``*checkers: Union[T_PermissionChecker, Dependent[bool]``: PermissionChecker
""" """
self.checkers = set( self.checkers: Set[Dependent[bool]] = set(
checker checker
if isinstance(checker, Handler) if isinstance(checker, Dependent)
else Handler(checker, allow_types=self.HANDLER_PARAM_TYPES) else Dependent[bool].parse(
call=checker, allow_types=self.HANDLER_PARAM_TYPES
)
for checker in checkers for checker in checkers
) )
""" """
@ -76,7 +85,7 @@ class Permission:
:类型: :类型:
* ``Set[Handler]`` * ``Set[Dependent[bool]]``
""" """
async def __call__( async def __call__(
@ -84,7 +93,7 @@ class Permission:
bot: Bot, bot: Bot,
event: Event, event: Event,
stack: Optional[AsyncExitStack] = None, stack: Optional[AsyncExitStack] = None,
dependency_cache: Optional[Dict[Callable[..., Any], Any]] = None, dependency_cache: Optional[CacheDict[T_Handler, Any]] = None,
) -> bool: ) -> bool:
""" """
:说明: :说明:
@ -96,7 +105,7 @@ class Permission:
* ``bot: Bot``: Bot 对象 * ``bot: Bot``: Bot 对象
* ``event: Event``: Event 对象 * ``event: Event``: Event 对象
* ``stack: Optional[AsyncExitStack]``: 异步上下文栈 * ``stack: Optional[AsyncExitStack]``: 异步上下文栈
* ``dependency_cache: Optional[Dict[Callable[..., Any], Any]]``: 依赖缓存 * ``dependency_cache: Optional[CacheDict[T_Handler, Any]]``: 依赖缓存
:返回: :返回:
@ -110,8 +119,8 @@ class Permission:
checker( checker(
bot=bot, bot=bot,
event=event, event=event,
_stack=stack, stack=stack,
_dependency_cache=dependency_cache, dependency_cache=dependency_cache,
) )
) )
for checker in self.checkers for checker in self.checkers

View File

@ -5,11 +5,16 @@ from types import ModuleType
from typing import Any, Set, Dict, List, Type, Tuple, Union, Optional from typing import Any, Set, Dict, List, Type, Tuple, Union, Optional
from nonebot.adapters import Event from nonebot.adapters import Event
from nonebot.handler import Handler
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from .manager import _current_plugin from .manager import _current_plugin
from nonebot.permission import Permission from nonebot.permission import Permission
from nonebot.typing import T_State, T_Handler, T_RuleChecker, T_StateFactory from nonebot.dependencies import Dependent
from nonebot.typing import (
T_State,
T_Handler,
T_RuleChecker,
T_PermissionChecker,
)
from nonebot.rule import ( from nonebot.rule import (
PREFIX_KEY, PREFIX_KEY,
RAW_CMD_KEY, RAW_CMD_KEY,
@ -43,9 +48,9 @@ def _get_matcher_module(depth: int = 1) -> Optional[ModuleType]:
def on( def on(
type: str = "", type: str = "",
rule: Optional[Union[Rule, T_RuleChecker]] = None, rule: Optional[Union[Rule, T_RuleChecker]] = None,
permission: Optional[Permission] = None, permission: Optional[Union[Permission, T_PermissionChecker]] = None,
*, *,
handlers: Optional[List[Union[T_Handler, Handler]]] = None, handlers: Optional[List[Union[T_Handler, Dependent]]] = None,
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = False, block: bool = False,
@ -61,8 +66,8 @@ def on(
* ``type: str``: 事件响应器类型 * ``type: str``: 事件响应器类型
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -75,7 +80,7 @@ def on(
matcher = Matcher.new( matcher = Matcher.new(
type, type,
Rule() & rule, Rule() & rule,
permission or Permission(), Permission() | permission,
temp=temp, temp=temp,
priority=priority, priority=priority,
block=block, block=block,
@ -91,7 +96,7 @@ def on(
def on_metaevent( def on_metaevent(
rule: Optional[Union[Rule, T_RuleChecker]] = None, rule: Optional[Union[Rule, T_RuleChecker]] = None,
*, *,
handlers: Optional[List[Union[T_Handler, Handler]]] = None, handlers: Optional[List[Union[T_Handler, Dependent]]] = None,
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = False, block: bool = False,
@ -106,7 +111,7 @@ def on_metaevent(
:参数: :参数:
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -134,9 +139,9 @@ def on_metaevent(
def on_message( def on_message(
rule: Optional[Union[Rule, T_RuleChecker]] = None, rule: Optional[Union[Rule, T_RuleChecker]] = None,
permission: Optional[Permission] = None, permission: Optional[Union[Permission, T_PermissionChecker]] = None,
*, *,
handlers: Optional[List[Union[T_Handler, Handler]]] = None, handlers: Optional[List[Union[T_Handler, Dependent]]] = None,
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = True, block: bool = True,
@ -151,8 +156,8 @@ def on_message(
:参数: :参数:
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -165,7 +170,7 @@ def on_message(
matcher = Matcher.new( matcher = Matcher.new(
"message", "message",
Rule() & rule, Rule() & rule,
permission or Permission(), Permission() | permission,
temp=temp, temp=temp,
priority=priority, priority=priority,
block=block, block=block,
@ -181,7 +186,7 @@ def on_message(
def on_notice( def on_notice(
rule: Optional[Union[Rule, T_RuleChecker]] = None, rule: Optional[Union[Rule, T_RuleChecker]] = None,
*, *,
handlers: Optional[List[Union[T_Handler, Handler]]] = None, handlers: Optional[List[Union[T_Handler, Dependent]]] = None,
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = False, block: bool = False,
@ -196,7 +201,7 @@ def on_notice(
:参数: :参数:
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -225,7 +230,7 @@ def on_notice(
def on_request( def on_request(
rule: Optional[Union[Rule, T_RuleChecker]] = None, rule: Optional[Union[Rule, T_RuleChecker]] = None,
*, *,
handlers: Optional[List[Union[T_Handler, Handler]]] = None, handlers: Optional[List[Union[T_Handler, Dependent]]] = None,
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = False, block: bool = False,
@ -240,7 +245,7 @@ def on_request(
:参数: :参数:
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -283,8 +288,8 @@ def on_startswith(
* ``msg: Union[str, Tuple[str, ...]]``: 指定消息开头内容 * ``msg: Union[str, Tuple[str, ...]]``: 指定消息开头内容
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``ignorecase: bool``: 是否忽略大小写 * ``ignorecase: bool``: 是否忽略大小写
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -314,8 +319,8 @@ def on_endswith(
* ``msg: Union[str, Tuple[str, ...]]``: 指定消息结尾内容 * ``msg: Union[str, Tuple[str, ...]]``: 指定消息结尾内容
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``ignorecase: bool``: 是否忽略大小写 * ``ignorecase: bool``: 是否忽略大小写
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -343,8 +348,8 @@ def on_keyword(
* ``keywords: Set[str]``: 关键词列表 * ``keywords: Set[str]``: 关键词列表
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -376,8 +381,8 @@ def on_command(
* ``cmd: Union[str, Tuple[str, ...]]``: 指定命令内容 * ``cmd: Union[str, Tuple[str, ...]]``: 指定命令内容
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``aliases: Optional[Set[Union[str, Tuple[str, ...]]]]``: 命令别名 * ``aliases: Optional[Set[Union[str, Tuple[str, ...]]]]``: 命令别名
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -434,8 +439,8 @@ def on_shell_command(
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``aliases: Optional[Set[Union[str, Tuple[str, ...]]]]``: 命令别名 * ``aliases: Optional[Set[Union[str, Tuple[str, ...]]]]``: 命令别名
* ``parser: Optional[ArgumentParser]``: ``nonebot.rule.ArgumentParser`` 对象 * ``parser: Optional[ArgumentParser]``: ``nonebot.rule.ArgumentParser`` 对象
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -486,8 +491,8 @@ def on_regex(
* ``pattern: str``: 正则表达式 * ``pattern: str``: 正则表达式
* ``flags: Union[int, re.RegexFlag]``: 正则匹配标志 * ``flags: Union[int, re.RegexFlag]``: 正则匹配标志
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -600,8 +605,8 @@ class MatcherGroup:
* ``type: str``: 事件响应器类型 * ``type: str``: 事件响应器类型
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -626,7 +631,7 @@ class MatcherGroup:
:参数: :参数:
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -653,8 +658,8 @@ class MatcherGroup:
:参数: :参数:
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -680,7 +685,7 @@ class MatcherGroup:
:参数: :参数:
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -706,7 +711,7 @@ class MatcherGroup:
:参数: :参数:
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -736,8 +741,8 @@ class MatcherGroup:
* ``msg: Union[str, Tuple[str, ...]]``: 指定消息开头内容 * ``msg: Union[str, Tuple[str, ...]]``: 指定消息开头内容
* ``ignorecase: bool``: 是否忽略大小写 * ``ignorecase: bool``: 是否忽略大小写
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -765,8 +770,8 @@ class MatcherGroup:
* ``msg: Union[str, Tuple[str, ...]]``: 指定消息结尾内容 * ``msg: Union[str, Tuple[str, ...]]``: 指定消息结尾内容
* ``ignorecase: bool``: 是否忽略大小写 * ``ignorecase: bool``: 是否忽略大小写
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -793,8 +798,8 @@ class MatcherGroup:
* ``keywords: Set[str]``: 关键词列表 * ``keywords: Set[str]``: 关键词列表
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -829,8 +834,8 @@ class MatcherGroup:
* ``cmd: Union[str, Tuple[str, ...]]``: 指定命令内容 * ``cmd: Union[str, Tuple[str, ...]]``: 指定命令内容
* ``aliases: Optional[Set[Union[str, Tuple[str, ...]]]]``: 命令别名 * ``aliases: Optional[Set[Union[str, Tuple[str, ...]]]]``: 命令别名
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -869,8 +874,8 @@ class MatcherGroup:
* ``aliases: Optional[Set[Union[str, Tuple[str, ...]]]]``: 命令别名 * ``aliases: Optional[Set[Union[str, Tuple[str, ...]]]]``: 命令别名
* ``parser: Optional[ArgumentParser]``: ``nonebot.rule.ArgumentParser`` 对象 * ``parser: Optional[ArgumentParser]``: ``nonebot.rule.ArgumentParser`` 对象
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
@ -904,8 +909,8 @@ class MatcherGroup:
* ``pattern: str``: 正则表达式 * ``pattern: str``: 正则表达式
* ``flags: Union[int, re.RegexFlag]``: 正则匹配标志 * ``flags: Union[int, re.RegexFlag]``: 正则匹配标志
* ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则
* ``permission: Optional[Permission]``: 事件响应权限 * ``permission: Optional[Union[Permission, T_PermissionChecker]] =]]``: 事件响应权限
* ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``handlers: Optional[List[Union[T_Handler, Dependent]]]``: 事件处理函数列表
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递

View File

@ -1,18 +1,23 @@
import re import re
from typing import Set, List, Type, Tuple, Union, Optional from typing import Set, List, Type, Tuple, Union, Optional
from nonebot.handler import Handler
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot.permission import Permission from nonebot.permission import Permission
from nonebot.dependencies import Dependent
from nonebot.rule import Rule, ArgumentParser from nonebot.rule import Rule, ArgumentParser
from nonebot.typing import T_State, T_Handler, T_RuleChecker, T_StateFactory from nonebot.typing import (
T_State,
T_Handler,
T_RuleChecker,
T_PermissionChecker,
)
def on( def on(
type: str = "", type: str = "",
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
*, *,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -21,7 +26,7 @@ def on(
def on_metaevent( def on_metaevent(
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
*, *,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -29,9 +34,9 @@ def on_metaevent(
) -> Type[Matcher]: ... ) -> Type[Matcher]: ...
def on_message( def on_message(
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
*, *,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -40,7 +45,7 @@ def on_message(
def on_notice( def on_notice(
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
*, *,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -49,7 +54,7 @@ def on_notice(
def on_request( def on_request(
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
*, *,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -60,8 +65,8 @@ def on_startswith(
rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = ..., rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = ...,
ignorecase: bool = ..., ignorecase: bool = ...,
*, *,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -72,8 +77,8 @@ def on_endswith(
rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = ..., rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = ...,
ignorecase: bool = ..., ignorecase: bool = ...,
*, *,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -83,8 +88,8 @@ def on_keyword(
keywords: Set[str], keywords: Set[str],
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
*, *,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -95,8 +100,8 @@ def on_command(
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ..., aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ...,
*, *,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -108,8 +113,8 @@ def on_shell_command(
aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ..., aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ...,
parser: Optional[ArgumentParser] = ..., parser: Optional[ArgumentParser] = ...,
*, *,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -120,8 +125,8 @@ def on_regex(
flags: Union[int, re.RegexFlag] = ..., flags: Union[int, re.RegexFlag] = ...,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
*, *,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -134,8 +139,8 @@ class CommandGroup:
cmd: Union[str, Tuple[str, ...]], cmd: Union[str, Tuple[str, ...]],
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -147,8 +152,8 @@ class CommandGroup:
*, *,
aliases: Optional[Set[Union[str, Tuple[str, ...]]]], aliases: Optional[Set[Union[str, Tuple[str, ...]]]],
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -161,8 +166,8 @@ class CommandGroup:
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
aliases: Optional[Set[Union[str, Tuple[str, ...]]]], aliases: Optional[Set[Union[str, Tuple[str, ...]]]],
parser: Optional[ArgumentParser] = ..., parser: Optional[ArgumentParser] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -175,8 +180,8 @@ class MatcherGroup:
*, *,
type: str = ..., type: str = ...,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -187,8 +192,8 @@ class MatcherGroup:
*, *,
type: str = ..., type: str = ...,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -198,7 +203,7 @@ class MatcherGroup:
self, self,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -208,8 +213,8 @@ class MatcherGroup:
self, self,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -219,7 +224,7 @@ class MatcherGroup:
self, self,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -229,7 +234,7 @@ class MatcherGroup:
self, self,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -241,8 +246,8 @@ class MatcherGroup:
*, *,
ignorecase: bool = ..., ignorecase: bool = ...,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -254,8 +259,8 @@ class MatcherGroup:
*, *,
ignorecase: bool = ..., ignorecase: bool = ...,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -266,8 +271,8 @@ class MatcherGroup:
keywords: Set[str], keywords: Set[str],
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -279,8 +284,8 @@ class MatcherGroup:
aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ..., aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ...,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -293,8 +298,8 @@ class MatcherGroup:
parser: Optional[ArgumentParser] = ..., parser: Optional[ArgumentParser] = ...,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
@ -306,8 +311,8 @@ class MatcherGroup:
flags: Union[int, re.RegexFlag] = ..., flags: Union[int, re.RegexFlag] = ...,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ...,
permission: Optional[Permission] = ..., permission: Optional[Union[Permission, T_PermissionChecker]] = ...,
handlers: Optional[List[Union[T_Handler, Handler]]] = ..., handlers: Optional[List[Union[T_Handler, Dependent]]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,

View File

@ -17,27 +17,17 @@ from argparse import Namespace
from contextlib import AsyncExitStack from contextlib import AsyncExitStack
from typing_extensions import TypedDict from typing_extensions import TypedDict
from argparse import ArgumentParser as ArgParser from argparse import ArgumentParser as ArgParser
from typing import ( from typing import Any, Set, List, Tuple, Union, NoReturn, Optional, Sequence
Any,
Dict,
List,
Type,
Tuple,
Union,
Callable,
NoReturn,
Optional,
Sequence,
)
from pygtrie import CharTrie from pygtrie import CharTrie
from nonebot.log import logger from nonebot.log import logger
from nonebot.handler import Handler from nonebot.utils import CacheDict
from nonebot import params, get_driver from nonebot import params, get_driver
from nonebot.typing import T_State, T_RuleChecker from nonebot.dependencies import Dependent
from nonebot.adapters import Bot, Event, MessageSegment from nonebot.adapters import Bot, Event, MessageSegment
from nonebot.exception import ParserExit, SkippedException from nonebot.exception import ParserExit, SkippedException
from nonebot.typing import T_State, T_Handler, T_RuleChecker
PREFIX_KEY = "_prefix" PREFIX_KEY = "_prefix"
SUFFIX_KEY = "_suffix" SUFFIX_KEY = "_suffix"
@ -74,23 +64,24 @@ class Rule:
__slots__ = ("checkers",) __slots__ = ("checkers",)
HANDLER_PARAM_TYPES = [ HANDLER_PARAM_TYPES = [
params.DependParam,
params.BotParam, params.BotParam,
params.EventParam, params.EventParam,
params.StateParam, params.StateParam,
params.DefaultParam, params.DefaultParam,
] ]
def __init__(self, *checkers: Union[T_RuleChecker, Handler]) -> None: def __init__(self, *checkers: Union[T_RuleChecker, Dependent[bool]]) -> None:
""" """
:参数: :参数:
* ``*checkers: Union[T_RuleChecker, Handler]``: RuleChecker * ``*checkers: Union[T_RuleChecker, Dependent[bool]]``: RuleChecker
""" """
self.checkers = set( self.checkers: Set[Dependent[bool]] = set(
checker checker
if isinstance(checker, Handler) if isinstance(checker, Dependent)
else Handler(checker, allow_types=self.HANDLER_PARAM_TYPES) else Dependent[bool](call=checker, allow_types=self.HANDLER_PARAM_TYPES)
for checker in checkers for checker in checkers
) )
""" """
@ -100,7 +91,7 @@ class Rule:
:类型: :类型:
* ``Set[Handler]`` * ``Set[Dependent[bool]]``
""" """
async def __call__( async def __call__(
@ -109,7 +100,7 @@ class Rule:
event: Event, event: Event,
state: T_State, state: T_State,
stack: Optional[AsyncExitStack] = None, stack: Optional[AsyncExitStack] = None,
dependency_cache: Optional[Dict[Callable[..., Any], Any]] = None, dependency_cache: Optional[CacheDict[T_Handler, Any]] = None,
) -> bool: ) -> bool:
""" """
:说明: :说明:
@ -122,7 +113,7 @@ class Rule:
* ``event: Event``: Event 对象 * ``event: Event``: Event 对象
* ``state: T_State``: 当前 State * ``state: T_State``: 当前 State
* ``stack: Optional[AsyncExitStack]``: 异步上下文栈 * ``stack: Optional[AsyncExitStack]``: 异步上下文栈
* ``dependency_cache: Optional[Dict[Callable[..., Any], Any]]``: 依赖缓存 * ``dependency_cache: Optional[CacheDict[T_Handler, Any]]``: 依赖缓存
:返回: :返回:
@ -137,8 +128,8 @@ class Rule:
bot=bot, bot=bot,
event=event, event=event,
state=state, state=state,
_stack=stack, stack=stack,
_dependency_cache=dependency_cache, dependency_cache=dependency_cache,
) )
for checker in self.checkers for checker in self.checkers
) )

View File

@ -28,9 +28,11 @@ from typing import (
NoReturn, NoReturn,
Optional, Optional,
Awaitable, Awaitable,
ForwardRef,
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from nonebot.utils import CacheDict
from nonebot.adapters import Bot, Event from nonebot.adapters import Bot, Event
from nonebot.permission import Permission from nonebot.permission import Permission
@ -53,14 +55,6 @@ T_State = Dict[Any, Any]
事件处理状态 State 类型 事件处理状态 State 类型
""" """
T_StateFactory = Callable[["Bot", "Event"], Awaitable[T_State]]
"""
:类型: ``Callable[[Bot, Event], Awaitable[T_State]]``
:说明:
事件处理状态 State 类工厂函数
"""
T_BotConnectionHook = Callable[["Bot"], Awaitable[None]] T_BotConnectionHook = Callable[["Bot"], Awaitable[None]]
""" """
@ -103,9 +97,11 @@ T_EventPreProcessor = Callable[..., Union[None, Awaitable[None]]]
:依赖参数: :依赖参数:
* ``DependParam``: 子依赖参数
* ``BotParam``: Bot 对象 * ``BotParam``: Bot 对象
* ``EventParam``: Event 对象 * ``EventParam``: Event 对象
* ``StateParam``: State 对象 * ``StateParam``: State 对象
* ``DefaultParam``: 带有默认值的参数
:说明: :说明:
@ -117,9 +113,11 @@ T_EventPostProcessor = Callable[..., Union[None, Awaitable[None]]]
:依赖参数: :依赖参数:
* ``DependParam``: 子依赖参数
* ``BotParam``: Bot 对象 * ``BotParam``: Bot 对象
* ``EventParam``: Event 对象 * ``EventParam``: Event 对象
* ``StateParam``: State 对象 * ``StateParam``: State 对象
* ``DefaultParam``: 带有默认值的参数
:说明: :说明:
@ -131,10 +129,12 @@ T_RunPreProcessor = Callable[..., Union[None, Awaitable[None]]]
:依赖参数: :依赖参数:
* ``DependParam``: 子依赖参数
* ``BotParam``: Bot 对象 * ``BotParam``: Bot 对象
* ``EventParam``: Event 对象 * ``EventParam``: Event 对象
* ``StateParam``: State 对象 * ``StateParam``: State 对象
* ``MatcherParam``: Matcher 对象 * ``MatcherParam``: Matcher 对象
* ``DefaultParam``: 带有默认值的参数
:说明: :说明:
@ -146,11 +146,13 @@ T_RunPostProcessor = Callable[..., Union[None, Awaitable[None]]]
:依赖参数: :依赖参数:
* ``DependParam``: 子依赖参数
* ``BotParam``: Bot 对象 * ``BotParam``: Bot 对象
* ``EventParam``: Event 对象 * ``EventParam``: Event 对象
* ``StateParam``: State 对象 * ``StateParam``: State 对象
* ``MatcherParam``: Matcher 对象 * ``MatcherParam``: Matcher 对象
* ``ExceptionParam``: 异常对象可能为 None * ``ExceptionParam``: 异常对象可能为 None
* ``DefaultParam``: 带有默认值的参数
:说明: :说明:
@ -163,9 +165,11 @@ T_RuleChecker = Callable[..., Union[bool, Awaitable[bool]]]
:依赖参数: :依赖参数:
* ``DependParam``: 子依赖参数
* ``BotParam``: Bot 对象 * ``BotParam``: Bot 对象
* ``EventParam``: Event 对象 * ``EventParam``: Event 对象
* ``StateParam``: State 对象 * ``StateParam``: State 对象
* ``DefaultParam``: 带有默认值的参数
:说明: :说明:
@ -177,8 +181,10 @@ T_PermissionChecker = Callable[..., Union[bool, Awaitable[bool]]]
:依赖参数: :依赖参数:
* ``DependParam``: 子依赖参数
* ``BotParam``: Bot 对象 * ``BotParam``: Bot 对象
* ``EventParam``: Event 对象 * ``EventParam``: Event 对象
* ``DefaultParam``: 带有默认值的参数
:说明: :说明:
@ -193,37 +199,52 @@ T_Handler = Callable[..., Any]
Handler 处理函数 Handler 处理函数
""" """
T_DependencyCache = Dict[T_Handler, Any] T_ArgsParser = Callable[..., Union[None, Awaitable[None]]]
""" """
:类型: ``Dict[T_Handler, Any]`` :类型: ``Callable[..., Union[None, Awaitable[None]]]``
:说明: :依赖参数:
依赖缓存, 用于存储依赖函数的返回值 * ``DependParam``: 子依赖参数
""" * ``BotParam``: Bot 对象
T_ArgsParser = Callable[ * ``EventParam``: Event 对象
["Bot", "Event", T_State], Union[Awaitable[None], Awaitable[NoReturn]] * ``StateParam``: State 对象
] * ``MatcherParam``: Matcher 对象
""" * ``DefaultParam``: 带有默认值的参数
:类型: ``Callable[[Bot, Event, T_State], Union[Awaitable[None], Awaitable[NoReturn]]]``
:说明: :说明:
ArgsParser 即消息参数解析函数 Matcher.got 获取参数时被运行 ArgsParser 即消息参数解析函数 Matcher.got 获取参数时被运行
""" """
T_TypeUpdater = Callable[["Bot", "Event", T_State, str], Awaitable[str]] T_TypeUpdater = Callable[..., Union[str, Awaitable[str]]]
""" """
:类型: ``Callable[[Bot, Event, T_State, str], Awaitable[str]]`` :类型: ``Callable[..., Union[None, Awaitable[None]]]``
:依赖参数:
* ``DependParam``: 子依赖参数
* ``BotParam``: Bot 对象
* ``EventParam``: Event 对象
* ``StateParam``: State 对象
* ``MatcherParam``: Matcher 对象
* ``DefaultParam``: 带有默认值的参数
:说明: :说明:
TypeUpdater Matcher.pause, Matcher.reject 时被运行用于更新响应的事件类型默认会更新为 ``message`` TypeUpdater Matcher.pause, Matcher.reject 时被运行用于更新响应的事件类型默认会更新为 ``message``
""" """
T_PermissionUpdater = Callable[ T_PermissionUpdater = Callable[..., Union["Permission", Awaitable["Permission"]]]
["Bot", "Event", T_State, "Permission"], Awaitable["Permission"]
]
""" """
:类型: ``Callable[[Bot, Event, T_State, Permission], Awaitable[Permission]]`` :类型: ``Callable[..., Union[Permission, Awaitable[Permission]]]``
:依赖参数:
* ``DependParam``: 子依赖参数
* ``BotParam``: Bot 对象
* ``EventParam``: Event 对象
* ``StateParam``: State 对象
* ``MatcherParam``: Matcher 对象
* ``DefaultParam``: 带有默认值的参数
:说明: :说明:

View File

@ -2,17 +2,17 @@ import re
import json import json
import asyncio import asyncio
import inspect import inspect
import collections
import dataclasses import dataclasses
from functools import wraps, partial from functools import wraps, partial
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from typing_extensions import ParamSpec, get_args, get_origin from typing_extensions import ParamSpec, get_args, get_origin
from typing import ( from typing import (
Any, Any,
Dict,
Type, Type,
Deque,
Tuple, Tuple,
Union, Union,
Generic,
TypeVar, TypeVar,
Callable, Callable,
Optional, Optional,
@ -27,6 +27,8 @@ from nonebot.typing import overrides
P = ParamSpec("P") P = ParamSpec("P")
R = TypeVar("R") R = TypeVar("R")
T = TypeVar("T") T = TypeVar("T")
K = TypeVar("K")
V = TypeVar("V")
def escape_tag(s: str) -> str: def escape_tag(s: str) -> str:
@ -133,77 +135,31 @@ def get_name(obj: Any) -> str:
return obj.__class__.__name__ return obj.__class__.__name__
class CacheLock: class CacheDict(Dict[K, V], Generic[K, V]):
def __init__(self): def __init__(self, *args, **kwargs):
self._waiters: Optional[Deque[asyncio.Future]] = None super(CacheDict, self).__init__(*args, **kwargs)
self._locked = False self._lock = asyncio.Lock()
@property
def locked(self):
return self._lock.locked()
def __repr__(self): def __repr__(self):
extra = "locked" if self._locked else "unlocked" extra = "locked" if self.locked else "unlocked"
if self._waiters:
extra = f"{extra}, waiters: {len(self._waiters)}"
return f"<{self.__class__.__name__} [{extra}]>" return f"<{self.__class__.__name__} [{extra}]>"
async def __aenter__(self): async def __aenter__(self) -> None:
await self.acquire() await self.acquire()
return None return None
async def __aexit__(self, exc_type, exc, tb): async def __aexit__(self, exc_type, exc, tb):
self.release() self.release()
def locked(self):
return self._locked
async def acquire(self): async def acquire(self):
if not self._locked and ( return await self._lock.acquire()
self._waiters is None or all(w.cancelled() for w in self._waiters)
):
self._locked = True
return True
if self._waiters is None:
self._waiters = collections.deque()
loop = asyncio.get_running_loop()
future = loop.create_future()
self._waiters.append(future)
# Finally block should be called before the CancelledError
# handling as we don't want CancelledError to call
# _wake_up_first() and attempt to wake up itself.
try:
try:
await future
finally:
self._waiters.remove(future)
except asyncio.CancelledError:
if not self._locked:
self._wake_up_first()
raise
self._locked = True
return True
def release(self): def release(self):
if self._locked: self._lock.release()
self._locked = False
self._wake_up_first()
else:
raise RuntimeError("Lock is not acquired.")
def _wake_up_first(self):
if not self._waiters:
return
try:
future = next(iter(self._waiters))
except StopIteration:
return
# .done() necessarily means that a waiter will wake up later on and
# either take the lock, or, if it was cancelled and lock wasn't
# taken already, will hit this again and wake up a new waiter.
if not future.done():
future.set_result(True)
class DataclassEncoder(json.JSONEncoder): class DataclassEncoder(json.JSONEncoder):

23
tests/plugins/depends.py Normal file
View File

@ -0,0 +1,23 @@
from nonebot import on_message
from nonebot.adapters import Event
from nonebot.params import Depends
test = on_message()
test2 = on_message()
runned = False
def dependency(event: Event):
# test cache
global runned
assert not runned
runned = True
return event
@test.handle()
@test2.handle()
async def handle(x: Event = Depends(dependency)):
# test dependency
return x

View File

@ -1,6 +1,12 @@
import os import os
import sys
from typing import TYPE_CHECKING, Set
import pytest import pytest
from utils import load_plugin
if TYPE_CHECKING:
from nonebot.plugin import Plugin
os.environ["CONFIG_FROM_ENV"] = "env" os.environ["CONFIG_FROM_ENV"] = "env"
@ -17,3 +23,14 @@ async def test_init(nonebug_init):
assert config.config_from_env == "env" assert config.config_from_env == "env"
assert config.config_from_init == "init" assert config.config_from_init == "init"
assert config.common_config == "common" assert config.common_config == "common"
@pytest.mark.asyncio
async def test_load_plugin(load_plugin: Set["Plugin"]):
import nonebot
assert nonebot.get_loaded_plugins() == load_plugin
plugin = nonebot.get_plugin("depends")
assert plugin
assert plugin.module_name == "plugins.depends"
assert "plugins.depends" in sys.modules

14
tests/utils.py Normal file
View File

@ -0,0 +1,14 @@
from pathlib import Path
from typing import TYPE_CHECKING, Set
import pytest
if TYPE_CHECKING:
from nonebot.plugin import Plugin
@pytest.fixture
def load_plugin(nonebug_init: None) -> Set["Plugin"]:
import nonebot
return nonebot.load_plugins(str(Path(__file__).parent / "plugins"))