diff --git a/nonebot/matcher.py b/nonebot/matcher.py index 0d552d9f..46884164 100644 --- a/nonebot/matcher.py +++ b/nonebot/matcher.py @@ -10,18 +10,18 @@ from types import ModuleType from datetime import datetime from contextvars import ContextVar from collections import defaultdict -from typing import (Any, Type, List, Dict, Union, Mapping, Iterable, Callable, - Optional, NoReturn, TYPE_CHECKING) +from typing import (TYPE_CHECKING, Any, Dict, List, Type, Union, Mapping, + Callable, Iterable, NoReturn, Optional) from nonebot.rule import Rule from nonebot.log import logger from nonebot.handler import Handler from nonebot.adapters import MessageTemplate -from nonebot.permission import Permission, USER -from nonebot.typing import (T_State, T_StateFactory, T_Handler, T_ArgsParser, - T_TypeUpdater, T_PermissionUpdater) -from nonebot.exception import (PausedException, RejectedException, - FinishedException, StopPropagation) +from nonebot.permission import USER, Permission +from nonebot.exception import (PausedException, StopPropagation, + FinishedException, RejectedException) +from nonebot.typing import (T_State, T_Handler, T_ArgsParser, T_TypeUpdater, + T_StateFactory, T_PermissionUpdater) if TYPE_CHECKING: from nonebot.adapters import Bot, Event, Message, MessageSegment @@ -31,8 +31,9 @@ matchers: Dict[int, List[Type["Matcher"]]] = defaultdict(list) :类型: ``Dict[int, List[Type[Matcher]]]`` :说明: 用于存储当前所有的事件响应器 """ -current_bot: ContextVar = ContextVar("current_bot") -current_event: ContextVar = 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") class MatcherMeta(type): @@ -421,7 +422,7 @@ class Matcher(metaclass=MatcherMeta): async def _key_getter(bot: "Bot", event: "Event", state: T_State): state["_current_key"] = key if key not in state: - if prompt: + if prompt is not None: if isinstance(prompt, MessageTemplate): _prompt = prompt.format(**state) else: @@ -472,8 +473,8 @@ class Matcher(metaclass=MatcherMeta): return _decorator @classmethod - async def send(cls, message: Union[str, "Message", "MessageSegment"], - **kwargs) -> Any: + async def send(cls, message: Union[str, "Message", "MessageSegment", + MessageTemplate], **kwargs) -> Any: """ :说明: @@ -484,14 +485,19 @@ class Matcher(metaclass=MatcherMeta): * ``message: Union[str, Message, MessageSegment]``: 消息内容 * ``**kwargs``: 其他传递给 ``bot.send`` 的参数,请参考对应 adapter 的 bot 对象 api """ - bot: "Bot" = current_bot.get() + bot = current_bot.get() event = current_event.get() - return await bot.send(event=event, message=message, **kwargs) + state = current_state.get() + if isinstance(message, MessageTemplate): + _message = message.format(**state) + else: + _message = message + return await bot.send(event=event, message=_message, **kwargs) @classmethod async def finish(cls, - message: Optional[Union[str, "Message", - "MessageSegment"]] = None, + message: Optional[Union[str, "Message", "MessageSegment", + MessageTemplate]] = None, **kwargs) -> NoReturn: """ :说明: @@ -505,14 +511,19 @@ class Matcher(metaclass=MatcherMeta): """ bot = current_bot.get() event = current_event.get() - if message is not None: - await bot.send(event=event, message=message, **kwargs) + state = current_state.get() + if isinstance(message, MessageTemplate): + _message = message.format(**state) + else: + _message = message + if _message is not None: + await bot.send(event=event, message=_message, **kwargs) raise FinishedException @classmethod async def pause(cls, - prompt: Optional[Union[str, "Message", - "MessageSegment"]] = None, + prompt: Optional[Union[str, "Message", "MessageSegment", + MessageTemplate]] = None, **kwargs) -> NoReturn: """ :说明: @@ -526,8 +537,13 @@ class Matcher(metaclass=MatcherMeta): """ bot = current_bot.get() event = current_event.get() - if prompt: - await bot.send(event=event, message=prompt, **kwargs) + state = current_state.get() + if isinstance(prompt, MessageTemplate): + _prompt = prompt.format(**state) + else: + _prompt = prompt + if _prompt is not None: + await bot.send(event=event, message=_prompt, **kwargs) raise PausedException @classmethod @@ -547,8 +563,13 @@ class Matcher(metaclass=MatcherMeta): """ bot = current_bot.get() event = current_event.get() - if prompt: - await bot.send(event=event, message=prompt, **kwargs) + state = current_state.get() + if isinstance(prompt, MessageTemplate): + _prompt = prompt.format(**state) + else: + _prompt = prompt + if _prompt is not None: + await bot.send(event=event, message=_prompt, **kwargs) raise RejectedException def stop_propagation(self): @@ -563,6 +584,7 @@ class Matcher(metaclass=MatcherMeta): 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) try: # Refresh preprocess state self.state = await self._default_state_factory( @@ -655,3 +677,4 @@ class Matcher(metaclass=MatcherMeta): logger.info(f"Matcher {self} running complete") current_bot.reset(b_t) current_event.reset(e_t) + current_state.reset(s_t) diff --git a/pages/changelog.md b/pages/changelog.md index cea08545..9d6def04 100644 --- a/pages/changelog.md +++ b/pages/changelog.md @@ -7,7 +7,7 @@ sidebar: auto ## v2.0.0a16 - 新增 `MessageFormatter` 可用于 `Message` 的模板生成 -- 新增 `matcher.got` 支持 `MessageFormatter` +- 新增 `matcher.got` `matcher.send` `matcher.pause` `matcher.reject` `matcher.finish` 支持 `MessageFormatter` - 移除 `matcher.got` 原本的 `state format` 支持,由 `MessageFormatter` template 替代 - `adapter` 基类拆分为单独文件 - 修复 `fastapi` Driver Websocket 未能正确提供请求头部 diff --git a/tests/.env.dev b/tests/.env.dev index b04033ea..d0aa5fd9 100644 --- a/tests/.env.dev +++ b/tests/.env.dev @@ -13,7 +13,7 @@ COMMAND_SEP=["/", "."] CUSTOM_CONFIG1=config in env CUSTOM_CONFIG3= -CQHTTP_WS_URLS={"123123123": "ws://127.0.0.1:6700/"} +# CQHTTP_WS_URLS={"123123123": "ws://127.0.0.1:6700/"} MIRAI_AUTH_KEY=12345678 MIRAI_HOST=127.0.0.1 diff --git a/tests/test_plugins/test_template.py b/tests/test_plugins/test_template.py new file mode 100644 index 00000000..a23c9589 --- /dev/null +++ b/tests/test_plugins/test_template.py @@ -0,0 +1,14 @@ +from nonebot import on_command +from nonebot.typing import T_State +from nonebot.adapters.cqhttp import Bot, MessageSegment, GroupMessageEvent + +template = on_command("template") + + +@template.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + state["at"] = MessageSegment.at(event.get_user_id()) + state["test"] = "test" + # message: /template {at} hello {test}! + ft = event.message.template(event.get_plaintext()) + await template.send(ft)