⚗️ add handler class

This commit is contained in:
yanyongyu
2021-03-18 19:16:18 +08:00
parent 62135dc117
commit 6bd12b7f2c
3 changed files with 208 additions and 92 deletions

View File

@ -2,9 +2,10 @@
事件响应器
==========
该模块实现事件响应器的创建与运行,并提供一些快捷方法来帮助用户更好的与机器人进行 对话 。
该模块实现事件响应器的创建与运行,并提供一些快捷方法来帮助用户更好的与机器人进行对话 。
"""
import sys
import inspect
from functools import wraps
from datetime import datetime
@ -14,6 +15,7 @@ from typing import Type, List, Dict, Union, Mapping, Iterable, Callable, Optiona
from nonebot.rule import Rule
from nonebot.log import logger
from nonebot.handler import Handler
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
@ -31,11 +33,21 @@ current_event: ContextVar = ContextVar("current_event")
class MatcherMeta(type):
if TYPE_CHECKING:
module: Optional[str]
type: str
rule: Rule
permission: Permission
handlers: List[T_Handler]
priority: int
block: bool
temp: bool
expire_time: Optional[datetime]
def __repr__(self) -> str:
return (f"<Matcher from {self.module or 'unknow'}, " # type: ignore
f"type={self.type}, priority={self.priority}, " # type: ignore
f"temp={self.temp}>") # type: ignore
return (f"<Matcher from {self.module or 'unknow'}, "
f"type={self.type}, priority={self.priority}, "
f"temp={self.temp}>")
def __str__(self) -> str:
return repr(self)
@ -64,9 +76,9 @@ class Matcher(metaclass=MatcherMeta):
:类型: ``Permission``
:说明: 事件响应器触发权限
"""
handlers: List[T_Handler] = []
handlers: List[Handler] = []
"""
:类型: ``List[T_Handler]``
:类型: ``List[Handler]``
:说明: 事件响应器拥有的事件处理函数列表
"""
priority: int = 1
@ -134,7 +146,7 @@ class Matcher(metaclass=MatcherMeta):
type_: str = "",
rule: Optional[Rule] = None,
permission: Optional[Permission] = None,
handlers: Optional[List[T_Handler]] = None,
handlers: Optional[List[Union[T_Handler, Handler]]] = None,
temp: bool = False,
priority: int = 1,
block: bool = False,
@ -178,7 +190,9 @@ class Matcher(metaclass=MatcherMeta):
"permission":
permission or Permission(),
"handlers": [
cls.process_handler(handler) for handler in handlers
handler
if isinstance(handler, Handler) else Handler(handler)
for handler in handlers
] if handlers else [],
"temp":
temp,
@ -284,27 +298,13 @@ class Matcher(metaclass=MatcherMeta):
cls._default_permission_updater = func
return func
@staticmethod
def process_handler(handler: T_Handler) -> T_Handler:
signature = inspect.signature(handler, follow_wrapped=False)
bot = signature.parameters.get("bot")
event = signature.parameters.get("event")
state = signature.parameters.get("state")
matcher = signature.parameters.get("matcher")
if not bot:
raise ValueError("Handler missing parameter 'bot'")
handler.__params__ = {
"bot": bot.annotation,
"event": event.annotation if event else None,
"state": T_State if state else None,
"matcher": matcher.annotation if matcher else None
}
return handler
@classmethod
def append_handler(cls, handler: T_Handler) -> None:
# Process handler first
cls.handlers.append(cls.process_handler(handler))
def append_handler(cls,
handler: T_Handler,
module: Optional[str] = None) -> Handler:
handler_ = Handler(handler, module)
cls.handlers.append(handler_)
return handler_
@classmethod
def handle(cls) -> Callable[[T_Handler], T_Handler]:
@ -319,6 +319,9 @@ class Matcher(metaclass=MatcherMeta):
"""
def _decorator(func: T_Handler) -> T_Handler:
print(
sys._getframe(1).f_code.co_filename,
sys._getframe(1).f_code.co_name)
cls.append_handler(func)
return func
@ -339,23 +342,17 @@ class Matcher(metaclass=MatcherMeta):
async def _receive(bot: "Bot", event: "Event") -> NoReturn:
raise PausedException
cls.process_handler(_receive)
if cls.handlers:
# 已有前置handlers则接受一条新的消息否则视为接收初始消息
cls.append_handler(_receive)
receive_handler = cls.append_handler(_receive)
else:
receive_handler = None
def _decorator(func: T_Handler) -> T_Handler:
cls.process_handler(func)
if not cls.handlers or cls.handlers[-1] is not func:
cls.append_handler(func)
_receive.__params__.update({
"bot":
func.__params__["bot"],
"event":
func.__params__["event"] or _receive.__params__["event"]
})
func_handler = cls.append_handler(func)
receive_handler.update_signature(bot=func_handler.bot_type,
event=func_handler.event_type)
return func
@ -416,42 +413,27 @@ class Matcher(metaclass=MatcherMeta):
else:
state[state["_current_key"]] = str(event.get_message())
cls.append_handler(_key_getter)
cls.append_handler(_key_parser)
getter_handler = cls.append_handler(_key_getter)
parser_handler = cls.append_handler(_key_parser)
def _decorator(func: T_Handler) -> T_Handler:
if not hasattr(cls.handlers[-1], "__wrapped__"):
cls.process_handler(func)
parser = cls.handlers.pop()
@wraps(func)
async def wrapper(bot: "Bot", event: "Event", state: T_State,
matcher: Matcher):
await matcher.run_handler(parser, bot, event, state)
await matcher.run_handler(func, bot, event, state)
await parser(matcher, bot, event, state)
await func_handler(matcher, bot, event, state)
if "_current_key" in state:
del state["_current_key"]
cls.append_handler(wrapper)
func_handler = cls.append_handler(wrapper)
wrapper.__params__.update({
"bot":
func.__params__["bot"],
"event":
func.__params__["event"] or wrapper.__params__["event"]
})
_key_getter.__params__.update({
"bot":
func.__params__["bot"],
"event":
func.__params__["event"] or wrapper.__params__["event"]
})
_key_parser.__params__.update({
"bot":
func.__params__["bot"],
"event":
func.__params__["event"] or wrapper.__params__["event"]
})
getter_handler.update_signature(bot=func_handler.bot_type,
event=func_handler.event_type)
parser_handler.update_signature(bot=func_handler.bot_type,
event=func_handler.event_type)
return func
@ -545,32 +527,6 @@ class Matcher(metaclass=MatcherMeta):
"""
self.block = True
async def run_handler(self, handler: T_Handler, bot: "Bot", event: "Event",
state: T_State):
if not hasattr(handler, "__params__"):
self.process_handler(handler)
params = getattr(handler, "__params__")
BotType = ((params["bot"] is not inspect.Parameter.empty) and
inspect.isclass(params["bot"]) and params["bot"])
if BotType and not isinstance(bot, BotType):
logger.debug(
f"Matcher {self} bot type {type(bot)} not match annotation {BotType}, ignored"
)
return
EventType = ((params["event"] is not inspect.Parameter.empty) and
inspect.isclass(params["event"]) and params["event"])
if EventType and not isinstance(event, EventType):
logger.debug(
f"Matcher {self} event type {type(event)} not match annotation {EventType}, ignored"
)
return
args = {"bot": bot, "event": event, "state": state, "matcher": self}
await handler(
**{k: v for k, v in args.items() if params[k] is not None})
# 运行handlers
async def run(self, bot: "Bot", event: "Event", state: T_State):
b_t = current_bot.set(bot)
@ -583,7 +539,7 @@ class Matcher(metaclass=MatcherMeta):
for _ in range(len(self.handlers)):
handler = self.handlers.pop(0)
await self.run_handler(handler, bot, event, state_)
await handler(self, bot, event, state_)
except RejectedException:
self.handlers.insert(0, handler) # type: ignore