mirror of
https://github.com/nonebot/nonebot2.git
synced 2024-11-27 18:45:05 +08:00
🐛 detect runtime plugin (#1857)
This commit is contained in:
parent
17c86f7da2
commit
2a2f7b6dce
@ -28,13 +28,26 @@ from nonebot.rule import (
|
|||||||
shell_command,
|
shell_command,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from .plugin import Plugin
|
||||||
|
from . import get_plugin_by_module_name
|
||||||
from .manager import _current_plugin_chain
|
from .manager import _current_plugin_chain
|
||||||
|
|
||||||
|
|
||||||
def _store_matcher(matcher: Type[Matcher]) -> None:
|
def _store_matcher(matcher: Type[Matcher]) -> None:
|
||||||
# only store the matcher defined in the plugin
|
# only store the matcher defined when plugin loading
|
||||||
if plugins := _current_plugin_chain.get():
|
if plugin_chain := _current_plugin_chain.get():
|
||||||
plugins[-1].matcher.add(matcher)
|
plugin_chain[-1].matcher.add(matcher)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_matcher_plugin(depth: int = 1) -> Optional[Plugin]:
|
||||||
|
# matcher defined when plugin loading
|
||||||
|
if plugin_chain := _current_plugin_chain.get():
|
||||||
|
return plugin_chain[-1]
|
||||||
|
|
||||||
|
# matcher defined when plugin running
|
||||||
|
if module := _get_matcher_module(depth + 1):
|
||||||
|
if plugin := get_plugin_by_module_name(module.__name__):
|
||||||
|
return plugin
|
||||||
|
|
||||||
|
|
||||||
def _get_matcher_module(depth: int = 1) -> Optional[ModuleType]:
|
def _get_matcher_module(depth: int = 1) -> Optional[ModuleType]:
|
||||||
@ -71,7 +84,6 @@ def on(
|
|||||||
block: 是否阻止事件向更低优先级传递
|
block: 是否阻止事件向更低优先级传递
|
||||||
state: 默认 state
|
state: 默认 state
|
||||||
"""
|
"""
|
||||||
plugin_chain = _current_plugin_chain.get()
|
|
||||||
matcher = Matcher.new(
|
matcher = Matcher.new(
|
||||||
type,
|
type,
|
||||||
Rule() & rule,
|
Rule() & rule,
|
||||||
@ -81,7 +93,7 @@ def on(
|
|||||||
priority=priority,
|
priority=priority,
|
||||||
block=block,
|
block=block,
|
||||||
handlers=handlers,
|
handlers=handlers,
|
||||||
plugin=plugin_chain[-1] if plugin_chain else None,
|
plugin=_get_matcher_plugin(_depth + 1),
|
||||||
module=_get_matcher_module(_depth + 1),
|
module=_get_matcher_module(_depth + 1),
|
||||||
default_state=state,
|
default_state=state,
|
||||||
)
|
)
|
||||||
|
@ -47,7 +47,7 @@ class Plugin:
|
|||||||
manager: "PluginManager"
|
manager: "PluginManager"
|
||||||
"""导入该插件的插件管理器"""
|
"""导入该插件的插件管理器"""
|
||||||
matcher: Set[Type[Matcher]] = field(default_factory=set)
|
matcher: Set[Type[Matcher]] = field(default_factory=set)
|
||||||
"""插件内定义的 `Matcher`"""
|
"""插件加载时定义的 `Matcher`"""
|
||||||
parent_plugin: Optional["Plugin"] = None
|
parent_plugin: Optional["Plugin"] = None
|
||||||
"""父插件"""
|
"""父插件"""
|
||||||
sub_plugins: Set["Plugin"] = field(default_factory=set)
|
sub_plugins: Set["Plugin"] = field(default_factory=set)
|
||||||
|
@ -90,3 +90,6 @@ async def overload(event: FakeEvent):
|
|||||||
@test_overload.handle()
|
@test_overload.handle()
|
||||||
async def finish():
|
async def finish():
|
||||||
await test_overload.finish()
|
await test_overload.finish()
|
||||||
|
|
||||||
|
|
||||||
|
test_destroy = on_message()
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
from typing import Type
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
from nonebot.adapters import Event
|
from nonebot.adapters import Event
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
from nonebot import (
|
from nonebot import (
|
||||||
CommandGroup,
|
CommandGroup,
|
||||||
MatcherGroup,
|
MatcherGroup,
|
||||||
@ -50,6 +52,20 @@ matcher_on = on(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def matcher_on_factory() -> Type[Matcher]:
|
||||||
|
return on(
|
||||||
|
"test",
|
||||||
|
rule=rule,
|
||||||
|
permission=permission,
|
||||||
|
handlers=[handler],
|
||||||
|
temp=True,
|
||||||
|
expire_time=expire_time,
|
||||||
|
priority=priority,
|
||||||
|
block=True,
|
||||||
|
state=state,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
matcher_on_metaevent = on_metaevent(
|
matcher_on_metaevent = on_metaevent(
|
||||||
rule=rule,
|
rule=rule,
|
||||||
handlers=[handler],
|
handlers=[handler],
|
||||||
|
@ -79,6 +79,20 @@ async def test_matcher(app: App):
|
|||||||
ctx.should_finished()
|
ctx.should_finished()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_matcher_destroy(app: App):
|
||||||
|
from plugins.matcher.matcher_process import test_destroy
|
||||||
|
|
||||||
|
async with app.test_matcher(test_destroy) as ctx:
|
||||||
|
assert len(matchers) == 1
|
||||||
|
assert len(matchers[test_destroy.priority]) == 1
|
||||||
|
assert matchers[test_destroy.priority][0] is test_destroy
|
||||||
|
|
||||||
|
test_destroy.destroy()
|
||||||
|
|
||||||
|
assert len(matchers[test_destroy.priority]) == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_type_updater(app: App):
|
async def test_type_updater(app: App):
|
||||||
from plugins.matcher.matcher_type import test_type_updater, test_custom_updater
|
from plugins.matcher.matcher_type import test_type_updater, test_custom_updater
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
from typing import Type, Optional
|
from typing import Type, Callable, Optional
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import nonebot
|
import nonebot
|
||||||
|
from nonebot.adapters import Event
|
||||||
from nonebot.typing import T_RuleChecker
|
from nonebot.typing import T_RuleChecker
|
||||||
from nonebot.matcher import Matcher, matchers
|
from nonebot.matcher import Matcher, matchers
|
||||||
from nonebot.rule import (
|
from nonebot.rule import (
|
||||||
@ -18,7 +19,74 @@ from nonebot.rule import (
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_on():
|
@pytest.mark.parametrize(
|
||||||
|
"matcher_name, pre_rule_factory, has_permission",
|
||||||
|
[
|
||||||
|
pytest.param("matcher_on", None, True),
|
||||||
|
pytest.param("matcher_on_metaevent", None, False),
|
||||||
|
pytest.param("matcher_on_message", None, True),
|
||||||
|
pytest.param("matcher_on_notice", None, False),
|
||||||
|
pytest.param("matcher_on_request", None, False),
|
||||||
|
pytest.param(
|
||||||
|
"matcher_on_startswith", lambda e: StartswithRule(("test",)), True
|
||||||
|
),
|
||||||
|
pytest.param("matcher_on_endswith", lambda e: EndswithRule(("test",)), True),
|
||||||
|
pytest.param("matcher_on_fullmatch", lambda e: FullmatchRule(("test",)), True),
|
||||||
|
pytest.param("matcher_on_keyword", lambda e: KeywordsRule("test"), True),
|
||||||
|
pytest.param("matcher_on_command", lambda e: CommandRule([("test",)]), True),
|
||||||
|
pytest.param(
|
||||||
|
"matcher_on_shell_command",
|
||||||
|
lambda e: ShellCommandRule([("test",)], None),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
pytest.param("matcher_on_regex", lambda e: RegexRule("test"), True),
|
||||||
|
pytest.param("matcher_on_type", lambda e: IsTypeRule(e), True),
|
||||||
|
pytest.param("matcher_sub_cmd", lambda e: CommandRule([("test", "sub")]), True),
|
||||||
|
pytest.param(
|
||||||
|
"matcher_sub_shell_cmd",
|
||||||
|
lambda e: ShellCommandRule([("test", "sub")], None),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
pytest.param("matcher_group_on", None, True),
|
||||||
|
pytest.param("matcher_group_on_metaevent", None, False),
|
||||||
|
pytest.param("matcher_group_on_message", None, True),
|
||||||
|
pytest.param("matcher_group_on_notice", None, False),
|
||||||
|
pytest.param("matcher_group_on_request", None, False),
|
||||||
|
pytest.param(
|
||||||
|
"matcher_group_on_startswith",
|
||||||
|
lambda e: StartswithRule(("test",)),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"matcher_group_on_endswith",
|
||||||
|
lambda e: EndswithRule(("test",)),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"matcher_group_on_fullmatch",
|
||||||
|
lambda e: FullmatchRule(("test",)),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
pytest.param("matcher_group_on_keyword", lambda e: KeywordsRule("test"), True),
|
||||||
|
pytest.param(
|
||||||
|
"matcher_group_on_command",
|
||||||
|
lambda e: CommandRule([("test",)]),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"matcher_group_on_shell_command",
|
||||||
|
lambda e: ShellCommandRule([("test",)], None),
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
pytest.param("matcher_group_on_regex", lambda e: RegexRule("test"), True),
|
||||||
|
pytest.param("matcher_group_on_type", lambda e: IsTypeRule(e), True),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_on(
|
||||||
|
matcher_name: str,
|
||||||
|
pre_rule_factory: Optional[Callable[[Type[Event]], T_RuleChecker]],
|
||||||
|
has_permission: bool,
|
||||||
|
):
|
||||||
import plugins.plugin.matchers as module
|
import plugins.plugin.matchers as module
|
||||||
from plugins.plugin.matchers import (
|
from plugins.plugin.matchers import (
|
||||||
TestEvent,
|
TestEvent,
|
||||||
@ -26,91 +94,56 @@ async def test_on():
|
|||||||
state,
|
state,
|
||||||
handler,
|
handler,
|
||||||
priority,
|
priority,
|
||||||
matcher_on,
|
|
||||||
permission,
|
permission,
|
||||||
expire_time,
|
expire_time,
|
||||||
matcher_on_type,
|
|
||||||
matcher_sub_cmd,
|
|
||||||
matcher_group_on,
|
|
||||||
matcher_on_regex,
|
|
||||||
matcher_on_notice,
|
|
||||||
matcher_on_command,
|
|
||||||
matcher_on_keyword,
|
|
||||||
matcher_on_message,
|
|
||||||
matcher_on_request,
|
|
||||||
matcher_on_endswith,
|
|
||||||
matcher_on_fullmatch,
|
|
||||||
matcher_on_metaevent,
|
|
||||||
matcher_group_on_type,
|
|
||||||
matcher_on_startswith,
|
|
||||||
matcher_sub_shell_cmd,
|
|
||||||
matcher_group_on_regex,
|
|
||||||
matcher_group_on_notice,
|
|
||||||
matcher_group_on_command,
|
|
||||||
matcher_group_on_keyword,
|
|
||||||
matcher_group_on_message,
|
|
||||||
matcher_group_on_request,
|
|
||||||
matcher_on_shell_command,
|
|
||||||
matcher_group_on_endswith,
|
|
||||||
matcher_group_on_fullmatch,
|
|
||||||
matcher_group_on_metaevent,
|
|
||||||
matcher_group_on_startswith,
|
|
||||||
matcher_group_on_shell_command,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
matcher = getattr(module, matcher_name)
|
||||||
|
assert issubclass(matcher, Matcher), f"{matcher_name} should be a Matcher"
|
||||||
|
|
||||||
|
pre_rule = pre_rule_factory(TestEvent) if pre_rule_factory else None
|
||||||
|
|
||||||
plugin = nonebot.get_plugin("plugin")
|
plugin = nonebot.get_plugin("plugin")
|
||||||
|
assert plugin, "plugin should be loaded"
|
||||||
|
|
||||||
def _check(
|
assert {dependent.call for dependent in matcher.rule.checkers} == (
|
||||||
matcher: Type[Matcher],
|
{pre_rule, rule} if pre_rule else {rule}
|
||||||
pre_rule: Optional[T_RuleChecker],
|
)
|
||||||
has_permission: bool,
|
if has_permission:
|
||||||
):
|
assert {dependent.call for dependent in matcher.permission.checkers} == {
|
||||||
assert {dependent.call for dependent in matcher.rule.checkers} == (
|
permission
|
||||||
{pre_rule, rule} if pre_rule else {rule}
|
}
|
||||||
)
|
else:
|
||||||
if has_permission:
|
assert not matcher.permission.checkers
|
||||||
assert {dependent.call for dependent in matcher.permission.checkers} == {
|
assert [dependent.call for dependent in matcher.handlers] == [handler]
|
||||||
permission
|
assert matcher.temp is True
|
||||||
}
|
assert matcher.expire_time == expire_time
|
||||||
else:
|
assert matcher in matchers[priority]
|
||||||
assert not matcher.permission.checkers
|
assert matcher.block is True
|
||||||
assert [dependent.call for dependent in matcher.handlers] == [handler]
|
assert matcher._default_state == state
|
||||||
assert matcher.temp is True
|
|
||||||
assert matcher.expire_time == expire_time
|
|
||||||
assert matcher in matchers[priority]
|
|
||||||
assert matcher.block is True
|
|
||||||
assert matcher._default_state == state
|
|
||||||
|
|
||||||
|
assert matcher.plugin is plugin
|
||||||
|
assert matcher in plugin.matcher
|
||||||
|
assert matcher.module is module
|
||||||
|
assert matcher.plugin_name == "plugin"
|
||||||
|
assert matcher.module_name == "plugins.plugin.matchers"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_runtime_on():
|
||||||
|
import plugins.plugin.matchers as module
|
||||||
|
from plugins.plugin.matchers import matcher_on_factory
|
||||||
|
|
||||||
|
matcher = matcher_on_factory()
|
||||||
|
|
||||||
|
plugin = nonebot.get_plugin("plugin")
|
||||||
|
assert plugin, "plugin should be loaded"
|
||||||
|
|
||||||
|
try:
|
||||||
assert matcher.plugin is plugin
|
assert matcher.plugin is plugin
|
||||||
|
assert matcher not in plugin.matcher
|
||||||
assert matcher.module is module
|
assert matcher.module is module
|
||||||
assert matcher.plugin_name == "plugin"
|
assert matcher.plugin_name == "plugin"
|
||||||
assert matcher.module_name == "plugins.plugin.matchers"
|
assert matcher.module_name == "plugins.plugin.matchers"
|
||||||
|
finally:
|
||||||
_check(matcher_on, None, True)
|
matcher.destroy()
|
||||||
_check(matcher_on_metaevent, None, False)
|
|
||||||
_check(matcher_on_message, None, True)
|
|
||||||
_check(matcher_on_notice, None, False)
|
|
||||||
_check(matcher_on_request, None, False)
|
|
||||||
_check(matcher_on_startswith, StartswithRule(("test",)), True)
|
|
||||||
_check(matcher_on_endswith, EndswithRule(("test",)), True)
|
|
||||||
_check(matcher_on_fullmatch, FullmatchRule(("test",)), True)
|
|
||||||
_check(matcher_on_keyword, KeywordsRule("test"), True)
|
|
||||||
_check(matcher_on_command, CommandRule([("test",)]), True)
|
|
||||||
_check(matcher_on_shell_command, ShellCommandRule([("test",)], None), True)
|
|
||||||
_check(matcher_on_regex, RegexRule("test"), True)
|
|
||||||
_check(matcher_on_type, IsTypeRule(TestEvent), True)
|
|
||||||
_check(matcher_sub_cmd, CommandRule([("test", "sub")]), True)
|
|
||||||
_check(matcher_sub_shell_cmd, ShellCommandRule([("test", "sub")], None), True)
|
|
||||||
_check(matcher_group_on, None, True)
|
|
||||||
_check(matcher_group_on_metaevent, None, False)
|
|
||||||
_check(matcher_group_on_message, None, True)
|
|
||||||
_check(matcher_group_on_notice, None, False)
|
|
||||||
_check(matcher_group_on_request, None, False)
|
|
||||||
_check(matcher_group_on_startswith, StartswithRule(("test",)), True)
|
|
||||||
_check(matcher_group_on_endswith, EndswithRule(("test",)), True)
|
|
||||||
_check(matcher_group_on_fullmatch, FullmatchRule(("test",)), True)
|
|
||||||
_check(matcher_group_on_keyword, KeywordsRule("test"), True)
|
|
||||||
_check(matcher_group_on_command, CommandRule([("test",)]), True)
|
|
||||||
_check(matcher_group_on_shell_command, ShellCommandRule([("test",)], None), True)
|
|
||||||
_check(matcher_group_on_regex, RegexRule("test"), True)
|
|
||||||
_check(matcher_group_on_type, IsTypeRule(TestEvent), True)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user