mirror of
https://github.com/nonebot/nonebot2.git
synced 2025-09-26 05:46:45 +00:00
✨ finish matcher process
This commit is contained in:
@ -3,6 +3,7 @@ from itertools import chain
|
||||
from typing import Any, Dict, List, Tuple, Callable, Optional, cast
|
||||
|
||||
from .models import Dependent
|
||||
from nonebot.log import logger
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters import Bot, Event
|
||||
from .models import Depends as DependsClass
|
||||
@ -70,7 +71,7 @@ def get_dependent(*,
|
||||
f"{dependent.event_param_name} / {param_name}")
|
||||
dependent.event_param_name = param_name
|
||||
dependent.event_param_type = generic_get_types(param.annotation)
|
||||
elif generic_check_issubclass(param.annotation, dict):
|
||||
elif generic_check_issubclass(param.annotation, Dict):
|
||||
if dependent.state_param_name is not None:
|
||||
raise ValueError(f"{func} has more than one State parameter: "
|
||||
f"{dependent.state_param_name} / {param_name}")
|
||||
@ -114,9 +115,15 @@ async def solve_dependencies(
|
||||
# check bot and event type
|
||||
if sub_dependent.bot_param_type and not isinstance(
|
||||
bot, sub_dependent.bot_param_type):
|
||||
logger.debug(
|
||||
f"Matcher {matcher} bot type {type(bot)} not match depends {func} "
|
||||
f"annotation {sub_dependent.bot_param_type}, ignored")
|
||||
return values, dependency_cache, True
|
||||
elif sub_dependent.event_param_type and not isinstance(
|
||||
event, sub_dependent.event_param_type):
|
||||
logger.debug(
|
||||
f"Matcher {matcher} event type {type(event)} not match depends {func} "
|
||||
f"annotation {sub_dependent.event_param_type}, ignored")
|
||||
return values, dependency_cache, True
|
||||
|
||||
# dependency overrides
|
||||
|
@ -8,6 +8,7 @@
|
||||
import asyncio
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Tuple, Callable, Optional
|
||||
|
||||
from nonebot.log import logger
|
||||
from .models import Depends, Dependent
|
||||
from nonebot.utils import get_name, run_sync
|
||||
from nonebot.typing import T_State, T_Handler
|
||||
@ -48,7 +49,18 @@ class Handler:
|
||||
self.dependency_overrides_provider = dependency_overrides_provider
|
||||
self.dependent = get_dependent(func=func)
|
||||
|
||||
async def __call__(self, matcher: "Matcher", bot: Bot, event: Event,
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"<Handler {self.func}("
|
||||
f"[bot {self.dependent.bot_param_name}]: {self.dependent.bot_param_type}, "
|
||||
f"[event {self.dependent.event_param_name}]: {self.dependent.event_param_type}, "
|
||||
f"[state {self.dependent.state_param_name}], "
|
||||
f"[matcher {self.dependent.matcher_param_name}])>")
|
||||
|
||||
def __str__(self) -> str:
|
||||
return repr(self)
|
||||
|
||||
async def __call__(self, matcher: "Matcher", bot: "Bot", event: "Event",
|
||||
state: T_State):
|
||||
values, _, ignored = await solve_dependencies(
|
||||
dependent=self.dependent,
|
||||
@ -68,9 +80,14 @@ class Handler:
|
||||
# check bot and event type
|
||||
if self.dependent.bot_param_type and not isinstance(
|
||||
bot, self.dependent.bot_param_type):
|
||||
logger.debug(f"Matcher {matcher} bot type {type(bot)} not match "
|
||||
f"annotation {self.dependent.bot_param_type}, ignored")
|
||||
return
|
||||
elif self.dependent.event_param_type and not isinstance(
|
||||
event, self.dependent.event_param_type):
|
||||
logger.debug(
|
||||
f"Matcher {matcher} event type {type(event)} not match "
|
||||
f"annotation {self.dependent.event_param_type}, ignored")
|
||||
return
|
||||
|
||||
if asyncio.iscoroutinefunction(self.func):
|
||||
|
@ -17,8 +17,9 @@ from .handler import Handler
|
||||
from nonebot.rule import Rule
|
||||
from nonebot import get_driver
|
||||
from nonebot.log import logger
|
||||
from nonebot.adapters import MessageTemplate
|
||||
from nonebot.permission import USER, Permission
|
||||
from nonebot.adapters import (Bot, Event, Message, MessageSegment,
|
||||
MessageTemplate)
|
||||
from nonebot.exception import (PausedException, StopPropagation,
|
||||
FinishedException, RejectedException)
|
||||
from nonebot.typing import (T_State, T_Handler, T_ArgsParser, T_TypeUpdater,
|
||||
@ -26,15 +27,14 @@ from nonebot.typing import (T_State, T_Handler, T_ArgsParser, T_TypeUpdater,
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from nonebot.plugin import Plugin
|
||||
from nonebot.adapters import Bot, Event, Message, MessageSegment
|
||||
|
||||
matchers: Dict[int, List[Type["Matcher"]]] = defaultdict(list)
|
||||
"""
|
||||
:类型: ``Dict[int, List[Type[Matcher]]]``
|
||||
:说明: 用于存储当前所有的事件响应器
|
||||
"""
|
||||
current_bot: ContextVar["Bot"] = ContextVar("current_bot")
|
||||
current_event: ContextVar["Event"] = ContextVar("current_event")
|
||||
current_bot: ContextVar[Bot] = ContextVar("current_bot")
|
||||
current_event: ContextVar[Event] = ContextVar("current_event")
|
||||
current_state: ContextVar[T_State] = ContextVar("current_state")
|
||||
|
||||
|
||||
@ -259,7 +259,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
return NewMatcher
|
||||
|
||||
@classmethod
|
||||
async def check_perm(cls, bot: "Bot", event: "Event") -> bool:
|
||||
async def check_perm(cls, bot: Bot, event: Event) -> bool:
|
||||
"""
|
||||
:说明:
|
||||
|
||||
@ -279,8 +279,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
await cls.permission(bot, event))
|
||||
|
||||
@classmethod
|
||||
async def check_rule(cls, bot: "Bot", event: "Event",
|
||||
state: T_State) -> bool:
|
||||
async def check_rule(cls, bot: Bot, event: Event, state: T_State) -> bool:
|
||||
"""
|
||||
:说明:
|
||||
|
||||
@ -383,18 +382,21 @@ class Matcher(metaclass=MatcherMeta):
|
||||
* 无
|
||||
"""
|
||||
|
||||
async def _receive(state: T_State) -> Union[None, NoReturn]:
|
||||
if state.get(_receive):
|
||||
return
|
||||
state[_receive] = True
|
||||
raise RejectedException
|
||||
|
||||
def _decorator(func: T_Handler) -> T_Handler:
|
||||
|
||||
async def _receive() -> NoReturn:
|
||||
func_handler.remove_dependency(depend)
|
||||
raise PausedException
|
||||
|
||||
depend = Depends(_receive)
|
||||
|
||||
if cls.handlers and cls.handlers[-1].func is func:
|
||||
func_handler = cls.handlers[-1]
|
||||
func_handler.prepend_dependency(depend)
|
||||
else:
|
||||
func_handler = cls.append_handler(
|
||||
cls.append_handler(
|
||||
func, dependencies=[depend] if cls.handlers else [])
|
||||
|
||||
return func
|
||||
@ -405,7 +407,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
def got(
|
||||
cls,
|
||||
key: str,
|
||||
prompt: Optional[Union[str, "Message", "MessageSegment",
|
||||
prompt: Optional[Union[str, Message, MessageSegment,
|
||||
MessageTemplate]] = None,
|
||||
args_parser: Optional[T_ArgsParser] = None
|
||||
) -> Callable[[T_Handler], T_Handler]:
|
||||
@ -421,32 +423,36 @@ class Matcher(metaclass=MatcherMeta):
|
||||
* ``args_parser: Optional[T_ArgsParser]``: 可选参数解析函数,空则使用默认解析函数
|
||||
"""
|
||||
|
||||
async def _key_getter(bot: Bot, event: Event, state: T_State):
|
||||
if state.get(f"_{key}_prompted"):
|
||||
return
|
||||
|
||||
state["_current_key"] = key
|
||||
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
|
||||
|
||||
parser = args_parser or cls._default_parser
|
||||
if parser:
|
||||
await parser(bot, event, state)
|
||||
else:
|
||||
state[key] = str(event.get_message())
|
||||
state[f"_{key}_parsed"] = True
|
||||
|
||||
def _decorator(func: T_Handler) -> T_Handler:
|
||||
|
||||
async def _key_getter(bot: "Bot", event: "Event", state: T_State):
|
||||
func_handler.remove_dependency(get_depend)
|
||||
state["_current_key"] = key
|
||||
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 PausedException
|
||||
else:
|
||||
state["_skip_key"] = True
|
||||
|
||||
async def _key_parser(bot: "Bot", event: "Event", state: T_State):
|
||||
if key in state and state.get("_skip_key"):
|
||||
del state["_skip_key"]
|
||||
return
|
||||
parser = args_parser or cls._default_parser
|
||||
if parser:
|
||||
await parser(bot, event, state)
|
||||
else:
|
||||
state[state["_current_key"]] = str(event.get_message())
|
||||
|
||||
get_depend = Depends(_key_getter)
|
||||
parser_depend = Depends(_key_parser)
|
||||
|
||||
@ -455,15 +461,15 @@ class Matcher(metaclass=MatcherMeta):
|
||||
func_handler.prepend_dependency(parser_depend)
|
||||
func_handler.prepend_dependency(get_depend)
|
||||
else:
|
||||
func_handler = cls.append_handler(
|
||||
func, dependencies=[get_depend, parser_depend])
|
||||
cls.append_handler(func,
|
||||
dependencies=[get_depend, parser_depend])
|
||||
|
||||
return func
|
||||
|
||||
return _decorator
|
||||
|
||||
@classmethod
|
||||
async def send(cls, message: Union[str, "Message", "MessageSegment",
|
||||
async def send(cls, message: Union[str, Message, MessageSegment,
|
||||
MessageTemplate], **kwargs) -> Any:
|
||||
"""
|
||||
:说明:
|
||||
@ -486,7 +492,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
|
||||
@classmethod
|
||||
async def finish(cls,
|
||||
message: Optional[Union[str, "Message", "MessageSegment",
|
||||
message: Optional[Union[str, Message, MessageSegment,
|
||||
MessageTemplate]] = None,
|
||||
**kwargs) -> NoReturn:
|
||||
"""
|
||||
@ -512,7 +518,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
|
||||
@classmethod
|
||||
async def pause(cls,
|
||||
prompt: Optional[Union[str, "Message", "MessageSegment",
|
||||
prompt: Optional[Union[str, Message, MessageSegment,
|
||||
MessageTemplate]] = None,
|
||||
**kwargs) -> NoReturn:
|
||||
"""
|
||||
@ -538,8 +544,8 @@ class Matcher(metaclass=MatcherMeta):
|
||||
|
||||
@classmethod
|
||||
async def reject(cls,
|
||||
prompt: Optional[Union[str, "Message",
|
||||
"MessageSegment"]] = None,
|
||||
prompt: Optional[Union[str, Message,
|
||||
MessageSegment]] = None,
|
||||
**kwargs) -> NoReturn:
|
||||
"""
|
||||
:说明:
|
||||
@ -554,6 +560,8 @@ class Matcher(metaclass=MatcherMeta):
|
||||
bot = current_bot.get()
|
||||
event = current_event.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):
|
||||
_prompt = prompt.format(**state)
|
||||
else:
|
||||
@ -571,7 +579,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
self.block = True
|
||||
|
||||
# 运行handlers
|
||||
async def run(self, bot: "Bot", event: "Event", state: T_State):
|
||||
async def run(self, bot: Bot, event: Event, state: T_State):
|
||||
b_t = current_bot.set(bot)
|
||||
e_t = current_event.set(event)
|
||||
s_t = current_state.set(self.state)
|
||||
|
@ -1,8 +1,9 @@
|
||||
import inspect
|
||||
from typing import Any, Dict, Type, Tuple, Union, Callable
|
||||
from typing_extensions import GenericAlias, get_args, get_origin # type: ignore
|
||||
|
||||
from pydantic.typing import (ForwardRef, get_args, get_origin,
|
||||
evaluate_forwardref)
|
||||
from loguru import logger
|
||||
from pydantic.typing import ForwardRef, evaluate_forwardref
|
||||
|
||||
|
||||
def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
|
||||
@ -25,7 +26,13 @@ def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str,
|
||||
annotation = param.annotation
|
||||
if isinstance(annotation, str):
|
||||
annotation = ForwardRef(annotation)
|
||||
annotation = evaluate_forwardref(annotation, globalns, globalns)
|
||||
try:
|
||||
annotation = evaluate_forwardref(annotation, globalns, globalns)
|
||||
except Exception as e:
|
||||
logger.opt(colors=True, exception=e).warning(
|
||||
f"Unknown ForwardRef[\"{param.annotation}\"] for parameter {param.name}"
|
||||
)
|
||||
return inspect.Parameter.empty
|
||||
return annotation
|
||||
|
||||
|
||||
@ -33,13 +40,16 @@ def generic_check_issubclass(
|
||||
cls: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any],
|
||||
...]]) -> bool:
|
||||
try:
|
||||
return isinstance(cls, type) and issubclass(cls, class_or_tuple)
|
||||
return issubclass(cls, class_or_tuple)
|
||||
except TypeError:
|
||||
if get_origin(cls) is Union:
|
||||
for type_ in get_args(cls):
|
||||
if not generic_check_issubclass(type_, class_or_tuple):
|
||||
return False
|
||||
return True
|
||||
elif isinstance(cls, GenericAlias):
|
||||
origin = get_origin(cls)
|
||||
return bool(origin and issubclass(origin, class_or_tuple))
|
||||
raise
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user