diff --git a/nonebot/matcher.py b/nonebot/matcher.py index 762e891c..92fffbc1 100644 --- a/nonebot/matcher.py +++ b/nonebot/matcher.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- import typing +import inspect from functools import wraps from datetime import datetime from collections import defaultdict @@ -38,6 +39,13 @@ class Matcher: self.handlers = self.handlers.copy() self.state = self._default_state.copy() + def __repr__(self) -> str: + return (f"") + + def __str__(self) -> str: + return self.__repr__() + @classmethod def new(cls, type_: str = "", @@ -117,7 +125,7 @@ class Matcher: cls.handlers.append(_handler) def _decorator(func: Handler) -> Handler: - if cls.handlers[-1] is not func: + if not cls.handlers or cls.handlers[-1] is not func: cls.handlers.append(func) return func @@ -141,6 +149,8 @@ class Matcher: raise PausedException async def _key_parser(bot: Bot, event: Event, state: dict): + if key in state: + return parser = args_parser or cls._default_parser if parser: await parser(bot, event, state) @@ -151,8 +161,15 @@ class Matcher: cls.handlers.append(_key_parser) def _decorator(func: Handler) -> Handler: - if cls.handlers[-1] is not func: - cls.handlers.append(func) + if not hasattr(cls.handlers[-1], "__wrapped__"): + parser = cls.handlers.pop() + + @wraps(func) + async def wrapper(bot: Bot, event: Event, state: dict): + await parser(bot, event, state) + await func(bot, event, state) + + cls.handlers.append(wrapper) return func @@ -180,34 +197,35 @@ class Matcher: handler = self.handlers.pop(0) annotation = typing.get_type_hints(handler) BotType = annotation.get("bot") - if BotType and not isinstance(bot, BotType): + if BotType and inspect.isclass(BotType) and not isinstance( + bot, BotType): continue await handler(bot, event, self.state) except RejectedException: self.handlers.insert(0, handler) # type: ignore - matcher = Matcher.new( + Matcher.new( self.type, - self.rule, + Rule(), USER(event.user_id, perm=self.permission), # type:ignore self.handlers, temp=True, priority=0, + block=True, default_state=self.state, expire_time=datetime.now() + bot.config.session_expire_timeout) - matchers[0].append(matcher) return except PausedException: - matcher = Matcher.new( + Matcher.new( self.type, - self.rule, + Rule(), USER(event.user_id, perm=self.permission), # type:ignore self.handlers, temp=True, priority=0, + block=True, default_state=self.state, expire_time=datetime.now() + bot.config.session_expire_timeout) - matchers[0].append(matcher) return except FinishedException: return diff --git a/nonebot/message.py b/nonebot/message.py index d7963f00..0e883438 100644 --- a/nonebot/message.py +++ b/nonebot/message.py @@ -22,7 +22,7 @@ def event_preprocessor(func: PreProcessor) -> PreProcessor: async def _run_matcher(Matcher: Type[Matcher], bot: Bot, event: Event, state: dict) -> Union[None, NoReturn]: - if datetime.now() > Matcher.expire_time: + if Matcher.expire_time and datetime.now() > Matcher.expire_time: raise _ExceptionContainer([ExpiredException]) try: @@ -65,8 +65,7 @@ async def handle_event(bot: Bot, event: Event): return # Trie Match - if event.type == "message": - _, _ = TrieRule.get_value(bot, event, state) + _, _ = TrieRule.get_value(bot, event, state) break_flag = False for priority in sorted(matchers.keys()): diff --git a/nonebot/plugin.py b/nonebot/plugin.py index 63e06793..cefe7537 100644 --- a/nonebot/plugin.py +++ b/nonebot/plugin.py @@ -2,9 +2,10 @@ # -*- coding: utf-8 -*- import re +import sys import pkgutil import importlib -from importlib.util import module_from_spec +from importlib._bootstrap import _load from nonebot.log import logger from nonebot.matcher import Matcher @@ -185,9 +186,12 @@ def load_plugins(*plugin_dir: str) -> Set[Plugin]: if name.startswith("_"): continue + spec = module_info.module_finder.find_spec(name) + if spec.name in sys.modules: + continue + try: - spec = module_info.module_finder.find_spec(name) - module = module_from_spec(spec) + module = _load(spec) plugin = Plugin(name, module, _tmp_matchers.copy()) plugins[name] = plugin diff --git a/nonebot/rule.py b/nonebot/rule.py index c13e2f1d..a846748f 100644 --- a/nonebot/rule.py +++ b/nonebot/rule.py @@ -59,6 +59,11 @@ class TrieRule: @classmethod def get_value(cls, bot: Bot, event: Event, state: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]: + if event.type != "message": + state["_prefix"] = {} + state["_suffix"] = {} + return {}, {} + prefix = None suffix = None message = event.message[0] @@ -109,8 +114,12 @@ def command(command: Tuple[str]) -> Rule: config = get_driver().config command_start = config.command_start command_sep = config.command_sep - for start, sep in product(command_start, command_sep): - TrieRule.add_prefix(f"{start}{sep.join(command)}", command) + if len(command) == 1: + for start in command_start: + TrieRule.add_prefix(f"{start}{command[0]}", command) + else: + for start, sep in product(command_start, command_sep): + TrieRule.add_prefix(f"{start}{sep.join(command)}", command) async def _command(bot: Bot, event: Event, state: dict) -> bool: return command in state["_prefix"].values() diff --git a/package.json b/package.json index 571e6731..06e5231f 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,7 @@ "description": "An asynchronous QQ bot framework.", "homepage": "https://nonebot.cqp.moe/", "main": "index.js", - "contributors": [ - { + "contributors": [{ "name": "Richard Chien", "email": "richardchienthebest@gmail.com" }, diff --git a/tests/test_plugins/test_metaevent.py b/tests/test_plugins/test_metaevent.py index 93609139..f683716a 100644 --- a/tests/test_plugins/test_metaevent.py +++ b/tests/test_plugins/test_metaevent.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from nonebot.plugin import on_metaevent from nonebot.typing import Bot, Event +from nonebot.plugin import on_metaevent async def heartbeat(bot: Bot, event: Event, state: dict) -> bool: diff --git a/tests/test_plugins/test_package/test_command.py b/tests/test_plugins/test_package/test_command.py index 34501ecd..57551450 100644 --- a/tests/test_plugins/test_package/test_command.py +++ b/tests/test_plugins/test_package/test_command.py @@ -11,8 +11,8 @@ test_command = on_command("帮助", to_me()) @test_command.handle() async def test_handler(bot: Bot, event: Event, state: dict): - print("[!] Command:", state["_prefix"]) - args = str(event.message)[len(state["_prefix"]):].strip() + args = str(event.message)[len(list(state["_prefix"].keys())[0]):].strip() + print("[!] Command:", state["_prefix"], "Args:", args) if args: state["help"] = args else: