mirror of
https://github.com/nonebot/nonebot2.git
synced 2024-11-24 00:55:07 +08:00
✨ Feature: 为事件响应器添加更多源码信息 (#2351)
This commit is contained in:
parent
3601a33f20
commit
c4716e3e17
@ -6,6 +6,7 @@ matchers = MatcherManager()
|
|||||||
|
|
||||||
from .matcher import Matcher as Matcher
|
from .matcher import Matcher as Matcher
|
||||||
from .matcher import current_bot as current_bot
|
from .matcher import current_bot as current_bot
|
||||||
|
from .matcher import MatcherSource as MatcherSource
|
||||||
from .matcher import current_event as current_event
|
from .matcher import current_event as current_event
|
||||||
from .matcher import current_handler as current_handler
|
from .matcher import current_handler as current_handler
|
||||||
from .matcher import current_matcher as current_matcher
|
from .matcher import current_matcher as current_matcher
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
|
import sys
|
||||||
|
import inspect
|
||||||
|
import warnings
|
||||||
|
from pathlib import Path
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
|
from dataclasses import dataclass
|
||||||
from contextvars import ContextVar
|
from contextvars import ContextVar
|
||||||
from typing_extensions import Self
|
from typing_extensions import Self
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
@ -20,6 +25,7 @@ from typing import (
|
|||||||
|
|
||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
from nonebot.internal.rule import Rule
|
from nonebot.internal.rule import Rule
|
||||||
|
from nonebot.utils import classproperty
|
||||||
from nonebot.dependencies import Dependent
|
from nonebot.dependencies import Dependent
|
||||||
from nonebot.internal.permission import User, Permission
|
from nonebot.internal.permission import User, Permission
|
||||||
from nonebot.internal.adapter import (
|
from nonebot.internal.adapter import (
|
||||||
@ -74,15 +80,51 @@ current_matcher: ContextVar["Matcher"] = ContextVar("current_matcher")
|
|||||||
current_handler: ContextVar[Dependent] = ContextVar("current_handler")
|
current_handler: ContextVar[Dependent] = ContextVar("current_handler")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MatcherSource:
|
||||||
|
"""Matcher 源代码上下文信息"""
|
||||||
|
|
||||||
|
plugin_name: Optional[str] = None
|
||||||
|
"""事件响应器所在插件名称"""
|
||||||
|
module_name: Optional[str] = None
|
||||||
|
"""事件响应器所在插件模块的路径名"""
|
||||||
|
lineno: Optional[int] = None
|
||||||
|
"""事件响应器所在行号"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def plugin(self) -> Optional["Plugin"]:
|
||||||
|
"""事件响应器所在插件"""
|
||||||
|
from nonebot.plugin import get_plugin
|
||||||
|
|
||||||
|
if self.plugin_name is not None:
|
||||||
|
return get_plugin(self.plugin_name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def module(self) -> Optional[ModuleType]:
|
||||||
|
if self.module_name is not None:
|
||||||
|
return sys.modules.get(self.module_name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def file(self) -> Optional[Path]:
|
||||||
|
if self.module is not None and (file := inspect.getsourcefile(self.module)):
|
||||||
|
return Path(file).absolute()
|
||||||
|
|
||||||
|
|
||||||
class MatcherMeta(type):
|
class MatcherMeta(type):
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
module_name: Optional[str]
|
|
||||||
type: str
|
type: str
|
||||||
|
_source: Optional[MatcherSource]
|
||||||
|
module_name: Optional[str]
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return (
|
return (
|
||||||
f"{self.__name__}(type={self.type!r}"
|
f"{self.__name__}(type={self.type!r}"
|
||||||
+ (f", module={self.module_name}" if self.module_name else "")
|
+ (f", module={self.module_name}" if self.module_name else "")
|
||||||
|
+ (
|
||||||
|
f", lineno={self._source.lineno}"
|
||||||
|
if self._source and self._source.lineno is not None
|
||||||
|
else ""
|
||||||
|
)
|
||||||
+ ")"
|
+ ")"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -90,14 +132,7 @@ class MatcherMeta(type):
|
|||||||
class Matcher(metaclass=MatcherMeta):
|
class Matcher(metaclass=MatcherMeta):
|
||||||
"""事件响应器类"""
|
"""事件响应器类"""
|
||||||
|
|
||||||
plugin: ClassVar[Optional["Plugin"]] = None
|
_source: ClassVar[Optional[MatcherSource]] = None
|
||||||
"""事件响应器所在插件"""
|
|
||||||
module: ClassVar[Optional[ModuleType]] = None
|
|
||||||
"""事件响应器所在插件模块"""
|
|
||||||
plugin_name: ClassVar[Optional[str]] = None
|
|
||||||
"""事件响应器所在插件名"""
|
|
||||||
module_name: ClassVar[Optional[str]] = None
|
|
||||||
"""事件响应器所在点分割插件模块路径"""
|
|
||||||
|
|
||||||
type: ClassVar[str] = ""
|
type: ClassVar[str] = ""
|
||||||
"""事件响应器类型"""
|
"""事件响应器类型"""
|
||||||
@ -142,6 +177,11 @@ class Matcher(metaclass=MatcherMeta):
|
|||||||
return (
|
return (
|
||||||
f"{self.__class__.__name__}(type={self.type!r}"
|
f"{self.__class__.__name__}(type={self.type!r}"
|
||||||
+ (f", module={self.module_name}" if self.module_name else "")
|
+ (f", module={self.module_name}" if self.module_name else "")
|
||||||
|
+ (
|
||||||
|
f", lineno={self._source.lineno}"
|
||||||
|
if self._source and self._source.lineno is not None
|
||||||
|
else ""
|
||||||
|
)
|
||||||
+ ")"
|
+ ")"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -158,6 +198,7 @@ class Matcher(metaclass=MatcherMeta):
|
|||||||
*,
|
*,
|
||||||
plugin: Optional["Plugin"] = None,
|
plugin: Optional["Plugin"] = None,
|
||||||
module: Optional[ModuleType] = None,
|
module: Optional[ModuleType] = None,
|
||||||
|
source: Optional[MatcherSource] = None,
|
||||||
expire_time: Optional[Union[datetime, timedelta]] = None,
|
expire_time: Optional[Union[datetime, timedelta]] = None,
|
||||||
default_state: Optional[T_State] = None,
|
default_state: Optional[T_State] = None,
|
||||||
default_type_updater: Optional[Union[T_TypeUpdater, Dependent[str]]] = None,
|
default_type_updater: Optional[Union[T_TypeUpdater, Dependent[str]]] = None,
|
||||||
@ -176,22 +217,47 @@ class Matcher(metaclass=MatcherMeta):
|
|||||||
temp: 是否为临时事件响应器,即触发一次后删除
|
temp: 是否为临时事件响应器,即触发一次后删除
|
||||||
priority: 响应优先级
|
priority: 响应优先级
|
||||||
block: 是否阻止事件向更低优先级的响应器传播
|
block: 是否阻止事件向更低优先级的响应器传播
|
||||||
plugin: 事件响应器所在插件
|
plugin: **Deprecated.** 事件响应器所在插件
|
||||||
module: 事件响应器所在模块
|
module: **Deprecated.** 事件响应器所在模块
|
||||||
default_state: 默认状态 `state`
|
source: 事件响应器源代码上下文信息
|
||||||
expire_time: 事件响应器最终有效时间点,过时即被删除
|
expire_time: 事件响应器最终有效时间点,过时即被删除
|
||||||
|
default_state: 默认状态 `state`
|
||||||
|
default_type_updater: 默认事件类型更新函数
|
||||||
|
default_permission_updater: 默认会话权限更新函数
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
Type[Matcher]: 新的事件响应器类
|
Type[Matcher]: 新的事件响应器类
|
||||||
"""
|
"""
|
||||||
|
if plugin is not None:
|
||||||
|
warnings.warn(
|
||||||
|
(
|
||||||
|
"Pass `plugin` context info to create Matcher is deprecated. "
|
||||||
|
"Use `source` instead."
|
||||||
|
),
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
|
if module is not None:
|
||||||
|
warnings.warn(
|
||||||
|
(
|
||||||
|
"Pass `module` context info to create Matcher is deprecated. "
|
||||||
|
"Use `source` instead."
|
||||||
|
),
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
|
source = source or (
|
||||||
|
MatcherSource(
|
||||||
|
plugin_name=plugin and plugin.name,
|
||||||
|
module_name=module and module.__name__,
|
||||||
|
)
|
||||||
|
if plugin is not None or module is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
NewMatcher = type(
|
NewMatcher = type(
|
||||||
cls.__name__,
|
cls.__name__,
|
||||||
(cls,),
|
(cls,),
|
||||||
{
|
{
|
||||||
"plugin": plugin,
|
"_source": source,
|
||||||
"module": module,
|
|
||||||
"plugin_name": plugin and plugin.name,
|
|
||||||
"module_name": module and module.__name__,
|
|
||||||
"type": type_,
|
"type": type_,
|
||||||
"rule": rule or Rule(),
|
"rule": rule or Rule(),
|
||||||
"permission": permission or Permission(),
|
"permission": permission or Permission(),
|
||||||
@ -253,6 +319,26 @@ class Matcher(metaclass=MatcherMeta):
|
|||||||
"""销毁当前的事件响应器"""
|
"""销毁当前的事件响应器"""
|
||||||
matchers[cls.priority].remove(cls)
|
matchers[cls.priority].remove(cls)
|
||||||
|
|
||||||
|
@classproperty
|
||||||
|
def plugin(cls) -> Optional["Plugin"]:
|
||||||
|
"""事件响应器所在插件"""
|
||||||
|
return cls._source and cls._source.plugin
|
||||||
|
|
||||||
|
@classproperty
|
||||||
|
def module(cls) -> Optional[ModuleType]:
|
||||||
|
"""事件响应器所在插件模块"""
|
||||||
|
return cls._source and cls._source.module
|
||||||
|
|
||||||
|
@classproperty
|
||||||
|
def plugin_name(cls) -> Optional[str]:
|
||||||
|
"""事件响应器所在插件名"""
|
||||||
|
return cls._source and cls._source.plugin_name
|
||||||
|
|
||||||
|
@classproperty
|
||||||
|
def module_name(cls) -> Optional[str]:
|
||||||
|
"""事件响应器所在插件模块路径"""
|
||||||
|
return cls._source and cls._source.module_name
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def check_perm(
|
async def check_perm(
|
||||||
cls,
|
cls,
|
||||||
@ -773,8 +859,7 @@ class Matcher(metaclass=MatcherMeta):
|
|||||||
temp=True,
|
temp=True,
|
||||||
priority=0,
|
priority=0,
|
||||||
block=True,
|
block=True,
|
||||||
plugin=self.plugin,
|
source=self.__class__._source,
|
||||||
module=self.module,
|
|
||||||
expire_time=bot.config.session_expire_timeout,
|
expire_time=bot.config.session_expire_timeout,
|
||||||
default_state=self.state,
|
default_state=self.state,
|
||||||
default_type_updater=self.__class__._default_type_updater,
|
default_type_updater=self.__class__._default_type_updater,
|
||||||
@ -794,8 +879,7 @@ class Matcher(metaclass=MatcherMeta):
|
|||||||
temp=True,
|
temp=True,
|
||||||
priority=0,
|
priority=0,
|
||||||
block=True,
|
block=True,
|
||||||
plugin=self.plugin,
|
source=self.__class__._source,
|
||||||
module=self.module,
|
|
||||||
expire_time=bot.config.session_expire_timeout,
|
expire_time=bot.config.session_expire_timeout,
|
||||||
default_state=self.state,
|
default_state=self.state,
|
||||||
default_type_updater=self.__class__._default_type_updater,
|
default_type_updater=self.__class__._default_type_updater,
|
||||||
|
@ -8,6 +8,7 @@ FrontMatter:
|
|||||||
from nonebot.internal.matcher import Matcher as Matcher
|
from nonebot.internal.matcher import Matcher as Matcher
|
||||||
from nonebot.internal.matcher import matchers as matchers
|
from nonebot.internal.matcher import matchers as matchers
|
||||||
from nonebot.internal.matcher import current_bot as current_bot
|
from nonebot.internal.matcher import current_bot as current_bot
|
||||||
|
from nonebot.internal.matcher import MatcherSource as MatcherSource
|
||||||
from nonebot.internal.matcher import current_event as current_event
|
from nonebot.internal.matcher import current_event as current_event
|
||||||
from nonebot.internal.matcher import MatcherManager as MatcherManager
|
from nonebot.internal.matcher import MatcherManager as MatcherManager
|
||||||
from nonebot.internal.matcher import MatcherProvider as MatcherProvider
|
from nonebot.internal.matcher import MatcherProvider as MatcherProvider
|
||||||
|
@ -7,14 +7,15 @@ FrontMatter:
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
import inspect
|
import inspect
|
||||||
|
import warnings
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from typing import Any, Set, Dict, List, Type, Tuple, Union, Optional
|
from typing import Any, Set, Dict, List, Type, Tuple, Union, Optional
|
||||||
|
|
||||||
from nonebot.adapters import Event
|
from nonebot.adapters import Event
|
||||||
from nonebot.matcher import Matcher
|
|
||||||
from nonebot.permission import Permission
|
from nonebot.permission import Permission
|
||||||
from nonebot.dependencies import Dependent
|
from nonebot.dependencies import Dependent
|
||||||
|
from nonebot.matcher import Matcher, MatcherSource
|
||||||
from nonebot.typing import T_State, T_Handler, T_RuleChecker, T_PermissionChecker
|
from nonebot.typing import T_State, T_Handler, T_RuleChecker, T_PermissionChecker
|
||||||
from nonebot.rule import (
|
from nonebot.rule import (
|
||||||
Rule,
|
Rule,
|
||||||
@ -45,25 +46,39 @@ def store_matcher(matcher: Type[Matcher]) -> None:
|
|||||||
plugin_chain[-1].matcher.add(matcher)
|
plugin_chain[-1].matcher.add(matcher)
|
||||||
|
|
||||||
|
|
||||||
def get_matcher_plugin(depth: int = 1) -> Optional[Plugin]:
|
def get_matcher_plugin(depth: int = 1) -> Optional[Plugin]: # pragma: no cover
|
||||||
"""获取事件响应器定义所在插件。
|
"""获取事件响应器定义所在插件。
|
||||||
|
|
||||||
|
**Deprecated**, 请使用 {ref}`nonebot.plugin.on.get_matcher_source` 获取信息。
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
depth: 调用栈深度
|
depth: 调用栈深度
|
||||||
"""
|
"""
|
||||||
# matcher defined when plugin loading
|
warnings.warn(
|
||||||
if plugin_chain := _current_plugin_chain.get():
|
"`get_matcher_plugin` is deprecated, please use `get_matcher_source` instead",
|
||||||
return plugin_chain[-1]
|
DeprecationWarning,
|
||||||
|
)
|
||||||
# matcher defined when plugin running
|
return (source := get_matcher_source(depth + 1)) and source.plugin
|
||||||
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]: # pragma: no cover
|
||||||
"""获取事件响应器定义所在模块。
|
"""获取事件响应器定义所在模块。
|
||||||
|
|
||||||
|
**Deprecated**, 请使用 {ref}`nonebot.plugin.on.get_matcher_source` 获取信息。
|
||||||
|
|
||||||
|
参数:
|
||||||
|
depth: 调用栈深度
|
||||||
|
"""
|
||||||
|
warnings.warn(
|
||||||
|
"`get_matcher_module` is deprecated, please use `get_matcher_source` instead",
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
|
return (source := get_matcher_source(depth + 1)) and source.module
|
||||||
|
|
||||||
|
|
||||||
|
def get_matcher_source(depth: int = 1) -> Optional[MatcherSource]:
|
||||||
|
"""获取事件响应器定义所在源码信息。
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
depth: 调用栈深度
|
depth: 调用栈深度
|
||||||
"""
|
"""
|
||||||
@ -71,7 +86,22 @@ def get_matcher_module(depth: int = 1) -> Optional[ModuleType]:
|
|||||||
if current_frame is None:
|
if current_frame is None:
|
||||||
return None
|
return None
|
||||||
frame = inspect.getouterframes(current_frame)[depth + 1].frame
|
frame = inspect.getouterframes(current_frame)[depth + 1].frame
|
||||||
return inspect.getmodule(frame)
|
|
||||||
|
module_name = (module := inspect.getmodule(frame)) and module.__name__
|
||||||
|
|
||||||
|
plugin: Optional["Plugin"] = None
|
||||||
|
# matcher defined when plugin loading
|
||||||
|
if plugin_chain := _current_plugin_chain.get():
|
||||||
|
plugin = plugin_chain[-1]
|
||||||
|
# matcher defined when plugin running
|
||||||
|
elif module_name:
|
||||||
|
plugin = get_plugin_by_module_name(module_name)
|
||||||
|
|
||||||
|
return MatcherSource(
|
||||||
|
plugin_name=plugin and plugin.name,
|
||||||
|
module_name=module_name,
|
||||||
|
lineno=frame.f_lineno,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def on(
|
def on(
|
||||||
@ -109,8 +139,7 @@ def on(
|
|||||||
priority=priority,
|
priority=priority,
|
||||||
block=block,
|
block=block,
|
||||||
handlers=handlers,
|
handlers=handlers,
|
||||||
plugin=get_matcher_plugin(_depth + 1),
|
source=get_matcher_source(_depth + 1),
|
||||||
module=get_matcher_module(_depth + 1),
|
|
||||||
default_state=state,
|
default_state=state,
|
||||||
)
|
)
|
||||||
store_matcher(matcher)
|
store_matcher(matcher)
|
||||||
|
@ -4,10 +4,10 @@ from types import ModuleType
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from nonebot.adapters import Event
|
from nonebot.adapters import Event
|
||||||
from nonebot.matcher import Matcher
|
|
||||||
from nonebot.permission import Permission
|
from nonebot.permission import Permission
|
||||||
from nonebot.dependencies import Dependent
|
from nonebot.dependencies import Dependent
|
||||||
from nonebot.rule import Rule, ArgumentParser
|
from nonebot.rule import Rule, ArgumentParser
|
||||||
|
from nonebot.matcher import Matcher, MatcherSource
|
||||||
from nonebot.typing import T_State, T_Handler, T_RuleChecker, T_PermissionChecker
|
from nonebot.typing import T_State, T_Handler, T_RuleChecker, T_PermissionChecker
|
||||||
|
|
||||||
from .plugin import Plugin
|
from .plugin import Plugin
|
||||||
@ -15,6 +15,7 @@ from .plugin import Plugin
|
|||||||
def store_matcher(matcher: type[Matcher]) -> None: ...
|
def store_matcher(matcher: type[Matcher]) -> None: ...
|
||||||
def get_matcher_plugin(depth: int = ...) -> Plugin | None: ...
|
def get_matcher_plugin(depth: int = ...) -> Plugin | None: ...
|
||||||
def get_matcher_module(depth: int = ...) -> ModuleType | None: ...
|
def get_matcher_module(depth: int = ...) -> ModuleType | None: ...
|
||||||
|
def get_matcher_source(depth: int = ...) -> MatcherSource | None: ...
|
||||||
def on(
|
def on(
|
||||||
type: str = "",
|
type: str = "",
|
||||||
rule: Rule | T_RuleChecker | None = ...,
|
rule: Rule | T_RuleChecker | None = ...,
|
||||||
|
@ -21,6 +21,7 @@ from typing import (
|
|||||||
Type,
|
Type,
|
||||||
Tuple,
|
Tuple,
|
||||||
Union,
|
Union,
|
||||||
|
Generic,
|
||||||
TypeVar,
|
TypeVar,
|
||||||
Callable,
|
Callable,
|
||||||
Optional,
|
Optional,
|
||||||
@ -220,6 +221,16 @@ def resolve_dot_notation(
|
|||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
|
class classproperty(Generic[T]):
|
||||||
|
"""类属性装饰器"""
|
||||||
|
|
||||||
|
def __init__(self, func: Callable[[Any], T]) -> None:
|
||||||
|
self.func = func
|
||||||
|
|
||||||
|
def __get__(self, instance: Any, owner: Optional[Type[Any]] = None) -> T:
|
||||||
|
return self.func(type(instance) if owner is None else owner)
|
||||||
|
|
||||||
|
|
||||||
class DataclassEncoder(json.JSONEncoder):
|
class DataclassEncoder(json.JSONEncoder):
|
||||||
"""可以序列化 {ref}`nonebot.adapters.Message`(List[Dataclass]) 的 `JSONEncoder`"""
|
"""可以序列化 {ref}`nonebot.adapters.Message`(List[Dataclass]) 的 `JSONEncoder`"""
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ exclude_lines =
|
|||||||
if (typing\.)?TYPE_CHECKING( is True)?:
|
if (typing\.)?TYPE_CHECKING( is True)?:
|
||||||
@(abc\.)?abstractmethod
|
@(abc\.)?abstractmethod
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
warnings\.warn
|
||||||
\.\.\.
|
\.\.\.
|
||||||
pass
|
pass
|
||||||
if __name__ == .__main__.:
|
if __name__ == .__main__.:
|
||||||
|
3
tests/plugins/matcher/matcher_info.py
Normal file
3
tests/plugins/matcher/matcher_info.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from nonebot import on
|
||||||
|
|
||||||
|
matcher = on("message", temp=False, expire_time=None, priority=1, block=True)
|
@ -1,12 +1,45 @@
|
|||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from nonebug import App
|
from nonebug import App
|
||||||
|
|
||||||
|
from nonebot import get_plugin
|
||||||
from nonebot.permission import User
|
from nonebot.permission import User
|
||||||
from nonebot.matcher import Matcher, matchers
|
from nonebot.matcher import Matcher, matchers
|
||||||
from utils import FakeMessage, make_fake_event
|
from utils import FakeMessage, make_fake_event
|
||||||
from nonebot.message import check_and_run_matcher
|
from nonebot.message import check_and_run_matcher
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_matcher_info(app: App):
|
||||||
|
from plugins.matcher.matcher_info import matcher
|
||||||
|
|
||||||
|
assert issubclass(matcher, Matcher)
|
||||||
|
assert matcher.type == "message"
|
||||||
|
assert matcher.priority == 1
|
||||||
|
assert matcher.temp is False
|
||||||
|
assert matcher.expire_time is None
|
||||||
|
assert matcher.block is True
|
||||||
|
|
||||||
|
assert matcher._source
|
||||||
|
|
||||||
|
assert matcher._source.module_name == "plugins.matcher.matcher_info"
|
||||||
|
assert matcher.module is sys.modules["plugins.matcher.matcher_info"]
|
||||||
|
assert matcher.module_name == "plugins.matcher.matcher_info"
|
||||||
|
|
||||||
|
assert matcher._source.plugin_name == "matcher_info"
|
||||||
|
assert matcher.plugin is get_plugin("matcher_info")
|
||||||
|
assert matcher.plugin_name == "matcher_info"
|
||||||
|
|
||||||
|
assert (
|
||||||
|
matcher._source.file
|
||||||
|
== (Path(__file__).parent.parent / "plugins/matcher/matcher_info.py").absolute()
|
||||||
|
)
|
||||||
|
|
||||||
|
assert matcher._source.lineno == 3
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_matcher_handle(app: App):
|
async def test_matcher_handle(app: App):
|
||||||
from plugins.matcher.matcher_process import test_handle
|
from plugins.matcher.matcher_process import test_handle
|
||||||
|
Loading…
Reference in New Issue
Block a user