mirror of
https://github.com/nonebot/nonebot2.git
synced 2024-11-24 09:05:04 +08:00
🔇 Feature: 调整日志输出格式与等级 (#1233)
This commit is contained in:
parent
179d7105c9
commit
8c42490a7e
@ -40,10 +40,12 @@ FrontMatter:
|
|||||||
import importlib
|
import importlib
|
||||||
from typing import Any, Dict, Type, Optional
|
from typing import Any, Dict, Type, Optional
|
||||||
|
|
||||||
|
import loguru
|
||||||
|
|
||||||
|
from nonebot.log import logger
|
||||||
from nonebot.adapters import Bot
|
from nonebot.adapters import Bot
|
||||||
from nonebot.utils import escape_tag
|
from nonebot.utils import escape_tag
|
||||||
from nonebot.config import Env, Config
|
from nonebot.config import Env, Config
|
||||||
from nonebot.log import logger, default_filter
|
|
||||||
from nonebot.drivers import Driver, ReverseDriver, combine_driver
|
from nonebot.drivers import Driver, ReverseDriver, combine_driver
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -206,6 +208,15 @@ def _resolve_combine_expr(obj_str: str) -> Type[Driver]:
|
|||||||
return combine_driver(DriverClass, *mixins)
|
return combine_driver(DriverClass, *mixins)
|
||||||
|
|
||||||
|
|
||||||
|
def _log_patcher(record: "loguru.Record"):
|
||||||
|
record["name"] = (
|
||||||
|
plugin.name
|
||||||
|
if (module_name := record["name"])
|
||||||
|
and (plugin := get_plugin_by_module_name(module_name))
|
||||||
|
else (module_name and module_name.split(".")[0])
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def init(*, _env_file: Optional[str] = None, **kwargs: Any) -> None:
|
def init(*, _env_file: Optional[str] = None, **kwargs: Any) -> None:
|
||||||
"""初始化 NoneBot 以及 全局 {ref}`nonebot.drivers.Driver` 对象。
|
"""初始化 NoneBot 以及 全局 {ref}`nonebot.drivers.Driver` 对象。
|
||||||
|
|
||||||
@ -232,7 +243,9 @@ def init(*, _env_file: Optional[str] = None, **kwargs: Any) -> None:
|
|||||||
_env_file=_env_file or f".env.{env.environment}",
|
_env_file=_env_file or f".env.{env.environment}",
|
||||||
)
|
)
|
||||||
|
|
||||||
default_filter.level = config.log_level
|
logger.configure(
|
||||||
|
extra={"nonebot_log_level": config.log_level}, patcher=_log_patcher
|
||||||
|
)
|
||||||
logger.opt(colors=True).info(
|
logger.opt(colors=True).info(
|
||||||
f"Current <y><b>Env: {escape_tag(env.environment)}</b></y>"
|
f"Current <y><b>Env: {escape_tag(env.environment)}</b></y>"
|
||||||
)
|
)
|
||||||
|
@ -25,7 +25,6 @@ from pydantic.env_settings import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
from nonebot.utils import escape_tag
|
|
||||||
|
|
||||||
|
|
||||||
class CustomEnvSettings(EnvSettingsSource):
|
class CustomEnvSettings(EnvSettingsSource):
|
||||||
@ -85,13 +84,15 @@ class CustomEnvSettings(EnvSettingsSource):
|
|||||||
if env_file_vars:
|
if env_file_vars:
|
||||||
for env_name in env_file_vars.keys():
|
for env_name in env_file_vars.keys():
|
||||||
env_val = env_vars[env_name]
|
env_val = env_vars[env_name]
|
||||||
try:
|
if env_val and (val_striped := env_val.strip()):
|
||||||
if env_val:
|
try:
|
||||||
env_val = settings.__config__.json_loads(env_val.strip())
|
env_val = settings.__config__.json_loads(val_striped)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.opt(colors=True, exception=e).trace(
|
logger.trace(
|
||||||
f"Error while parsing JSON for {escape_tag(env_name)}. Assumed as string."
|
"Error while parsing JSON for "
|
||||||
)
|
f"{env_name!r}={val_striped!r}. "
|
||||||
|
"Assumed as string."
|
||||||
|
)
|
||||||
|
|
||||||
d[env_name] = env_val
|
d[env_name] = env_val
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ from pydantic.fields import Required, FieldInfo, Undefined, ModelField
|
|||||||
|
|
||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
from nonebot.typing import _DependentCallable
|
from nonebot.typing import _DependentCallable
|
||||||
|
from nonebot.exception import SkippedException
|
||||||
from nonebot.utils import run_sync, is_coroutine_callable
|
from nonebot.utils import run_sync, is_coroutine_callable
|
||||||
|
|
||||||
from .utils import check_field_type, get_typed_signature
|
from .utils import check_field_type, get_typed_signature
|
||||||
@ -85,7 +86,15 @@ class Dependent(Generic[R]):
|
|||||||
parameterless: Tuple[Param] = field(default_factory=tuple)
|
parameterless: Tuple[Param] = field(default_factory=tuple)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<Dependent call={self.call}>"
|
if inspect.isfunction(self.call) or inspect.isclass(self.call):
|
||||||
|
call_str = self.call.__name__
|
||||||
|
else:
|
||||||
|
call_str = repr(self.call)
|
||||||
|
return (
|
||||||
|
f"Dependent(call={call_str}"
|
||||||
|
+ (f", parameterless={self.parameterless}" if self.parameterless else "")
|
||||||
|
+ ")"
|
||||||
|
)
|
||||||
|
|
||||||
async def __call__(self, **kwargs: Any) -> R:
|
async def __call__(self, **kwargs: Any) -> R:
|
||||||
# do pre-check
|
# do pre-check
|
||||||
@ -178,19 +187,22 @@ class Dependent(Generic[R]):
|
|||||||
else cls.parse_parameterless(tuple(parameterless), allow_types)
|
else cls.parse_parameterless(tuple(parameterless), allow_types)
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.trace(
|
|
||||||
f"Parsed dependent with call={call}, "
|
|
||||||
f"params={params}, "
|
|
||||||
f"parameterless={parameterless_params}"
|
|
||||||
)
|
|
||||||
|
|
||||||
return cls(call, params, parameterless_params)
|
return cls(call, params, parameterless_params)
|
||||||
|
|
||||||
async def check(self, **params: Any) -> None:
|
async def check(self, **params: Any) -> None:
|
||||||
await asyncio.gather(*(param._check(**params) for param in self.parameterless))
|
try:
|
||||||
await asyncio.gather(
|
await asyncio.gather(
|
||||||
*(cast(Param, param.field_info)._check(**params) for param in self.params)
|
*(param._check(**params) for param in self.parameterless)
|
||||||
)
|
)
|
||||||
|
await asyncio.gather(
|
||||||
|
*(
|
||||||
|
cast(Param, param.field_info)._check(**params)
|
||||||
|
for param in self.params
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except SkippedException as e:
|
||||||
|
logger.trace(f"{self} skipped due to {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
async def _solve_field(self, field: ModelField, params: Dict[str, Any]) -> Any:
|
async def _solve_field(self, field: ModelField, params: Dict[str, Any]) -> Any:
|
||||||
value = await cast(Param, field.field_info)._solve(**params)
|
value = await cast(Param, field.field_info)._solve(**params)
|
||||||
|
@ -27,7 +27,7 @@ from nonebot.drivers import HTTPVersion, ForwardMixin, ForwardDriver, combine_dr
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
import aiohttp
|
import aiohttp
|
||||||
except ImportError:
|
except ImportError: # pragma: no cover
|
||||||
raise ImportError(
|
raise ImportError(
|
||||||
"Please install aiohttp first to use this driver. `pip install nonebot2[aiohttp]`"
|
"Please install aiohttp first to use this driver. `pip install nonebot2[aiohttp]`"
|
||||||
) from None
|
) from None
|
||||||
|
@ -31,7 +31,7 @@ from nonebot.drivers import (
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
import httpx
|
import httpx
|
||||||
except ImportError:
|
except ImportError: # pragma: no cover
|
||||||
raise ImportError(
|
raise ImportError(
|
||||||
"Please install httpx by using `pip install nonebot2[httpx]`"
|
"Please install httpx by using `pip install nonebot2[httpx]`"
|
||||||
) from None
|
) from None
|
||||||
|
@ -37,7 +37,7 @@ try:
|
|||||||
from quart import Quart, Request, Response
|
from quart import Quart, Request, Response
|
||||||
from quart.datastructures import FileStorage
|
from quart.datastructures import FileStorage
|
||||||
from quart import Websocket as QuartWebSocket
|
from quart import Websocket as QuartWebSocket
|
||||||
except ImportError:
|
except ImportError: # pragma: no cover
|
||||||
raise ImportError(
|
raise ImportError(
|
||||||
"Please install Quart by using `pip install nonebot2[quart]`"
|
"Please install Quart by using `pip install nonebot2[quart]`"
|
||||||
) from None
|
) from None
|
||||||
|
@ -30,10 +30,10 @@ from nonebot.drivers import ForwardMixin, ForwardDriver, combine_driver
|
|||||||
try:
|
try:
|
||||||
from websockets.exceptions import ConnectionClosed
|
from websockets.exceptions import ConnectionClosed
|
||||||
from websockets.legacy.client import Connect, WebSocketClientProtocol
|
from websockets.legacy.client import Connect, WebSocketClientProtocol
|
||||||
except ImportError:
|
except ImportError: # pragma: no cover
|
||||||
raise ImportError(
|
raise ImportError(
|
||||||
"Please install websockets by using `pip install nonebot2[websockets]`"
|
"Please install websockets by using `pip install nonebot2[websockets]`"
|
||||||
)
|
) from None
|
||||||
|
|
||||||
logger = logging.Logger("websockets.client", "INFO")
|
logger = logging.Logger("websockets.client", "INFO")
|
||||||
logger.addHandler(LoguruHandler())
|
logger.addHandler(LoguruHandler())
|
||||||
|
@ -46,10 +46,14 @@ class ParserExit(NoneBotException):
|
|||||||
self.status = status
|
self.status = status
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self) -> str:
|
||||||
return f"<ParserExit status={self.status} message={self.message}>"
|
return (
|
||||||
|
f"ParserExit(status={self.status}"
|
||||||
|
+ (f", message={self.message!r}" if self.message else "")
|
||||||
|
+ ")"
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return self.__repr__()
|
return self.__repr__()
|
||||||
|
|
||||||
|
|
||||||
@ -68,10 +72,10 @@ class IgnoredException(ProcessException):
|
|||||||
def __init__(self, reason: Any):
|
def __init__(self, reason: Any):
|
||||||
self.reason: Any = reason
|
self.reason: Any = reason
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self) -> str:
|
||||||
return f"<IgnoredException, reason={self.reason}>"
|
return f"IgnoredException(reason={self.reason!r})"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return self.__repr__()
|
return self.__repr__()
|
||||||
|
|
||||||
|
|
||||||
@ -99,11 +103,14 @@ class TypeMisMatch(SkippedException):
|
|||||||
self.param: ModelField = param
|
self.param: ModelField = param
|
||||||
self.value: Any = value
|
self.value: Any = value
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self) -> str:
|
||||||
return f"<TypeMisMatch, param={self.param}, value={self.value}>"
|
return (
|
||||||
|
f"TypeMisMatch(param={self.param.name}, "
|
||||||
|
f"type={self.param._type_display()}, value={self.value!r}>"
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
self.__repr__()
|
return self.__repr__()
|
||||||
|
|
||||||
|
|
||||||
class MockApiException(ProcessException):
|
class MockApiException(ProcessException):
|
||||||
@ -116,10 +123,10 @@ class MockApiException(ProcessException):
|
|||||||
def __init__(self, result: Any):
|
def __init__(self, result: Any):
|
||||||
self.result = result
|
self.result = result
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self) -> str:
|
||||||
return f"<ApiCancelledException, result={self.result}>"
|
return f"MockApiException(result={self.result!r})"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return self.__repr__()
|
return self.__repr__()
|
||||||
|
|
||||||
|
|
||||||
@ -195,7 +202,8 @@ class AdapterException(NoneBotException):
|
|||||||
adapter_name: 标识 adapter
|
adapter_name: 标识 adapter
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, adapter_name: str) -> None:
|
def __init__(self, adapter_name: str, *args: object) -> None:
|
||||||
|
super().__init__(*args)
|
||||||
self.adapter_name: str = adapter_name
|
self.adapter_name: str = adapter_name
|
||||||
|
|
||||||
|
|
||||||
@ -231,4 +239,11 @@ class WebSocketClosed(DriverException):
|
|||||||
self.reason = reason
|
self.reason = reason
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<WebSocketClosed code={self.code} reason={self.reason}>"
|
return (
|
||||||
|
f"WebSocketClosed(code={self.code}"
|
||||||
|
+ (f", reason={self.reason!r}" if self.reason else "")
|
||||||
|
+ ")"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.__repr__()
|
||||||
|
@ -33,6 +33,9 @@ class Adapter(abc.ABC):
|
|||||||
self.bots: Dict[str, Bot] = {}
|
self.bots: Dict[str, Bot] = {}
|
||||||
"""本协议适配器已建立连接的 {ref}`nonebot.adapters.Bot` 实例"""
|
"""本协议适配器已建立连接的 {ref}`nonebot.adapters.Bot` 实例"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"Adapter(name={self.get_name()!r})"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def get_name(cls) -> str:
|
def get_name(cls) -> str:
|
||||||
|
@ -13,10 +13,9 @@ if TYPE_CHECKING:
|
|||||||
from .adapter import Adapter
|
from .adapter import Adapter
|
||||||
from .message import Message, MessageSegment
|
from .message import Message, MessageSegment
|
||||||
|
|
||||||
|
class _ApiCall(Protocol):
|
||||||
class _ApiCall(Protocol):
|
async def __call__(self, **kwargs: Any) -> Any:
|
||||||
async def __call__(self, **kwargs: Any) -> Any:
|
...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class Bot(abc.ABC):
|
class Bot(abc.ABC):
|
||||||
@ -40,7 +39,10 @@ class Bot(abc.ABC):
|
|||||||
self.self_id: str = self_id
|
self.self_id: str = self_id
|
||||||
"""机器人 ID"""
|
"""机器人 ID"""
|
||||||
|
|
||||||
def __getattr__(self, name: str) -> _ApiCall:
|
def __repr__(self) -> str:
|
||||||
|
return f"Bot(type={self.type!r}, self_id={self.self_id!r})"
|
||||||
|
|
||||||
|
def __getattr__(self, name: str) -> "_ApiCall":
|
||||||
return partial(self.call_api, name)
|
return partial(self.call_api, name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -56,6 +56,9 @@ class MessageTemplate(Formatter, Generic[TF]):
|
|||||||
self.factory: Type[TF] = factory
|
self.factory: Type[TF] = factory
|
||||||
self.format_specs: Dict[str, FormatSpecFunc] = {}
|
self.format_specs: Dict[str, FormatSpecFunc] = {}
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"MessageTemplate({self.template!r}, factory={self.factory!r})"
|
||||||
|
|
||||||
def add_format_spec(
|
def add_format_spec(
|
||||||
self, spec: FormatSpecFunc_T, name: Optional[str] = None
|
self, spec: FormatSpecFunc_T, name: Optional[str] = None
|
||||||
) -> FormatSpecFunc_T:
|
) -> FormatSpecFunc_T:
|
||||||
|
@ -40,12 +40,18 @@ class Driver(abc.ABC):
|
|||||||
"""环境名称"""
|
"""环境名称"""
|
||||||
self.config: Config = config
|
self.config: Config = config
|
||||||
"""全局配置对象"""
|
"""全局配置对象"""
|
||||||
self._clients: Dict[str, "Bot"] = {}
|
self._bots: Dict[str, "Bot"] = {}
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return (
|
||||||
|
f"Driver(type={self.type!r}, "
|
||||||
|
f"adapters={len(self._adapters)}, bots={len(self._bots)})"
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bots(self) -> Dict[str, "Bot"]:
|
def bots(self) -> Dict[str, "Bot"]:
|
||||||
"""获取当前所有已连接的 Bot"""
|
"""获取当前所有已连接的 Bot"""
|
||||||
return self._clients
|
return self._bots
|
||||||
|
|
||||||
def register_adapter(self, adapter: Type["Adapter"], **kwargs) -> None:
|
def register_adapter(self, adapter: Type["Adapter"], **kwargs) -> None:
|
||||||
"""注册一个协议适配器
|
"""注册一个协议适配器
|
||||||
@ -124,9 +130,9 @@ class Driver(abc.ABC):
|
|||||||
|
|
||||||
def _bot_connect(self, bot: "Bot") -> None:
|
def _bot_connect(self, bot: "Bot") -> None:
|
||||||
"""在连接成功后,调用该函数来注册 bot 对象"""
|
"""在连接成功后,调用该函数来注册 bot 对象"""
|
||||||
if bot.self_id in self._clients:
|
if bot.self_id in self._bots:
|
||||||
raise RuntimeError(f"Duplicate bot connection with id {bot.self_id}")
|
raise RuntimeError(f"Duplicate bot connection with id {bot.self_id}")
|
||||||
self._clients[bot.self_id] = bot
|
self._bots[bot.self_id] = bot
|
||||||
|
|
||||||
async def _run_hook(bot: "Bot") -> None:
|
async def _run_hook(bot: "Bot") -> None:
|
||||||
coros = list(
|
coros = list(
|
||||||
@ -148,8 +154,8 @@ class Driver(abc.ABC):
|
|||||||
|
|
||||||
def _bot_disconnect(self, bot: "Bot") -> None:
|
def _bot_disconnect(self, bot: "Bot") -> None:
|
||||||
"""在连接断开后,调用该函数来注销 bot 对象"""
|
"""在连接断开后,调用该函数来注销 bot 对象"""
|
||||||
if bot.self_id in self._clients:
|
if bot.self_id in self._bots:
|
||||||
del self._clients[bot.self_id]
|
del self._bots[bot.self_id]
|
||||||
|
|
||||||
async def _run_hook(bot: "Bot") -> None:
|
async def _run_hook(bot: "Bot") -> None:
|
||||||
coros = list(
|
coros = list(
|
||||||
|
@ -131,9 +131,7 @@ class Request:
|
|||||||
self.files.append((name, file_info)) # type: ignore
|
self.files.append((name, file_info)) # type: ignore
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
class_name = self.__class__.__name__
|
return f"{self.__class__.__name__}(method={self.method!r}, url='{self.url!s}')"
|
||||||
url = str(self.url)
|
|
||||||
return f"<{class_name}({self.method!r}, {url!r})>"
|
|
||||||
|
|
||||||
|
|
||||||
class Response:
|
class Response:
|
||||||
@ -161,12 +159,18 @@ class Response:
|
|||||||
# request
|
# request
|
||||||
self.request: Optional[Request] = request
|
self.request: Optional[Request] = request
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"{self.__class__.__name__}(status_code={self.status_code!r})"
|
||||||
|
|
||||||
|
|
||||||
class WebSocket(abc.ABC):
|
class WebSocket(abc.ABC):
|
||||||
def __init__(self, *, request: Request):
|
def __init__(self, *, request: Request):
|
||||||
# request
|
# request
|
||||||
self.request: Request = request
|
self.request: Request = request
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"{self.__class__.__name__}('{self.request.url!s}')"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def closed(self) -> bool:
|
def closed(self) -> bool:
|
||||||
@ -320,17 +324,14 @@ class Cookies(MutableMapping):
|
|||||||
return len(self.jar)
|
return len(self.jar)
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[Cookie]:
|
def __iter__(self) -> Iterator[Cookie]:
|
||||||
return (cookie for cookie in self.jar)
|
return iter(self.jar)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
cookies_repr = ", ".join(
|
cookies_repr = ", ".join(
|
||||||
[
|
f"Cookie({cookie.name}={cookie.value} for {cookie.domain})"
|
||||||
f"<Cookie {cookie.name}={cookie.value} for {cookie.domain} />"
|
for cookie in self.jar
|
||||||
for cookie in self.jar
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
return f"{self.__class__.__name__}({cookies_repr})"
|
||||||
return f"<Cookies [{cookies_repr}]>"
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -36,7 +36,6 @@ from nonebot.typing import (
|
|||||||
T_PermissionUpdater,
|
T_PermissionUpdater,
|
||||||
)
|
)
|
||||||
from nonebot.exception import (
|
from nonebot.exception import (
|
||||||
TypeMisMatch,
|
|
||||||
PausedException,
|
PausedException,
|
||||||
StopPropagation,
|
StopPropagation,
|
||||||
SkippedException,
|
SkippedException,
|
||||||
@ -73,29 +72,16 @@ current_handler: ContextVar[Dependent] = ContextVar("current_handler")
|
|||||||
|
|
||||||
class MatcherMeta(type):
|
class MatcherMeta(type):
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
module: Optional[str]
|
|
||||||
plugin_name: Optional[str]
|
|
||||||
module_name: Optional[str]
|
module_name: Optional[str]
|
||||||
module_prefix: Optional[str]
|
|
||||||
type: 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:
|
def __repr__(self) -> str:
|
||||||
return (
|
return (
|
||||||
f"<Matcher from {self.module_name or 'unknown'}, "
|
f"Matcher(type={self.type!r}"
|
||||||
f"type={self.type}, priority={self.priority}, "
|
+ (f", module={self.module_name}" if self.module_name else "")
|
||||||
f"temp={self.temp}>"
|
+ ")"
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return repr(self)
|
|
||||||
|
|
||||||
|
|
||||||
class Matcher(metaclass=MatcherMeta):
|
class Matcher(metaclass=MatcherMeta):
|
||||||
"""事件响应器类"""
|
"""事件响应器类"""
|
||||||
@ -150,8 +136,9 @@ class Matcher(metaclass=MatcherMeta):
|
|||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return (
|
return (
|
||||||
f"<Matcher from {self.module_name or 'unknown'}, type={self.type}, "
|
f"Matcher(type={self.type!r}"
|
||||||
f"priority={self.priority}, temp={self.temp}>"
|
+ (f", module={self.module_name}" if self.module_name else "")
|
||||||
|
+ ")"
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -683,8 +670,8 @@ class Matcher(metaclass=MatcherMeta):
|
|||||||
dependency_cache: Optional[T_DependencyCache] = None,
|
dependency_cache: Optional[T_DependencyCache] = None,
|
||||||
):
|
):
|
||||||
logger.trace(
|
logger.trace(
|
||||||
f"Matcher {self} run with incoming args: "
|
f"{self} run with incoming args: "
|
||||||
f"bot={bot}, event={event}, state={state}"
|
f"bot={bot}, event={event!r}, state={state!r}"
|
||||||
)
|
)
|
||||||
b_t = current_bot.set(bot)
|
b_t = current_bot.set(bot)
|
||||||
e_t = current_event.set(event)
|
e_t = current_event.set(event)
|
||||||
@ -706,17 +693,12 @@ class Matcher(metaclass=MatcherMeta):
|
|||||||
stack=stack,
|
stack=stack,
|
||||||
dependency_cache=dependency_cache,
|
dependency_cache=dependency_cache,
|
||||||
)
|
)
|
||||||
except TypeMisMatch as e:
|
except SkippedException:
|
||||||
logger.debug(
|
|
||||||
f"Handler {handler} param {e.param.name} value {e.value} "
|
|
||||||
f"mismatch type {e.param._type_display()}, skipped"
|
|
||||||
)
|
|
||||||
except SkippedException as e:
|
|
||||||
logger.debug(f"Handler {handler} skipped")
|
logger.debug(f"Handler {handler} skipped")
|
||||||
except StopPropagation:
|
except StopPropagation:
|
||||||
self.block = True
|
self.block = True
|
||||||
finally:
|
finally:
|
||||||
logger.info(f"Matcher {self} running complete")
|
logger.info(f"{self} running complete")
|
||||||
current_bot.reset(b_t)
|
current_bot.reset(b_t)
|
||||||
current_event.reset(e_t)
|
current_event.reset(e_t)
|
||||||
current_matcher.reset(m_t)
|
current_matcher.reset(m_t)
|
||||||
|
@ -36,7 +36,7 @@ class DependsInner:
|
|||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
dep = get_name(self.dependency)
|
dep = get_name(self.dependency)
|
||||||
cache = "" if self.use_cache else ", use_cache=False"
|
cache = "" if self.use_cache else ", use_cache=False"
|
||||||
return f"{self.__class__.__name__}({dep}{cache})"
|
return f"DependsInner({dep}{cache})"
|
||||||
|
|
||||||
|
|
||||||
def Depends(
|
def Depends(
|
||||||
@ -71,6 +71,9 @@ def Depends(
|
|||||||
class DependParam(Param):
|
class DependParam(Param):
|
||||||
"""子依赖参数"""
|
"""子依赖参数"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"Depends({self.extra['dependent']})"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _check_param(
|
def _check_param(
|
||||||
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
||||||
@ -153,6 +156,17 @@ class DependParam(Param):
|
|||||||
class BotParam(Param):
|
class BotParam(Param):
|
||||||
"""{ref}`nonebot.adapters.Bot` 参数"""
|
"""{ref}`nonebot.adapters.Bot` 参数"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return (
|
||||||
|
"BotParam("
|
||||||
|
+ (
|
||||||
|
repr(cast(ModelField, checker).type_)
|
||||||
|
if (checker := self.extra.get("checker"))
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
+ ")"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _check_param(
|
def _check_param(
|
||||||
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
||||||
@ -179,13 +193,24 @@ class BotParam(Param):
|
|||||||
return bot
|
return bot
|
||||||
|
|
||||||
async def _check(self, bot: "Bot", **kwargs: Any) -> None:
|
async def _check(self, bot: "Bot", **kwargs: Any) -> None:
|
||||||
if checker := self.extra.get("checker", None):
|
if checker := self.extra.get("checker"):
|
||||||
check_field_type(checker, bot)
|
check_field_type(checker, bot)
|
||||||
|
|
||||||
|
|
||||||
class EventParam(Param):
|
class EventParam(Param):
|
||||||
"""{ref}`nonebot.adapters.Event` 参数"""
|
"""{ref}`nonebot.adapters.Event` 参数"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return (
|
||||||
|
"EventParam("
|
||||||
|
+ (
|
||||||
|
repr(cast(ModelField, checker).type_)
|
||||||
|
if (checker := self.extra.get("checker"))
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
+ ")"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _check_param(
|
def _check_param(
|
||||||
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
||||||
@ -216,20 +241,17 @@ class EventParam(Param):
|
|||||||
check_field_type(checker, event)
|
check_field_type(checker, event)
|
||||||
|
|
||||||
|
|
||||||
class StateInner(T_State):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class StateParam(Param):
|
class StateParam(Param):
|
||||||
"""事件处理状态参数"""
|
"""事件处理状态参数"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "StateParam()"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _check_param(
|
def _check_param(
|
||||||
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
||||||
) -> Optional["StateParam"]:
|
) -> Optional["StateParam"]:
|
||||||
if isinstance(param.default, StateInner):
|
if param.default == param.empty:
|
||||||
return cls(Required)
|
|
||||||
elif param.default == param.empty:
|
|
||||||
if param.annotation is T_State:
|
if param.annotation is T_State:
|
||||||
return cls(Required)
|
return cls(Required)
|
||||||
elif param.annotation == param.empty and param.name == "state":
|
elif param.annotation == param.empty and param.name == "state":
|
||||||
@ -242,6 +264,9 @@ class StateParam(Param):
|
|||||||
class MatcherParam(Param):
|
class MatcherParam(Param):
|
||||||
"""事件响应器实例参数"""
|
"""事件响应器实例参数"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "MatcherParam()"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _check_param(
|
def _check_param(
|
||||||
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
||||||
@ -264,6 +289,9 @@ class ArgInner:
|
|||||||
self.key = key
|
self.key = key
|
||||||
self.type = type
|
self.type = type
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"ArgInner(key={self.key!r}, type={self.type!r})"
|
||||||
|
|
||||||
|
|
||||||
def Arg(key: Optional[str] = None) -> Any:
|
def Arg(key: Optional[str] = None) -> Any:
|
||||||
"""`got` 的 Arg 参数消息"""
|
"""`got` 的 Arg 参数消息"""
|
||||||
@ -283,6 +311,9 @@ def ArgPlainText(key: Optional[str] = None) -> str:
|
|||||||
class ArgParam(Param):
|
class ArgParam(Param):
|
||||||
"""`got` 的 Arg 参数"""
|
"""`got` 的 Arg 参数"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"ArgParam(key={self.extra['key']!r}, type={self.extra['type']!r})"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _check_param(
|
def _check_param(
|
||||||
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
||||||
@ -307,6 +338,9 @@ class ArgParam(Param):
|
|||||||
class ExceptionParam(Param):
|
class ExceptionParam(Param):
|
||||||
"""`run_postprocessor` 的异常参数"""
|
"""`run_postprocessor` 的异常参数"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "ExceptionParam()"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _check_param(
|
def _check_param(
|
||||||
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
||||||
@ -323,6 +357,9 @@ class ExceptionParam(Param):
|
|||||||
class DefaultParam(Param):
|
class DefaultParam(Param):
|
||||||
"""默认值参数"""
|
"""默认值参数"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"DefaultParam(default={self.default!r})"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _check_param(
|
def _check_param(
|
||||||
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
cls, param: inspect.Parameter, allow_types: Tuple[Type[Param], ...]
|
||||||
|
@ -47,6 +47,9 @@ class Permission:
|
|||||||
}
|
}
|
||||||
"""存储 `PermissionChecker`"""
|
"""存储 `PermissionChecker`"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"Permission({', '.join(repr(checker) for checker in self.checkers)})"
|
||||||
|
|
||||||
async def __call__(
|
async def __call__(
|
||||||
self,
|
self,
|
||||||
bot: Bot,
|
bot: Bot,
|
||||||
@ -121,6 +124,13 @@ class User:
|
|||||||
self.users = users
|
self.users = users
|
||||||
self.perm = perm
|
self.perm = perm
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return (
|
||||||
|
f"User(users={self.users}"
|
||||||
|
+ (f", permission={self.perm})" if self.perm else "")
|
||||||
|
+ ")"
|
||||||
|
)
|
||||||
|
|
||||||
async def __call__(self, bot: Bot, event: Event) -> bool:
|
async def __call__(self, bot: Bot, event: Event) -> bool:
|
||||||
return bool(
|
return bool(
|
||||||
event.get_session_id() in self.users
|
event.get_session_id() in self.users
|
||||||
|
@ -47,6 +47,9 @@ class Rule:
|
|||||||
}
|
}
|
||||||
"""存储 `RuleChecker`"""
|
"""存储 `RuleChecker`"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"Rule({', '.join(repr(checker) for checker in self.checkers)})"
|
||||||
|
|
||||||
async def __call__(
|
async def __call__(
|
||||||
self,
|
self,
|
||||||
bot: Bot,
|
bot: Bot,
|
||||||
|
@ -14,16 +14,14 @@ FrontMatter:
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING, Union
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import loguru
|
import loguru
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
# avoid sphinx autodoc resolve annotation failed
|
# avoid sphinx autodoc resolve annotation failed
|
||||||
# because loguru module do not have `Logger` class actually
|
# because loguru module do not have `Logger` class actually
|
||||||
from loguru import Logger
|
from loguru import Logger, Record
|
||||||
|
|
||||||
from nonebot.plugin import Plugin
|
|
||||||
|
|
||||||
# logger = logging.getLogger("nonebot")
|
# logger = logging.getLogger("nonebot")
|
||||||
logger: "Logger" = loguru.logger
|
logger: "Logger" = loguru.logger
|
||||||
@ -47,26 +45,10 @@ logger: "Logger" = loguru.logger
|
|||||||
# logger.addHandler(default_handler)
|
# logger.addHandler(default_handler)
|
||||||
|
|
||||||
|
|
||||||
class Filter:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.level: Union[int, str] = "INFO"
|
|
||||||
|
|
||||||
def __call__(self, record):
|
|
||||||
module_name: str = record["name"]
|
|
||||||
# TODO: get plugin name instead of module name
|
|
||||||
# module = sys.modules.get(module_name)
|
|
||||||
# if module and hasattr(module, "__plugin__"):
|
|
||||||
# plugin: "Plugin" = getattr(module, "__plugin__")
|
|
||||||
# module_name = plugin.module_name
|
|
||||||
record["name"] = module_name.split(".")[0]
|
|
||||||
levelno = (
|
|
||||||
logger.level(self.level).no if isinstance(self.level, str) else self.level
|
|
||||||
)
|
|
||||||
return record["level"].no >= levelno
|
|
||||||
|
|
||||||
|
|
||||||
class LoguruHandler(logging.Handler): # pragma: no cover
|
class LoguruHandler(logging.Handler): # pragma: no cover
|
||||||
def emit(self, record):
|
"""logging 与 loguru 之间的桥梁,将 logging 的日志转发到 loguru。"""
|
||||||
|
|
||||||
|
def emit(self, record: logging.LogRecord):
|
||||||
try:
|
try:
|
||||||
level = logger.level(record.levelname).name
|
level = logger.level(record.levelname).name
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -82,9 +64,13 @@ class LoguruHandler(logging.Handler): # pragma: no cover
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
logger.remove()
|
def default_filter(record: "Record"):
|
||||||
default_filter: Filter = Filter()
|
"""默认的日志过滤器,根据 `config.log_level` 配置改变日志等级。"""
|
||||||
"""默认日志等级过滤器"""
|
log_level = record["extra"].get("nonebot_log_level", "INFO")
|
||||||
|
levelno = logger.level(log_level).no if isinstance(log_level, str) else log_level
|
||||||
|
return record["level"].no >= levelno
|
||||||
|
|
||||||
|
|
||||||
default_format: str = (
|
default_format: str = (
|
||||||
"<g>{time:MM-DD HH:mm:ss}</g> "
|
"<g>{time:MM-DD HH:mm:ss}</g> "
|
||||||
"[<lvl>{level}</lvl>] "
|
"[<lvl>{level}</lvl>] "
|
||||||
@ -93,6 +79,8 @@ default_format: str = (
|
|||||||
"{message}"
|
"{message}"
|
||||||
)
|
)
|
||||||
"""默认日志格式"""
|
"""默认日志格式"""
|
||||||
|
|
||||||
|
logger.remove()
|
||||||
logger_id = logger.add(
|
logger_id = logger.add(
|
||||||
sys.stdout,
|
sys.stdout,
|
||||||
level=0,
|
level=0,
|
||||||
@ -101,4 +89,4 @@ logger_id = logger.add(
|
|||||||
format=default_format,
|
format=default_format,
|
||||||
)
|
)
|
||||||
|
|
||||||
__autodoc__ = {"Filter": False, "LoguruHandler": False}
|
__autodoc__ = {"logger_id": False}
|
||||||
|
@ -51,14 +51,14 @@ _event_postprocessors: Set[Dependent[Any]] = set()
|
|||||||
_run_preprocessors: Set[Dependent[Any]] = set()
|
_run_preprocessors: Set[Dependent[Any]] = set()
|
||||||
_run_postprocessors: Set[Dependent[Any]] = set()
|
_run_postprocessors: Set[Dependent[Any]] = set()
|
||||||
|
|
||||||
EVENT_PCS_PARAMS = [
|
EVENT_PCS_PARAMS = (
|
||||||
DependParam,
|
DependParam,
|
||||||
BotParam,
|
BotParam,
|
||||||
EventParam,
|
EventParam,
|
||||||
StateParam,
|
StateParam,
|
||||||
DefaultParam,
|
DefaultParam,
|
||||||
]
|
)
|
||||||
RUN_PREPCS_PARAMS = [
|
RUN_PREPCS_PARAMS = (
|
||||||
DependParam,
|
DependParam,
|
||||||
BotParam,
|
BotParam,
|
||||||
EventParam,
|
EventParam,
|
||||||
@ -66,8 +66,8 @@ RUN_PREPCS_PARAMS = [
|
|||||||
ArgParam,
|
ArgParam,
|
||||||
MatcherParam,
|
MatcherParam,
|
||||||
DefaultParam,
|
DefaultParam,
|
||||||
]
|
)
|
||||||
RUN_POSTPCS_PARAMS = [
|
RUN_POSTPCS_PARAMS = (
|
||||||
DependParam,
|
DependParam,
|
||||||
ExceptionParam,
|
ExceptionParam,
|
||||||
BotParam,
|
BotParam,
|
||||||
@ -76,7 +76,7 @@ RUN_POSTPCS_PARAMS = [
|
|||||||
ArgParam,
|
ArgParam,
|
||||||
MatcherParam,
|
MatcherParam,
|
||||||
DefaultParam,
|
DefaultParam,
|
||||||
]
|
)
|
||||||
|
|
||||||
|
|
||||||
def event_preprocessor(func: T_EventPreProcessor) -> T_EventPreProcessor:
|
def event_preprocessor(func: T_EventPreProcessor) -> T_EventPreProcessor:
|
||||||
@ -170,9 +170,7 @@ async def _run_matcher(
|
|||||||
try:
|
try:
|
||||||
await asyncio.gather(*coros)
|
await asyncio.gather(*coros)
|
||||||
except IgnoredException:
|
except IgnoredException:
|
||||||
logger.opt(colors=True).info(
|
logger.opt(colors=True).info(f"{matcher} running is <b>cancelled</b>")
|
||||||
f"Matcher {matcher} running is <b>cancelled</b>"
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.opt(colors=True, exception=e).error(
|
logger.opt(colors=True, exception=e).error(
|
||||||
@ -184,11 +182,11 @@ async def _run_matcher(
|
|||||||
exception = None
|
exception = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.debug(f"Running matcher {matcher}")
|
logger.debug(f"Running {matcher}")
|
||||||
await matcher.run(bot, event, state, stack, dependency_cache)
|
await matcher.run(bot, event, state, stack, dependency_cache)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.opt(colors=True, exception=e).error(
|
logger.opt(colors=True, exception=e).error(
|
||||||
f"<r><bg #f8bbd0>Running matcher {matcher} failed.</bg #f8bbd0></r>"
|
f"<r><bg #f8bbd0>Running {matcher} failed.</bg #f8bbd0></r>"
|
||||||
)
|
)
|
||||||
exception = e
|
exception = e
|
||||||
|
|
||||||
@ -233,7 +231,7 @@ async def handle_event(bot: "Bot", event: "Event") -> None:
|
|||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
show_log = True
|
show_log = True
|
||||||
log_msg = f"<m>{escape_tag(bot.type.upper())} {escape_tag(bot.self_id)}</m> | "
|
log_msg = f"<m>{escape_tag(bot.type)} {escape_tag(bot.self_id)}</m> | "
|
||||||
try:
|
try:
|
||||||
log_msg += event.get_log_string()
|
log_msg += event.get_log_string()
|
||||||
except NoLogException:
|
except NoLogException:
|
||||||
|
@ -20,6 +20,9 @@ class Message:
|
|||||||
|
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "Message()"
|
||||||
|
|
||||||
async def __call__(self, type: str = EventType()) -> bool:
|
async def __call__(self, type: str = EventType()) -> bool:
|
||||||
return type == "message"
|
return type == "message"
|
||||||
|
|
||||||
@ -29,6 +32,9 @@ class Notice:
|
|||||||
|
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "Notice()"
|
||||||
|
|
||||||
async def __call__(self, type: str = EventType()) -> bool:
|
async def __call__(self, type: str = EventType()) -> bool:
|
||||||
return type == "notice"
|
return type == "notice"
|
||||||
|
|
||||||
@ -38,6 +44,9 @@ class Request:
|
|||||||
|
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "Request()"
|
||||||
|
|
||||||
async def __call__(self, type: str = EventType()) -> bool:
|
async def __call__(self, type: str = EventType()) -> bool:
|
||||||
return type == "request"
|
return type == "request"
|
||||||
|
|
||||||
@ -47,6 +56,9 @@ class MetaEvent:
|
|||||||
|
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "MetaEvent()"
|
||||||
|
|
||||||
async def __call__(self, type: str = EventType()) -> bool:
|
async def __call__(self, type: str = EventType()) -> bool:
|
||||||
return type == "meta_event"
|
return type == "meta_event"
|
||||||
|
|
||||||
@ -78,6 +90,9 @@ class SuperUser:
|
|||||||
|
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "Superuser()"
|
||||||
|
|
||||||
async def __call__(self, bot: Bot, event: Event) -> bool:
|
async def __call__(self, bot: Bot, event: Event) -> bool:
|
||||||
return event.get_type() == "message" and (
|
return event.get_type() == "message" and (
|
||||||
f"{bot.adapter.get_name().split(maxsplit=1)[0].lower()}:{event.get_user_id()}"
|
f"{bot.adapter.get_name().split(maxsplit=1)[0].lower()}:{event.get_user_id()}"
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
- `load_builtin_plugin` => {ref}``load_builtin_plugin` <nonebot.plugin.load.load_builtin_plugin>`
|
- `load_builtin_plugin` => {ref}``load_builtin_plugin` <nonebot.plugin.load.load_builtin_plugin>`
|
||||||
- `load_builtin_plugins` => {ref}``load_builtin_plugins` <nonebot.plugin.load.load_builtin_plugins>`
|
- `load_builtin_plugins` => {ref}``load_builtin_plugins` <nonebot.plugin.load.load_builtin_plugins>`
|
||||||
- `require` => {ref}``require` <nonebot.plugin.load.require>`
|
- `require` => {ref}``require` <nonebot.plugin.load.require>`
|
||||||
|
- `PluginMetadata` => {ref}``PluginMetadata` <nonebot.plugin.plugin.PluginMetadata>`
|
||||||
|
|
||||||
FrontMatter:
|
FrontMatter:
|
||||||
sidebar_position: 0
|
sidebar_position: 0
|
||||||
@ -85,13 +86,12 @@ def get_plugin_by_module_name(module_name: str) -> Optional["Plugin"]:
|
|||||||
参数:
|
参数:
|
||||||
module_name: 模块名,即 {ref}`nonebot.plugin.plugin.Plugin.module_name`。
|
module_name: 模块名,即 {ref}`nonebot.plugin.plugin.Plugin.module_name`。
|
||||||
"""
|
"""
|
||||||
splits = module_name.split(".")
|
|
||||||
loaded = {plugin.module_name: plugin for plugin in _plugins.values()}
|
loaded = {plugin.module_name: plugin for plugin in _plugins.values()}
|
||||||
while splits:
|
has_parent = True
|
||||||
name = ".".join(splits)
|
while has_parent:
|
||||||
if name in loaded:
|
if module_name in loaded:
|
||||||
return loaded[name]
|
return loaded[module_name]
|
||||||
splits.pop()
|
module_name, *has_parent = module_name.rsplit(".", 1)
|
||||||
|
|
||||||
|
|
||||||
def get_loaded_plugins() -> Set["Plugin"]:
|
def get_loaded_plugins() -> Set["Plugin"]:
|
||||||
|
@ -159,11 +159,10 @@ def require(name: str) -> ModuleType:
|
|||||||
"""
|
"""
|
||||||
plugin = get_plugin(_module_name_to_plugin_name(name))
|
plugin = get_plugin(_module_name_to_plugin_name(name))
|
||||||
if not plugin:
|
if not plugin:
|
||||||
manager = _find_manager_by_name(name)
|
if manager := _find_manager_by_name(name):
|
||||||
if manager:
|
|
||||||
plugin = manager.load_plugin(name)
|
plugin = manager.load_plugin(name)
|
||||||
else:
|
else:
|
||||||
plugin = load_plugin(name)
|
plugin = load_plugin(name)
|
||||||
if not plugin:
|
if not plugin:
|
||||||
raise RuntimeError(f'Cannot load plugin "{name}"!')
|
raise RuntimeError(f'Cannot load plugin "{name}"!')
|
||||||
return plugin.module
|
return plugin.module
|
||||||
|
@ -51,6 +51,9 @@ class PluginManager:
|
|||||||
self._searched_plugin_names: Dict[str, Path] = {}
|
self._searched_plugin_names: Dict[str, Path] = {}
|
||||||
self.prepare_plugins()
|
self.prepare_plugins()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"PluginManager(plugins={self.plugins}, search_path={self.search_path})"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def third_party_plugins(self) -> Set[str]:
|
def third_party_plugins(self) -> Set[str]:
|
||||||
"""返回所有独立插件名称。"""
|
"""返回所有独立插件名称。"""
|
||||||
|
@ -32,9 +32,8 @@ from .manager import _current_plugin_chain
|
|||||||
|
|
||||||
|
|
||||||
def _store_matcher(matcher: Type[Matcher]) -> None:
|
def _store_matcher(matcher: Type[Matcher]) -> None:
|
||||||
plugins = _current_plugin_chain.get()
|
|
||||||
# only store the matcher defined in the plugin
|
# only store the matcher defined in the plugin
|
||||||
if plugins:
|
if plugins := _current_plugin_chain.get():
|
||||||
plugins[-1].matcher.add(matcher)
|
plugins[-1].matcher.add(matcher)
|
||||||
|
|
||||||
|
|
||||||
@ -370,7 +369,7 @@ def on_command(
|
|||||||
state: 默认 state
|
state: 默认 state
|
||||||
"""
|
"""
|
||||||
|
|
||||||
commands = set([cmd]) | (aliases or set())
|
commands = {cmd} | (aliases or set())
|
||||||
block = kwargs.pop("block", False)
|
block = kwargs.pop("block", False)
|
||||||
return on_message(
|
return on_message(
|
||||||
command(*commands) & rule, block=block, **kwargs, _depth=_depth + 1
|
command(*commands) & rule, block=block, **kwargs, _depth=_depth + 1
|
||||||
@ -405,7 +404,7 @@ def on_shell_command(
|
|||||||
state: 默认 state
|
state: 默认 state
|
||||||
"""
|
"""
|
||||||
|
|
||||||
commands = set([cmd]) | (aliases or set())
|
commands = {cmd} | (aliases or set())
|
||||||
return on_message(
|
return on_message(
|
||||||
shell_command(*commands, parser=parser) & rule,
|
shell_command(*commands, parser=parser) & rule,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
@ -486,6 +485,9 @@ class CommandGroup:
|
|||||||
self.base_kwargs: Dict[str, Any] = kwargs
|
self.base_kwargs: Dict[str, Any] = kwargs
|
||||||
"""其他传递给 `on_command` 的参数默认值"""
|
"""其他传递给 `on_command` 的参数默认值"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"CommandGroup(cmd={self.basecmd})"
|
||||||
|
|
||||||
def command(self, cmd: Union[str, Tuple[str, ...]], **kwargs) -> Type[Matcher]:
|
def command(self, cmd: Union[str, Tuple[str, ...]], **kwargs) -> Type[Matcher]:
|
||||||
"""注册一个新的命令。新参数将会覆盖命令组默认值
|
"""注册一个新的命令。新参数将会覆盖命令组默认值
|
||||||
|
|
||||||
@ -544,6 +546,9 @@ class MatcherGroup:
|
|||||||
self.base_kwargs: Dict[str, Any] = kwargs
|
self.base_kwargs: Dict[str, Any] = kwargs
|
||||||
"""其他传递给 `on` 的参数默认值"""
|
"""其他传递给 `on` 的参数默认值"""
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"MatcherGroup(matchers={len(self.matchers)})"
|
||||||
|
|
||||||
def on(self, **kwargs) -> Type[Matcher]:
|
def on(self, **kwargs) -> Type[Matcher]:
|
||||||
"""注册一个基础事件响应器,可自定义类型。
|
"""注册一个基础事件响应器,可自定义类型。
|
||||||
|
|
||||||
|
@ -7,5 +7,5 @@ echo = on_command("echo", to_me())
|
|||||||
|
|
||||||
|
|
||||||
@echo.handle()
|
@echo.handle()
|
||||||
async def echo_escape(message: Message = CommandArg()):
|
async def handle_echo(message: Message = CommandArg()):
|
||||||
await echo.send(message=message)
|
await echo.send(message=message)
|
||||||
|
@ -15,8 +15,7 @@ async def matcher_mutex(event: Event) -> AsyncGenerator[bool, None]:
|
|||||||
yield result
|
yield result
|
||||||
else:
|
else:
|
||||||
current_event_id = id(event)
|
current_event_id = id(event)
|
||||||
event_id = _running_matcher.get(session_id, None)
|
if event_id := _running_matcher.get(session_id, None):
|
||||||
if event_id:
|
|
||||||
result = event_id != current_event_id
|
result = event_id != current_event_id
|
||||||
else:
|
else:
|
||||||
_running_matcher[session_id] = current_event_id
|
_running_matcher[session_id] = current_event_id
|
||||||
|
@ -131,7 +131,7 @@ class StartswithRule:
|
|||||||
self.ignorecase = ignorecase
|
self.ignorecase = ignorecase
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"StartswithRule(msg={self.msg}, ignorecase={self.ignorecase})"
|
return f"Startswith(msg={self.msg}, ignorecase={self.ignorecase})"
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
def __eq__(self, other: object) -> bool:
|
||||||
return (
|
return (
|
||||||
@ -185,7 +185,7 @@ class EndswithRule:
|
|||||||
self.ignorecase = ignorecase
|
self.ignorecase = ignorecase
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"EndswithRule(msg={self.msg}, ignorecase={self.ignorecase})"
|
return f"Endswith(msg={self.msg}, ignorecase={self.ignorecase})"
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
def __eq__(self, other: object) -> bool:
|
||||||
return (
|
return (
|
||||||
@ -239,7 +239,7 @@ class FullmatchRule:
|
|||||||
self.ignorecase = ignorecase
|
self.ignorecase = ignorecase
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"FullmatchRule(msg={self.msg}, ignorecase={self.ignorecase})"
|
return f"Fullmatch(msg={self.msg}, ignorecase={self.ignorecase})"
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
def __eq__(self, other: object) -> bool:
|
||||||
return (
|
return (
|
||||||
@ -286,7 +286,7 @@ class KeywordsRule:
|
|||||||
self.keywords = keywords
|
self.keywords = keywords
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"KeywordsRule(keywords={self.keywords})"
|
return f"Keywords(keywords={self.keywords})"
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
def __eq__(self, other: object) -> bool:
|
||||||
return isinstance(other, KeywordsRule) and frozenset(
|
return isinstance(other, KeywordsRule) and frozenset(
|
||||||
@ -327,7 +327,7 @@ class CommandRule:
|
|||||||
self.cmds = tuple(cmds)
|
self.cmds = tuple(cmds)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"CommandRule(cmds={self.cmds})"
|
return f"Command(cmds={self.cmds})"
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
def __eq__(self, other: object) -> bool:
|
||||||
return isinstance(other, CommandRule) and frozenset(self.cmds) == frozenset(
|
return isinstance(other, CommandRule) and frozenset(self.cmds) == frozenset(
|
||||||
@ -454,7 +454,7 @@ class ShellCommandRule:
|
|||||||
self.parser = parser
|
self.parser = parser
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"ShellCommandRule(cmds={self.cmds}, parser={self.parser})"
|
return f"ShellCommand(cmds={self.cmds}, parser={self.parser})"
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
def __eq__(self, other: object) -> bool:
|
||||||
return (
|
return (
|
||||||
@ -571,7 +571,7 @@ class RegexRule:
|
|||||||
self.flags = flags
|
self.flags = flags
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"RegexRule(regex={self.regex!r}, flags={self.flags})"
|
return f"Regex(regex={self.regex!r}, flags={self.flags})"
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
def __eq__(self, other: object) -> bool:
|
||||||
return (
|
return (
|
||||||
@ -630,7 +630,7 @@ class ToMeRule:
|
|||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return "ToMeRule()"
|
return "ToMe()"
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
def __eq__(self, other: object) -> bool:
|
||||||
return isinstance(other, ToMeRule)
|
return isinstance(other, ToMeRule)
|
||||||
@ -657,7 +657,7 @@ class IsTypeRule:
|
|||||||
self.types = types
|
self.types = types
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"IsTypeRule(types={tuple(type.__name__ for type in self.types)})"
|
return f"IsType(types={tuple(type.__name__ for type in self.types)})"
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
def __eq__(self, other: object) -> bool:
|
||||||
return isinstance(other, IsTypeRule) and self.types == other.types
|
return isinstance(other, IsTypeRule) and self.types == other.types
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
[report]
|
[report]
|
||||||
exclude_lines =
|
exclude_lines =
|
||||||
def __repr__
|
def __repr__
|
||||||
|
def __str__
|
||||||
pragma: no cover
|
pragma: no cover
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@(abc\.)?abstractmethod
|
@(abc\.)?abstractmethod
|
||||||
|
@ -61,7 +61,7 @@ async def test_get(monkeypatch: pytest.MonkeyPatch, nonebug_clear):
|
|||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
get_bot()
|
get_bot()
|
||||||
|
|
||||||
monkeypatch.setattr(driver, "_clients", {"test": "test"})
|
monkeypatch.setattr(driver, "_bots", {"test": "test"})
|
||||||
assert get_bot() == "test"
|
assert get_bot() == "test"
|
||||||
assert get_bot("test") == "test"
|
assert get_bot("test") == "test"
|
||||||
assert get_bots() == {"test": "test"}
|
assert get_bots() == {"test": "test"}
|
||||||
|
Loading…
Reference in New Issue
Block a user