🚨 Develop: 添加 ruff linter (#2114)

This commit is contained in:
Ju4tCode 2023-06-24 14:47:35 +08:00 committed by GitHub
parent fe21cbfa1d
commit 3d5dd5969c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 813 additions and 758 deletions

View File

@ -10,9 +10,11 @@
"settings": { "settings": {
"python.analysis.diagnosticMode": "workspace", "python.analysis.diagnosticMode": "workspace",
"python.analysis.typeCheckingMode": "basic", "python.analysis.typeCheckingMode": "basic",
"ruff.organizeImports": false,
"[python]": { "[python]": {
"editor.defaultFormatter": "ms-python.black-formatter", "editor.defaultFormatter": "ms-python.black-formatter",
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.ruff": true,
"source.organizeImports": true "source.organizeImports": true
} }
}, },
@ -44,6 +46,7 @@
"ms-python.vscode-pylance", "ms-python.vscode-pylance",
"ms-python.isort", "ms-python.isort",
"ms-python.black-formatter", "ms-python.black-formatter",
"charliermarsh.ruff",
"EditorConfig.EditorConfig", "EditorConfig.EditorConfig",
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss" "bradlc.vscode-tailwindcss"

21
.github/workflows/ruff.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: Ruff Lint
on:
push:
branches:
- master
pull_request:
paths:
- "nonebot/**"
- "packages/**"
- "tests/**"
jobs:
ruff:
name: Ruff Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Ruff Lint
uses: chartboost/ruff-action@v1

View File

@ -6,11 +6,12 @@ ci:
autoupdate_schedule: monthly autoupdate_schedule: monthly
autoupdate_commit_msg: ":arrow_up: auto update by pre-commit hooks" autoupdate_commit_msg: ":arrow_up: auto update by pre-commit hooks"
repos: repos:
- repo: https://github.com/hadialqattan/pycln - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v2.1.5 rev: v0.0.274
hooks: hooks:
- id: pycln - id: ruff
args: [--config, pyproject.toml] args: [--fix, --exit-non-zero-on-fix]
stages: [commit]
- repo: https://github.com/pycqa/isort - repo: https://github.com/pycqa/isort
rev: 5.12.0 rev: 5.12.0

View File

@ -24,12 +24,17 @@
- `load_all_plugins` => {ref}``load_all_plugins` <nonebot.plugin.load.load_all_plugins>` - `load_all_plugins` => {ref}``load_all_plugins` <nonebot.plugin.load.load_all_plugins>`
- `load_from_json` => {ref}``load_from_json` <nonebot.plugin.load.load_from_json>` - `load_from_json` => {ref}``load_from_json` <nonebot.plugin.load.load_from_json>`
- `load_from_toml` => {ref}``load_from_toml` <nonebot.plugin.load.load_from_toml>` - `load_from_toml` => {ref}``load_from_toml` <nonebot.plugin.load.load_from_toml>`
- `load_builtin_plugin` => {ref}``load_builtin_plugin` <nonebot.plugin.load.load_builtin_plugin>` - `load_builtin_plugin` =>
- `load_builtin_plugins` => {ref}``load_builtin_plugins` <nonebot.plugin.load.load_builtin_plugins>` {ref}``load_builtin_plugin` <nonebot.plugin.load.load_builtin_plugin>`
- `load_builtin_plugins` =>
{ref}``load_builtin_plugins` <nonebot.plugin.load.load_builtin_plugins>`
- `get_plugin` => {ref}``get_plugin` <nonebot.plugin.get_plugin>` - `get_plugin` => {ref}``get_plugin` <nonebot.plugin.get_plugin>`
- `get_plugin_by_module_name` => {ref}``get_plugin_by_module_name` <nonebot.plugin.get_plugin_by_module_name>` - `get_plugin_by_module_name` =>
- `get_loaded_plugins` => {ref}``get_loaded_plugins` <nonebot.plugin.get_loaded_plugins>` {ref}``get_plugin_by_module_name` <nonebot.plugin.get_plugin_by_module_name>`
- `get_available_plugin_names` => {ref}``get_available_plugin_names` <nonebot.plugin.get_available_plugin_names>` - `get_loaded_plugins` =>
{ref}``get_loaded_plugins` <nonebot.plugin.get_loaded_plugins>`
- `get_available_plugin_names` =>
{ref}``get_available_plugin_names` <nonebot.plugin.get_available_plugin_names>`
- `require` => {ref}``require` <nonebot.plugin.load.require>` - `require` => {ref}``require` <nonebot.plugin.load.require>`
FrontMatter: FrontMatter:
@ -69,7 +74,8 @@ def get_driver() -> Driver:
全局 {ref}`nonebot.drivers.Driver` 对象 全局 {ref}`nonebot.drivers.Driver` 对象
异常: 异常:
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用) ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化
({ref}`nonebot.init <nonebot.init>` 尚未调用)
用法: 用法:
```python ```python
@ -83,23 +89,33 @@ def get_driver() -> Driver:
@overload @overload
def get_adapter(name: str) -> Adapter: def get_adapter(name: str) -> Adapter:
... """
参数:
name: 适配器名称
返回:
指定名称的 {ref}`nonebot.adapters.Adapter` 对象
"""
@overload @overload
def get_adapter(name: Type[A]) -> A: def get_adapter(name: Type[A]) -> A:
... """
参数:
name: 适配器类型
返回:
指定类型的 {ref}`nonebot.adapters.Adapter` 对象
"""
def get_adapter(name: Union[str, Type[Adapter]]) -> Adapter: def get_adapter(name: Union[str, Type[Adapter]]) -> Adapter:
"""获取已注册的 {ref}`nonebot.adapters.Adapter` 实例。 """获取已注册的 {ref}`nonebot.adapters.Adapter` 实例。
返回:
指定名称或类型的 {ref}`nonebot.adapters.Adapter` 对象
异常: 异常:
ValueError: 指定的 {ref}`nonebot.adapters.Adapter` 未注册 ValueError: 指定的 {ref}`nonebot.adapters.Adapter` 未注册
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用) ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化
({ref}`nonebot.init <nonebot.init>` 尚未调用)
用法: 用法:
```python ```python
@ -121,7 +137,8 @@ def get_adapters() -> Dict[str, Adapter]:
所有 {ref}`nonebot.adapters.Adapter` 实例字典 所有 {ref}`nonebot.adapters.Adapter` 实例字典
异常: 异常:
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用) ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化
({ref}`nonebot.init <nonebot.init>` 尚未调用)
用法: 用法:
```python ```python
@ -139,7 +156,8 @@ def get_app() -> Any:
异常: 异常:
AssertionError: 全局 Driver 对象不是 {ref}`nonebot.drivers.ReverseDriver` 类型 AssertionError: 全局 Driver 对象不是 {ref}`nonebot.drivers.ReverseDriver` 类型
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用) ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化
({ref}`nonebot.init <nonebot.init>` 尚未调用)
用法: 用法:
```python ```python
@ -154,14 +172,16 @@ def get_app() -> Any:
def get_asgi() -> Any: def get_asgi() -> Any:
"""获取全局 {ref}`nonebot.drivers.ReverseDriver` 对应 [ASGI](https://asgi.readthedocs.io/) 对象。 """获取全局 {ref}`nonebot.drivers.ReverseDriver` 对应
[ASGI](https://asgi.readthedocs.io/) 对象
返回: 返回:
ASGI 对象 ASGI 对象
异常: 异常:
AssertionError: 全局 Driver 对象不是 {ref}`nonebot.drivers.ReverseDriver` 类型 AssertionError: 全局 Driver 对象不是 {ref}`nonebot.drivers.ReverseDriver` 类型
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用) ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化
({ref}`nonebot.init <nonebot.init>` 尚未调用)
用法: 用法:
```python ```python
@ -182,7 +202,8 @@ def get_bot(self_id: Optional[str] = None) -> Bot:
当不提供时返回一个 {ref}`nonebot.adapters.Bot` 当不提供时返回一个 {ref}`nonebot.adapters.Bot`
参数: 参数:
self_id: 用来识别 {ref}`nonebot.adapters.Bot` {ref}`nonebot.adapters.Bot.self_id` 属性 self_id: 用来识别 {ref}`nonebot.adapters.Bot`
{ref}`nonebot.adapters.Bot.self_id` 属性
返回: 返回:
{ref}`nonebot.adapters.Bot` 对象 {ref}`nonebot.adapters.Bot` 对象
@ -190,7 +211,8 @@ def get_bot(self_id: Optional[str] = None) -> Bot:
异常: 异常:
KeyError: 对应 self_id Bot 不存在 KeyError: 对应 self_id Bot 不存在
ValueError: 没有传入 self_id 且没有 Bot 可用 ValueError: 没有传入 self_id 且没有 Bot 可用
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用) ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化
({ref}`nonebot.init <nonebot.init>` 尚未调用)
用法: 用法:
```python ```python
@ -213,10 +235,12 @@ def get_bots() -> Dict[str, Bot]:
"""获取所有连接到 NoneBot 的 {ref}`nonebot.adapters.Bot` 对象。 """获取所有连接到 NoneBot 的 {ref}`nonebot.adapters.Bot` 对象。
返回: 返回:
一个以 {ref}`nonebot.adapters.Bot.self_id` 为键{ref}`nonebot.adapters.Bot` 对象为值的字典 一个以 {ref}`nonebot.adapters.Bot.self_id` 为键
{ref}`nonebot.adapters.Bot` 对象为值的字典
异常: 异常:
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用) ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化
({ref}`nonebot.init <nonebot.init>` 尚未调用)
用法: 用法:
```python ```python

View File

@ -1,13 +1,16 @@
"""本模块定义了 NoneBot 本身运行所需的配置项。 """本模块定义了 NoneBot 本身运行所需的配置项。
NoneBot 使用 [`pydantic`](https://pydantic-docs.helpmanual.io/) 以及 [`python-dotenv`](https://saurabh-kumar.com/python-dotenv/) 来读取配置 NoneBot 使用 [`pydantic`](https://pydantic-docs.helpmanual.io/) 以及
[`python-dotenv`](https://saurabh-kumar.com/python-dotenv/) 来读取配置
配置项需符合特殊格式或 json 序列化格式详情见 [`pydantic Field Type`](https://pydantic-docs.helpmanual.io/usage/types/) 文档 配置项需符合特殊格式或 json 序列化格式
详情见 [`pydantic Field Type`](https://pydantic-docs.helpmanual.io/usage/types/) 文档
FrontMatter: FrontMatter:
sidebar_position: 1 sidebar_position: 1
description: nonebot.config 模块 description: nonebot.config 模块
""" """
import os import os
from datetime import timedelta from datetime import timedelta
from ipaddress import IPv4Address from ipaddress import IPv4Address
@ -28,9 +31,8 @@ from nonebot.log import logger
class CustomEnvSettings(EnvSettingsSource): class CustomEnvSettings(EnvSettingsSource):
def __call__(self, settings: BaseSettings) -> Dict[str, Any]: def __call__(self, settings: BaseSettings) -> Dict[str, Any]:
""" """从环境变量和 dotenv 配置文件中读取配置项。"""
Build environment variables suitable for passing to the Model.
"""
d: Dict[str, Any] = {} d: Dict[str, Any] = {}
if settings.__config__.case_sensitive: if settings.__config__.case_sensitive:
@ -56,7 +58,8 @@ class CustomEnvSettings(EnvSettingsSource):
if env_val_built := self.explode_env_vars(field, env_vars): if env_val_built := self.explode_env_vars(field, env_vars):
d[field.alias] = env_val_built d[field.alias] = env_val_built
else: else:
# field is complex and there's a value, decode that as JSON, then add explode_env_vars # field is complex and there's a value
# decode that as JSON, then add explode_env_vars
try: try:
env_val = settings.__config__.parse_env_var(field.name, env_val) env_val = settings.__config__.parse_env_var(field.name, env_val)
except ValueError as e: except ValueError as e:
@ -72,7 +75,8 @@ class CustomEnvSettings(EnvSettingsSource):
else: else:
d[field.alias] = env_val d[field.alias] = env_val
elif env_val is not None: elif env_val is not None:
# simplest case, field is not complex, we only need to add the value if it was found # simplest case, field is not complex
# we only need to add the value if it was found
d[field.alias] = env_val d[field.alias] = env_val
# remain user custom config # remain user custom config
@ -82,7 +86,7 @@ class CustomEnvSettings(EnvSettingsSource):
# there's a value, decode that as JSON # there's a value, decode that as JSON
try: try:
env_val = settings.__config__.parse_env_var(env_name, val_striped) env_val = settings.__config__.parse_env_var(env_name, val_striped)
except ValueError as e: except ValueError:
logger.trace( logger.trace(
"Error while parsing JSON for " "Error while parsing JSON for "
f"{env_name!r}={val_striped!r}. " f"{env_name!r}={val_striped!r}. "
@ -139,7 +143,7 @@ class BaseConfig(BaseSettings):
class Env(BaseConfig): class Env(BaseConfig):
"""运行环境配置。大小写不敏感。 """运行环境配置。大小写不敏感。
将会从 `环境变量` > `.env 环境配置文件` 的优先级读取环境信息 将会从 **环境变量** > **dotenv 配置文件** 的优先级读取环境信息
""" """
environment: str = "prod" environment: str = "prod"
@ -170,15 +174,17 @@ class Config(BaseConfig):
配置格式为 `<module>[:<Driver>][+<module>[:<Mixin>]]*` 配置格式为 `<module>[:<Driver>][+<module>[:<Mixin>]]*`
`~` `nonebot.drivers.` 的缩写 `~` `nonebot.drivers.` 的缩写
配置方法参考: [配置驱动器](https://nonebot.dev/docs/advanced/driver#%E9%85%8D%E7%BD%AE%E9%A9%B1%E5%8A%A8%E5%99%A8)
""" """
host: IPvAnyAddress = IPv4Address("127.0.0.1") # type: ignore host: IPvAnyAddress = IPv4Address("127.0.0.1") # type: ignore
"""NoneBot {ref}`nonebot.drivers.ReverseDriver` 服务端监听的 IP/主机名。""" """NoneBot {ref}`nonebot.drivers.ReverseDriver` 服务端监听的 IP/主机名。"""
port: int = Field(default=8080, ge=1, le=65535) port: int = Field(default=8080, ge=1, le=65535)
"""NoneBot {ref}`nonebot.drivers.ReverseDriver` 服务端监听的端口。""" """NoneBot {ref}`nonebot.drivers.ReverseDriver` 服务端监听的端口。"""
log_level: Union[int, str] = "INFO" log_level: Union[int, str] = "INFO"
"""NoneBot 日志输出等级,可以为 `int` 类型等级或等级名称 """NoneBot 日志输出等级,可以为 `int` 类型等级或等级名称
参考 [`loguru 日志等级`](https://loguru.readthedocs.io/en/stable/api/logger.html#levels)。 参考 [记录日志](https://nonebot.dev/docs/appendices/log)[loguru 日志等级](https://loguru.readthedocs.io/en/stable/api/logger.html#levels)。
:::tip 提示 :::tip 提示
日志等级名称应为大写 `INFO` 日志等级名称应为大写 `INFO`
@ -209,6 +215,8 @@ class Config(BaseConfig):
command_start: Set[str] = {"/"} command_start: Set[str] = {"/"}
"""命令的起始标记,用于判断一条消息是不是命令。 """命令的起始标记,用于判断一条消息是不是命令。
参考[命令响应规则](https://nonebot.dev/docs/advanced/matcher#command)。
用法: 用法:
```conf ```conf
COMMAND_START=["/", ""] COMMAND_START=["/", ""]
@ -217,6 +225,8 @@ class Config(BaseConfig):
command_sep: Set[str] = {"."} command_sep: Set[str] = {"."}
"""命令的分隔标记,用于将文本形式的命令切分为元组(实际的命令名)。 """命令的分隔标记,用于将文本形式的命令切分为元组(实际的命令名)。
参考[命令响应规则](https://nonebot.dev/docs/advanced/matcher#command)。
用法: 用法:
```conf ```conf
COMMAND_SEP=["."] COMMAND_SEP=["."]

View File

@ -4,6 +4,7 @@ FrontMatter:
sidebar_position: 9 sidebar_position: 9
description: nonebot.consts 模块 description: nonebot.consts 模块
""" """
import os import os
import sys import sys
from typing import Literal from typing import Literal

View File

@ -82,8 +82,8 @@ class Dependent(Generic[R]):
""" """
call: _DependentCallable[R] call: _DependentCallable[R]
params: Tuple[ModelField] = field(default_factory=tuple) params: Tuple[ModelField, ...] = field(default_factory=tuple)
parameterless: Tuple[Param] = field(default_factory=tuple) parameterless: Tuple[Param, ...] = field(default_factory=tuple)
def __repr__(self) -> str: def __repr__(self) -> str:
if inspect.isfunction(self.call) or inspect.isclass(self.call): if inspect.isfunction(self.call) or inspect.isclass(self.call):
@ -129,7 +129,8 @@ class Dependent(Generic[R]):
break break
else: else:
raise ValueError( raise ValueError(
f"Unknown parameter {param.name} for function {call} with type {param.annotation}" f"Unknown parameter {param.name} "
f"for function {call} with type {param.annotation}"
) )
default_value = field_info.default default_value = field_info.default
@ -182,7 +183,7 @@ class Dependent(Generic[R]):
params = cls.parse_params(call, allow_types) params = cls.parse_params(call, allow_types)
parameterless_params = ( parameterless_params = (
tuple() ()
if parameterless is None if parameterless is None
else cls.parse_parameterless(tuple(parameterless), allow_types) else cls.parse_parameterless(tuple(parameterless), allow_types)
) )

View File

@ -3,6 +3,7 @@ FrontMatter:
sidebar_position: 1 sidebar_position: 1
description: nonebot.dependencies.utils 模块 description: nonebot.dependencies.utils 模块
""" """
import inspect import inspect
from typing import Any, Dict, TypeVar, Callable, ForwardRef from typing import Any, Dict, TypeVar, Callable, ForwardRef
@ -17,6 +18,7 @@ V = TypeVar("V")
def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature: def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
"""获取可调用对象签名""" """获取可调用对象签名"""
signature = inspect.signature(call) signature = inspect.signature(call)
globalns = getattr(call, "__globals__", {}) globalns = getattr(call, "__globals__", {})
typed_params = [ typed_params = [
@ -33,6 +35,7 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any: def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any:
"""获取参数的类型注解""" """获取参数的类型注解"""
annotation = param.annotation annotation = param.annotation
if isinstance(annotation, str): if isinstance(annotation, str):
annotation = ForwardRef(annotation) annotation = ForwardRef(annotation)
@ -47,6 +50,8 @@ def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) ->
def check_field_type(field: ModelField, value: V) -> V: def check_field_type(field: ModelField, value: V) -> V:
"""检查字段类型是否匹配"""
_, errs_ = field.validate(value, {}, loc=()) _, errs_ = field.validate(value, {}, loc=())
if errs_: if errs_:
raise TypeMisMatch(field, value) raise TypeMisMatch(field, value)

View File

@ -1,10 +1,11 @@
from typing_extensions import TypeAlias
from typing import Any, List, Union, Callable, Awaitable, cast from typing import Any, List, Union, Callable, Awaitable, cast
from nonebot.utils import run_sync, is_coroutine_callable from nonebot.utils import run_sync, is_coroutine_callable
SYNC_LIFESPAN_FUNC = Callable[[], Any] SYNC_LIFESPAN_FUNC: TypeAlias = Callable[[], Any]
ASYNC_LIFESPAN_FUNC = Callable[[], Awaitable[Any]] ASYNC_LIFESPAN_FUNC: TypeAlias = Callable[[], Awaitable[Any]]
LIFESPAN_FUNC = Union[SYNC_LIFESPAN_FUNC, ASYNC_LIFESPAN_FUNC] LIFESPAN_FUNC: TypeAlias = Union[SYNC_LIFESPAN_FUNC, ASYNC_LIFESPAN_FUNC]
class Lifespan: class Lifespan:

View File

@ -29,7 +29,8 @@ try:
import aiohttp import aiohttp
except ModuleNotFoundError as e: # pragma: no cover except ModuleNotFoundError as e: # 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. "
"Install with pip: `pip install nonebot2[aiohttp]`"
) from e ) from e

View File

@ -41,7 +41,8 @@ try:
from starlette.websockets import WebSocket, WebSocketState, WebSocketDisconnect from starlette.websockets import WebSocket, WebSocketState, WebSocketDisconnect
except ModuleNotFoundError as e: # pragma: no cover except ModuleNotFoundError as e: # pragma: no cover
raise ImportError( raise ImportError(
"Please install FastAPI by using `pip install nonebot2[fastapi]`" "Please install FastAPI first to use this driver. "
"Install with pip: `pip install nonebot2[fastapi]`"
) from e ) from e
@ -90,7 +91,7 @@ class Driver(ReverseDriver):
"""FastAPI 驱动框架。""" """FastAPI 驱动框架。"""
def __init__(self, env: Env, config: NoneBotConfig): def __init__(self, env: Env, config: NoneBotConfig):
super(Driver, self).__init__(env, config) super().__init__(env, config)
self.fastapi_config: Config = Config(**config.dict()) self.fastapi_config: Config = Config(**config.dict())

View File

@ -14,6 +14,7 @@ FrontMatter:
sidebar_position: 3 sidebar_position: 3
description: nonebot.drivers.httpx 模块 description: nonebot.drivers.httpx 模块
""" """
from typing import Type, AsyncGenerator from typing import Type, AsyncGenerator
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
@ -33,7 +34,8 @@ try:
import httpx import httpx
except ModuleNotFoundError as e: # pragma: no cover except ModuleNotFoundError as e: # pragma: no cover
raise ImportError( raise ImportError(
"Please install httpx by using `pip install nonebot2[httpx]`" "Please install httpx first to use this driver. "
"Install with pip: `pip install nonebot2[httpx]`"
) from e ) from e

View File

@ -9,7 +9,6 @@ FrontMatter:
description: nonebot.drivers.none 模块 description: nonebot.drivers.none 模块
""" """
import signal import signal
import asyncio import asyncio
import threading import threading

View File

@ -39,7 +39,8 @@ try:
from quart import Websocket as QuartWebSocket from quart import Websocket as QuartWebSocket
except ModuleNotFoundError as e: # pragma: no cover except ModuleNotFoundError as e: # pragma: no cover
raise ImportError( raise ImportError(
"Please install Quart by using `pip install nonebot2[quart]`" "Please install Quart first to use this driver. "
"Install with pip: `pip install nonebot2[quart]`"
) from e ) from e
_AsyncCallable = TypeVar("_AsyncCallable", bound=Callable[..., Coroutine]) _AsyncCallable = TypeVar("_AsyncCallable", bound=Callable[..., Coroutine])
@ -188,9 +189,7 @@ class Driver(ReverseDriver):
async def _handle_http(self, setup: HTTPServerSetup) -> Response: async def _handle_http(self, setup: HTTPServerSetup) -> Response:
request: Request = _request request: Request = _request
json = None json = await request.get_json() if request.is_json else None
if request.is_json:
json = await request.get_json()
data = await request.form data = await request.form
files_dict = await request.files files_dict = await request.files

View File

@ -14,10 +14,12 @@ FrontMatter:
sidebar_position: 4 sidebar_position: 4
description: nonebot.drivers.websockets 模块 description: nonebot.drivers.websockets 模块
""" """
import logging import logging
from functools import wraps from functools import wraps
from typing_extensions import ParamSpec
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from typing import Type, Union, AsyncGenerator from typing import Type, Union, TypeVar, Callable, Awaitable, AsyncGenerator
from nonebot.typing import overrides from nonebot.typing import overrides
from nonebot.log import LoguruHandler from nonebot.log import LoguruHandler
@ -32,16 +34,20 @@ try:
from websockets.legacy.client import Connect, WebSocketClientProtocol from websockets.legacy.client import Connect, WebSocketClientProtocol
except ModuleNotFoundError as e: # pragma: no cover except ModuleNotFoundError as e: # pragma: no cover
raise ImportError( raise ImportError(
"Please install websockets by using `pip install nonebot2[websockets]`" "Please install websockets first to use this driver. "
"Install with pip: `pip install nonebot2[websockets]`"
) from e ) from e
T = TypeVar("T")
P = ParamSpec("P")
logger = logging.Logger("websockets.client", "INFO") logger = logging.Logger("websockets.client", "INFO")
logger.addHandler(LoguruHandler()) logger.addHandler(LoguruHandler())
def catch_closed(func): def catch_closed(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]:
@wraps(func) @wraps(func)
async def decorator(*args, **kwargs): async def decorator(*args: P.args, **kwargs: P.kwargs) -> T:
try: try:
return await func(*args, **kwargs) return await func(*args, **kwargs)
except ConnectionClosed as e: except ConnectionClosed as e:

View File

@ -43,9 +43,9 @@ class NoneBotException(Exception):
# Rule Exception # Rule Exception
class ParserExit(NoneBotException): class ParserExit(NoneBotException):
"""{ref}`nonebot.rule.shell_command` 处理消息失败时返回的异常""" """{ref}`nonebot.rule.shell_command` 处理消息失败时返回的异常"""
def __init__(self, status: int = 0, message: Optional[str] = None): def __init__(self, status: int = 0, message: Optional[str] = None) -> None:
self.status = status self.status = status
self.message = message self.message = message
@ -69,7 +69,7 @@ class IgnoredException(ProcessException):
reason: 忽略事件的原因 reason: 忽略事件的原因
""" """
def __init__(self, reason: Any): def __init__(self, reason: Any) -> None:
self.reason: Any = reason self.reason: Any = reason
def __repr__(self) -> str: def __repr__(self) -> str:
@ -96,7 +96,7 @@ class SkippedException(ProcessException):
class TypeMisMatch(SkippedException): class TypeMisMatch(SkippedException):
"""当前 `Handler` 的参数类型不匹配。""" """当前 `Handler` 的参数类型不匹配。"""
def __init__(self, param: ModelField, value: Any): def __init__(self, param: ModelField, value: Any) -> None:
self.param: ModelField = param self.param: ModelField = param
self.value: Any = value self.value: Any = value
@ -108,7 +108,8 @@ class TypeMisMatch(SkippedException):
class MockApiException(ProcessException): class MockApiException(ProcessException):
"""指示 NoneBot 阻止本次 API 调用或修改本次调用返回值,并返回自定义内容。可由 api hook 抛出。 """指示 NoneBot 阻止本次 API 调用或修改本次调用返回值,并返回自定义内容。
可由 api hook 抛出
参数: 参数:
result: 返回的内容 result: 返回的内容
@ -144,7 +145,8 @@ class MatcherException(NoneBotException):
class PausedException(MatcherException): class PausedException(MatcherException):
"""指示 NoneBot 结束当前 `Handler` 并等待下一条消息后继续下一个 `Handler`。可用于用户输入新信息。 """指示 NoneBot 结束当前 `Handler` 并等待下一条消息后继续下一个 `Handler`。
可用于用户输入新信息
可以在 `Handler` 中通过 {ref}`nonebot.matcher.Matcher.pause` 抛出 可以在 `Handler` 中通过 {ref}`nonebot.matcher.Matcher.pause` 抛出
@ -158,7 +160,8 @@ class PausedException(MatcherException):
class RejectedException(MatcherException): class RejectedException(MatcherException):
"""指示 NoneBot 结束当前 `Handler` 并等待下一条消息后重新运行当前 `Handler`。可用于用户重新输入。 """指示 NoneBot 结束当前 `Handler` 并等待下一条消息后重新运行当前 `Handler`。
可用于用户重新输入
可以在 `Handler` 中通过 {ref}`nonebot.matcher.Matcher.reject` 抛出 可以在 `Handler` 中通过 {ref}`nonebot.matcher.Matcher.reject` 抛出
@ -187,7 +190,7 @@ class FinishedException(MatcherException):
# Adapter Exceptions # Adapter Exceptions
class AdapterException(NoneBotException): class AdapterException(NoneBotException):
"""代表 `Adapter` 抛出的异常,所有的 `Adapter` 都要在内部继承自这个 `Exception` """代表 `Adapter` 抛出的异常,所有的 `Adapter` 都要在内部继承自这个 `Exception`
参数: 参数:
adapter_name: 标识 adapter adapter_name: 标识 adapter
@ -210,7 +213,9 @@ class ApiNotAvailable(AdapterException):
class NetworkError(AdapterException): class NetworkError(AdapterException):
"""在网络出现问题时抛出,如: API 请求地址不正确, API 请求无返回或返回状态非正常等。""" """在网络出现问题时抛出,
: API 请求地址不正确, API 请求无返回或返回状态非正常等
"""
class ActionFailed(AdapterException): class ActionFailed(AdapterException):
@ -219,13 +224,13 @@ class ActionFailed(AdapterException):
# Driver Exceptions # Driver Exceptions
class DriverException(NoneBotException): class DriverException(NoneBotException):
"""`Driver` 抛出的异常基类""" """`Driver` 抛出的异常基类"""
class WebSocketClosed(DriverException): class WebSocketClosed(DriverException):
"""WebSocket 连接已关闭""" """WebSocket 连接已关闭"""
def __init__(self, code: int, reason: Optional[str] = None): def __init__(self, code: int, reason: Optional[str] = None) -> None:
self.code = code self.code = code
self.reason = reason self.reason = reason

View File

@ -44,10 +44,11 @@ class Event(abc.ABC, BaseModel):
def get_log_string(self) -> str: def get_log_string(self) -> str:
"""获取事件日志信息的方法。 """获取事件日志信息的方法。
通常你不需要修改这个方法只有当希望 NoneBot 隐藏该事件日志时可以抛出 `NoLogException` 异常 通常你不需要修改这个方法只有当希望 NoneBot 隐藏该事件日志时
可以抛出 `NoLogException` 异常
异常: 异常:
NoLogException: NoLogException: 希望 NoneBot 隐藏该事件日志
""" """
return f"[{self.get_event_name()}]: {self.get_event_description()}" return f"[{self.get_event_name()}]: {self.get_event_description()}"
@ -58,7 +59,9 @@ class Event(abc.ABC, BaseModel):
@abc.abstractmethod @abc.abstractmethod
def get_session_id(self) -> str: def get_session_id(self) -> str:
"""获取会话 id 的方法,用于判断当前事件属于哪一个会话,通常是用户 id、群组 id 组合。""" """获取会话 id 的方法,用于判断当前事件属于哪一个会话,
通常是用户 id群组 id 组合
"""
raise NotImplementedError raise NotImplementedError
@abc.abstractmethod @abc.abstractmethod

View File

@ -98,7 +98,7 @@ class MessageSegment(abc.ABC, Generic[TM]):
class Message(List[TMS], abc.ABC): class Message(List[TMS], abc.ABC):
"""消息数组 """消息序列
参数: 参数:
message: 消息内容 message: 消息内容
@ -124,9 +124,9 @@ class Message(List[TMS], abc.ABC):
def template(cls, format_string: Union[str, TM]) -> MessageTemplate[Self]: def template(cls, format_string: Union[str, TM]) -> MessageTemplate[Self]:
"""创建消息模板。 """创建消息模板。
用法和 `str.format` 大致相同, 但是可以输出消息对象, 并且支持以 `Message` 对象作为消息模板 用法和 `str.format` 大致相同支持以 `Message` 对象作为消息模板并输出消息对象
并且提供了拓展的格式化控制符
并且提供了拓展的格式化控制符, 可以用适用于该消息类型的 `MessageSegment` 工厂方法创建消息 可以通过该消息类型的 `MessageSegment` 工厂方法创建消息
参数: 参数:
format_string: 格式化模板 format_string: 格式化模板

View File

@ -1,5 +1,6 @@
import functools import functools
from string import Formatter from string import Formatter
from typing_extensions import TypeAlias
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Any, Any,
@ -25,7 +26,7 @@ if TYPE_CHECKING:
TM = TypeVar("TM", bound="Message") TM = TypeVar("TM", bound="Message")
TF = TypeVar("TF", str, "Message") TF = TypeVar("TF", str, "Message")
FormatSpecFunc = Callable[[Any], str] FormatSpecFunc: TypeAlias = Callable[[Any], str]
FormatSpecFunc_T = TypeVar("FormatSpecFunc_T", bound=FormatSpecFunc) FormatSpecFunc_T = TypeVar("FormatSpecFunc_T", bound=FormatSpecFunc)

View File

@ -89,9 +89,7 @@ class Driver(abc.ABC):
@abc.abstractmethod @abc.abstractmethod
def run(self, *args, **kwargs): def run(self, *args, **kwargs):
""" """启动驱动框架"""
启动驱动框架
"""
logger.opt(colors=True).debug( logger.opt(colors=True).debug(
f"<g>Loaded adapters: {escape_tag(', '.join(self._adapters))}</g>" f"<g>Loaded adapters: {escape_tag(', '.join(self._adapters))}</g>"
) )
@ -152,8 +150,10 @@ class Driver(abc.ABC):
await asyncio.gather(*coros) await asyncio.gather(*coros)
except Exception as e: except Exception as e:
logger.opt(colors=True, exception=e).error( logger.opt(colors=True, exception=e).error(
"<r><bg #f8bbd0>Error when running WebSocketConnection hook. " "<r><bg #f8bbd0>"
"Running cancelled!</bg #f8bbd0></r>" "Error when running WebSocketConnection hook. "
"Running cancelled!"
"</bg #f8bbd0></r>"
) )
asyncio.create_task(_run_hook(bot)) asyncio.create_task(_run_hook(bot))
@ -177,8 +177,10 @@ class Driver(abc.ABC):
await asyncio.gather(*coros) await asyncio.gather(*coros)
except Exception as e: except Exception as e:
logger.opt(colors=True, exception=e).error( logger.opt(colors=True, exception=e).error(
"<r><bg #f8bbd0>Error when running WebSocketDisConnection hook. " "<r><bg #f8bbd0>"
"Running cancelled!</bg #f8bbd0></r>" "Error when running WebSocketDisConnection hook. "
"Running cancelled!"
"</bg #f8bbd0></r>"
) )
asyncio.create_task(_run_hook(bot)) asyncio.create_task(_run_hook(bot))
@ -241,7 +243,7 @@ def combine_driver(driver: Type[Driver], *mixins: Type[ForwardMixin]) -> Type[Dr
# check first # check first
assert issubclass(driver, Driver), "`driver` must be subclass of Driver" assert issubclass(driver, Driver), "`driver` must be subclass of Driver"
assert all( assert all(
map(lambda m: issubclass(m, ForwardMixin), mixins) issubclass(m, ForwardMixin) for m in mixins
), "`mixins` must be subclass of ForwardMixin" ), "`mixins` must be subclass of ForwardMixin"
if not mixins: if not mixins:
@ -251,7 +253,9 @@ def combine_driver(driver: Type[Driver], *mixins: Type[ForwardMixin]) -> Type[Dr
return ( return (
driver.type.__get__(self) driver.type.__get__(self)
+ "+" + "+"
+ "+".join(map(lambda x: x.type.__get__(self), mixins)) + "+".join(x.type.__get__(self) for x in mixins)
) )
return type("CombinedDriver", (*mixins, driver, ForwardDriver), {"type": property(type_)}) # type: ignore return type(
"CombinedDriver", (*mixins, driver, ForwardDriver), {"type": property(type_)}
) # type: ignore

View File

@ -2,6 +2,7 @@ import abc
import urllib.request import urllib.request
from enum import Enum from enum import Enum
from dataclasses import dataclass from dataclasses import dataclass
from typing_extensions import TypeAlias
from http.cookiejar import Cookie, CookieJar from http.cookiejar import Cookie, CookieJar
from typing import ( from typing import (
IO, IO,
@ -21,28 +22,30 @@ from typing import (
from yarl import URL as URL from yarl import URL as URL
from multidict import CIMultiDict from multidict import CIMultiDict
RawURL = Tuple[bytes, bytes, Optional[int], bytes] RawURL: TypeAlias = Tuple[bytes, bytes, Optional[int], bytes]
SimpleQuery = Union[str, int, float] SimpleQuery: TypeAlias = Union[str, int, float]
QueryVariable = Union[SimpleQuery, List[SimpleQuery]] QueryVariable: TypeAlias = Union[SimpleQuery, List[SimpleQuery]]
QueryTypes = Union[ QueryTypes: TypeAlias = Union[
None, str, Mapping[str, QueryVariable], List[Tuple[str, QueryVariable]] None, str, Mapping[str, QueryVariable], List[Tuple[str, QueryVariable]]
] ]
HeaderTypes = Union[ HeaderTypes: TypeAlias = Union[
None, None,
CIMultiDict[str], CIMultiDict[str],
Dict[str, str], Dict[str, str],
List[Tuple[str, str]], List[Tuple[str, str]],
] ]
CookieTypes = Union[None, "Cookies", CookieJar, Dict[str, str], List[Tuple[str, str]]] CookieTypes: TypeAlias = Union[
None, "Cookies", CookieJar, Dict[str, str], List[Tuple[str, str]]
]
ContentTypes = Union[str, bytes, None] ContentTypes: TypeAlias = Union[str, bytes, None]
DataTypes = Union[dict, None] DataTypes: TypeAlias = Union[dict, None]
FileContent = Union[IO[bytes], bytes] FileContent: TypeAlias = Union[IO[bytes], bytes]
FileType = Tuple[Optional[str], FileContent, Optional[str]] FileType: TypeAlias = Tuple[Optional[str], FileContent, Optional[str]]
FileTypes = Union[ FileTypes: TypeAlias = Union[
# file (or bytes) # file (or bytes)
FileContent, FileContent,
# (filename, file (or bytes)) # (filename, file (or bytes))
@ -50,7 +53,7 @@ FileTypes = Union[
# (filename, file (or bytes), content_type) # (filename, file (or bytes), content_type)
FileType, FileType,
] ]
FilesTypes = Union[Dict[str, FileTypes], List[Tuple[str, FileTypes]], None] FilesTypes: TypeAlias = Union[Dict[str, FileTypes], List[Tuple[str, FileTypes]], None]
class HTTPVersion(Enum): class HTTPVersion(Enum):
@ -160,7 +163,6 @@ class Response:
class WebSocket(abc.ABC): class WebSocket(abc.ABC):
def __init__(self, *, request: Request): def __init__(self, *, request: Request):
# request
self.request: Request = request self.request: Request = request
def __repr__(self) -> str: def __repr__(self) -> str:
@ -169,9 +171,7 @@ class WebSocket(abc.ABC):
@property @property
@abc.abstractmethod @abc.abstractmethod
def closed(self) -> bool: def closed(self) -> bool:
""" """连接是否已经关闭"""
连接是否已经关闭
"""
raise NotImplementedError raise NotImplementedError
@abc.abstractmethod @abc.abstractmethod

View File

@ -29,6 +29,13 @@ from nonebot.internal.adapter import (
MessageSegment, MessageSegment,
MessageTemplate, MessageTemplate,
) )
from nonebot.typing import (
T_State,
T_Handler,
T_TypeUpdater,
T_DependencyCache,
T_PermissionUpdater,
)
from nonebot.consts import ( from nonebot.consts import (
ARG_KEY, ARG_KEY,
RECEIVE_KEY, RECEIVE_KEY,
@ -36,14 +43,6 @@ from nonebot.consts import (
LAST_RECEIVE_KEY, LAST_RECEIVE_KEY,
REJECT_CACHE_TARGET, REJECT_CACHE_TARGET,
) )
from nonebot.typing import (
Any,
T_State,
T_Handler,
T_TypeUpdater,
T_DependencyCache,
T_PermissionUpdater,
)
from nonebot.exception import ( from nonebot.exception import (
PausedException, PausedException,
StopPropagation, StopPropagation,
@ -376,7 +375,7 @@ class Matcher(metaclass=MatcherMeta):
return return
await matcher.reject() await matcher.reject()
_parameterless = (Depends(_receive), *(parameterless or tuple())) _parameterless = (Depends(_receive), *(parameterless or ()))
def _decorator(func: T_Handler) -> T_Handler: def _decorator(func: T_Handler) -> T_Handler:
if cls.handlers and cls.handlers[-1].call is func: if cls.handlers and cls.handlers[-1].call is func:
@ -406,7 +405,8 @@ class Matcher(metaclass=MatcherMeta):
) -> Callable[[T_Handler], T_Handler]: ) -> Callable[[T_Handler], T_Handler]:
"""装饰一个函数来指示 NoneBot 获取一个参数 `key` """装饰一个函数来指示 NoneBot 获取一个参数 `key`
当要获取的 `key` 不存在时接收用户新的一条消息再运行该函数如果 `key` 已存在则直接继续运行 当要获取的 `key` 不存在时接收用户新的一条消息再运行该函数
如果 `key` 已存在则直接继续运行
参数: 参数:
key: 参数名 key: 参数名
@ -423,7 +423,7 @@ class Matcher(metaclass=MatcherMeta):
return return
await matcher.reject(prompt) await matcher.reject(prompt)
_parameterless = (Depends(_key_getter), *(parameterless or tuple())) _parameterless = (Depends(_key_getter), *(parameterless or ()))
def _decorator(func: T_Handler) -> T_Handler: def _decorator(func: T_Handler) -> T_Handler:
if cls.handlers and cls.handlers[-1].call is func: if cls.handlers and cls.handlers[-1].call is func:
@ -454,7 +454,8 @@ class Matcher(metaclass=MatcherMeta):
参数: 参数:
message: 消息内容 message: 消息内容
kwargs: {ref}`nonebot.adapters.Bot.send` 的参数请参考对应 adapter bot 对象 api kwargs: {ref}`nonebot.adapters.Bot.send` 的参数
请参考对应 adapter bot 对象 api
""" """
bot = current_bot.get() bot = current_bot.get()
event = current_event.get() event = current_event.get()
@ -475,7 +476,8 @@ class Matcher(metaclass=MatcherMeta):
参数: 参数:
message: 消息内容 message: 消息内容
kwargs: {ref}`nonebot.adapters.Bot.send` 的参数请参考对应 adapter bot 对象 api kwargs: {ref}`nonebot.adapters.Bot.send` 的参数
请参考对应 adapter bot 对象 api
""" """
if message is not None: if message is not None:
await cls.send(message, **kwargs) await cls.send(message, **kwargs)
@ -491,7 +493,8 @@ class Matcher(metaclass=MatcherMeta):
参数: 参数:
prompt: 消息内容 prompt: 消息内容
kwargs: {ref}`nonebot.adapters.Bot.send` 的参数请参考对应 adapter bot 对象 api kwargs: {ref}`nonebot.adapters.Bot.send` 的参数
请参考对应 adapter bot 对象 api
""" """
if prompt is not None: if prompt is not None:
await cls.send(prompt, **kwargs) await cls.send(prompt, **kwargs)
@ -508,7 +511,8 @@ class Matcher(metaclass=MatcherMeta):
参数: 参数:
prompt: 消息内容 prompt: 消息内容
kwargs: {ref}`nonebot.adapters.Bot.send` 的参数请参考对应 adapter bot 对象 api kwargs: {ref}`nonebot.adapters.Bot.send` 的参数
请参考对应 adapter bot 对象 api
""" """
if prompt is not None: if prompt is not None:
await cls.send(prompt, **kwargs) await cls.send(prompt, **kwargs)
@ -527,7 +531,8 @@ class Matcher(metaclass=MatcherMeta):
参数: 参数:
key: 参数名 key: 参数名
prompt: 消息内容 prompt: 消息内容
kwargs: {ref}`nonebot.adapters.Bot.send` 的参数请参考对应 adapter bot 对象 api kwargs: {ref}`nonebot.adapters.Bot.send` 的参数
请参考对应 adapter bot 对象 api
""" """
matcher = current_matcher.get() matcher = current_matcher.get()
matcher.set_target(ARG_KEY.format(key=key)) matcher.set_target(ARG_KEY.format(key=key))
@ -548,7 +553,8 @@ class Matcher(metaclass=MatcherMeta):
参数: 参数:
id: 消息 id id: 消息 id
prompt: 消息内容 prompt: 消息内容
kwargs: {ref}`nonebot.adapters.Bot.send` 的参数请参考对应 adapter bot 对象 api kwargs: {ref}`nonebot.adapters.Bot.send` 的参数
请参考对应 adapter bot 对象 api
""" """
matcher = current_matcher.get() matcher = current_matcher.get()
matcher.set_target(RECEIVE_KEY.format(id=id)) matcher.set_target(RECEIVE_KEY.format(id=id))

View File

@ -63,7 +63,10 @@ def Depends(
finally: finally:
... ...
async def handler(param_name: Any = Depends(depend_func), gen: Any = Depends(depend_gen_func)): async def handler(
param_name: Any = Depends(depend_func),
gen: Any = Depends(depend_gen_func),
):
... ...
``` ```
""" """

View File

@ -88,5 +88,6 @@ logger_id = logger.add(
filter=default_filter, filter=default_filter,
format=default_format, format=default_format,
) )
"""默认日志处理器 id"""
__autodoc__ = {"logger_id": False} __autodoc__ = {"logger_id": False}

View File

@ -166,7 +166,7 @@ async def _apply_event_preprocessors(
for proc in _event_preprocessors for proc in _event_preprocessors
) )
) )
except IgnoredException as e: except IgnoredException:
logger.opt(colors=True).info( logger.opt(colors=True).info(
f"Event {escape_tag(event.get_event_name())} is <b>ignored</b>" f"Event {escape_tag(event.get_event_name())} is <b>ignored</b>"
) )
@ -293,7 +293,7 @@ async def _apply_run_postprocessors(
) -> None: ) -> None:
"""运行事件响应器运行后处理。 """运行事件响应器运行后处理。
Args: 参数:
bot: Bot 对象 bot: Bot 对象
event: Event 对象 event: Event 对象
matcher: 事件响应器 matcher: 事件响应器

View File

@ -1,7 +1,8 @@
"""本模块是 {ref}`nonebot.matcher.Matcher.permission` 的类型定义。 """本模块是 {ref}`nonebot.matcher.Matcher.permission` 的类型定义。
每个 {ref}`nonebot.matcher.Matcher` 拥有一个 {ref}`nonebot.permission.Permission` 每个{ref}`事件响应器 <nonebot.matcher.Matcher>`
其中是 `PermissionChecker` 的集合只要有一个 `PermissionChecker` 检查结果为 `True` 时就会继续运行 拥有一个 {ref}`nonebot.permission.Permission`其中是 `PermissionChecker` 的集合
只要有一个 `PermissionChecker` 检查结果为 `True` 时就会继续运行
FrontMatter: FrontMatter:
sidebar_position: 6 sidebar_position: 6

View File

@ -24,8 +24,10 @@
- `load_all_plugins` => {ref}``load_all_plugins` <nonebot.plugin.load.load_all_plugins>` - `load_all_plugins` => {ref}``load_all_plugins` <nonebot.plugin.load.load_all_plugins>`
- `load_from_json` => {ref}``load_from_json` <nonebot.plugin.load.load_from_json>` - `load_from_json` => {ref}``load_from_json` <nonebot.plugin.load.load_from_json>`
- `load_from_toml` => {ref}``load_from_toml` <nonebot.plugin.load.load_from_toml>` - `load_from_toml` => {ref}``load_from_toml` <nonebot.plugin.load.load_from_toml>`
- `load_builtin_plugin` => {ref}``load_builtin_plugin` <nonebot.plugin.load.load_builtin_plugin>` - `load_builtin_plugin` =>
- `load_builtin_plugins` => {ref}``load_builtin_plugins` <nonebot.plugin.load.load_builtin_plugins>` {ref}``load_builtin_plugin` <nonebot.plugin.load.load_builtin_plugin>`
- `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>` - `PluginMetadata` => {ref}``PluginMetadata` <nonebot.plugin.plugin.PluginMetadata>`
@ -42,7 +44,7 @@ from typing import Set, Dict, List, Tuple, Optional
_plugins: Dict[str, "Plugin"] = {} _plugins: Dict[str, "Plugin"] = {}
_managers: List["PluginManager"] = [] _managers: List["PluginManager"] = []
_current_plugin_chain: ContextVar[Tuple["Plugin", ...]] = ContextVar( _current_plugin_chain: ContextVar[Tuple["Plugin", ...]] = ContextVar(
"_current_plugin_chain", default=tuple() "_current_plugin_chain", default=()
) )

View File

@ -4,6 +4,7 @@ FrontMatter:
sidebar_position: 1 sidebar_position: 1
description: nonebot.plugin.load 模块 description: nonebot.plugin.load 模块
""" """
import json import json
from pathlib import Path from pathlib import Path
from types import ModuleType from types import ModuleType
@ -25,7 +26,8 @@ def load_plugin(module_path: Union[str, Path]) -> Optional[Plugin]:
"""加载单个插件,可以是本地插件或是通过 `pip` 安装的插件。 """加载单个插件,可以是本地插件或是通过 `pip` 安装的插件。
参数: 参数:
module_path: 插件名称 `path.to.your.plugin` 或插件路径 `pathlib.Path(path/to/your/plugin)` module_path: 插件名称 `path.to.your.plugin`
或插件路径 `pathlib.Path(path/to/your/plugin)`
""" """
module_path = ( module_path = (
path_to_module_name(module_path) path_to_module_name(module_path)
@ -63,7 +65,8 @@ def load_all_plugins(
def load_from_json(file_path: str, encoding: str = "utf-8") -> Set[Plugin]: def load_from_json(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
"""导入指定 json 文件中的 `plugins` 以及 `plugin_dirs` 下多个插件,以 `_` 开头的插件不会被导入! """导入指定 json 文件中的 `plugins` 以及 `plugin_dirs` 下多个插件。
`_` 开头的插件不会被导入!
参数: 参数:
file_path: 指定 json 文件路径 file_path: 指定 json 文件路径
@ -81,7 +84,7 @@ def load_from_json(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
nonebot.load_from_json("plugins.json") nonebot.load_from_json("plugins.json")
``` ```
""" """
with open(file_path, "r", encoding=encoding) as f: with open(file_path, encoding=encoding) as f:
data = json.load(f) data = json.load(f)
if not isinstance(data, dict): if not isinstance(data, dict):
raise TypeError("json file must contains a dict!") raise TypeError("json file must contains a dict!")
@ -93,7 +96,9 @@ def load_from_json(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
def load_from_toml(file_path: str, encoding: str = "utf-8") -> Set[Plugin]: def load_from_toml(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
"""导入指定 toml 文件 `[tool.nonebot]` 中的 `plugins` 以及 `plugin_dirs` 下多个插件,以 `_` 开头的插件不会被导入! """导入指定 toml 文件 `[tool.nonebot]` 中的
`plugins` 以及 `plugin_dirs` 下多个插件
`_` 开头的插件不会被导入!
参数: 参数:
file_path: 指定 toml 文件路径 file_path: 指定 toml 文件路径
@ -110,7 +115,7 @@ def load_from_toml(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
nonebot.load_from_toml("pyproject.toml") nonebot.load_from_toml("pyproject.toml")
``` ```
""" """
with open(file_path, "r", encoding=encoding) as f: with open(file_path, encoding=encoding) as f:
data = tomllib.loads(f.read()) data = tomllib.loads(f.read())
nonebot_data = data.get("tool", {}).get("nonebot") nonebot_data = data.get("tool", {}).get("nonebot")

View File

@ -6,6 +6,7 @@ FrontMatter:
sidebar_position: 5 sidebar_position: 5
description: nonebot.plugin.manager 模块 description: nonebot.plugin.manager 模块
""" """
import sys import sys
import pkgutil import pkgutil
import importlib import importlib

View File

@ -4,6 +4,7 @@ FrontMatter:
sidebar_position: 2 sidebar_position: 2
description: nonebot.plugin.on 模块 description: nonebot.plugin.on 模块
""" """
import re import re
import inspect import inspect
from types import ModuleType from types import ModuleType
@ -322,7 +323,8 @@ def on_shell_command(
与普通的 `on_command` 不同的是在添加 `parser` 参数时, 响应器会自动处理消息 与普通的 `on_command` 不同的是在添加 `parser` 参数时, 响应器会自动处理消息
并将用户输入的原始参数列表保存在 `state["argv"]`, `parser` 处理的参数保存在 `state["args"]` 可以通过 {ref}`nonebot.params.ShellCommandArgv` 获取原始参数列表
通过 {ref}`nonebot.params.ShellCommandArgs` 获取解析后的参数字典
参数: 参数:
cmd: 指定命令内容 cmd: 指定命令内容
@ -712,7 +714,8 @@ class MatcherGroup(_Group):
与普通的 `on_command` 不同的是在添加 `parser` 参数时, 响应器会自动处理消息 与普通的 `on_command` 不同的是在添加 `parser` 参数时, 响应器会自动处理消息
并将用户输入的原始参数列表保存在 `state["argv"]`, `parser` 处理的参数保存在 `state["args"]` 可以通过 {ref}`nonebot.params.ShellCommandArgv` 获取原始参数列表
通过 {ref}`nonebot.params.ShellCommandArgs` 获取解析后的参数字典
参数: 参数:
cmd: 指定命令内容 cmd: 指定命令内容

View File

@ -1,7 +1,6 @@
import re import re
from types import ModuleType from types import ModuleType
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Set, List, Type, Tuple, Union, Optional
from nonebot.adapters import Event from nonebot.adapters import Event
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
@ -12,399 +11,399 @@ from nonebot.typing import T_State, T_Handler, T_RuleChecker, T_PermissionChecke
from .plugin import Plugin from .plugin import Plugin
def store_matcher(matcher: Type[Matcher]) -> None: ... def store_matcher(matcher: type[Matcher]) -> None: ...
def get_matcher_plugin(depth: int = ...) -> Optional[Plugin]: ... def get_matcher_plugin(depth: int = ...) -> Plugin | None: ...
def get_matcher_module(depth: int = ...) -> Optional[ModuleType]: ... def get_matcher_module(depth: int = ...) -> ModuleType | None: ...
def on( def on(
type: str = "", type: str = "",
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
*, *,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_metaevent( def on_metaevent(
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
*, *,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_message( def on_message(
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
*, *,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_notice( def on_notice(
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
*, *,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_request( def on_request(
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
*, *,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_startswith( def on_startswith(
msg: Union[str, Tuple[str, ...]], msg: str | tuple[str, ...],
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
ignorecase: bool = ..., ignorecase: bool = ...,
*, *,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_endswith( def on_endswith(
msg: Union[str, Tuple[str, ...]], msg: str | tuple[str, ...],
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
ignorecase: bool = ..., ignorecase: bool = ...,
*, *,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_fullmatch( def on_fullmatch(
msg: Union[str, Tuple[str, ...]], msg: str | tuple[str, ...],
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
ignorecase: bool = ..., ignorecase: bool = ...,
*, *,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_keyword( def on_keyword(
keywords: Set[str], keywords: set[str],
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
*, *,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_command( def on_command(
cmd: Union[str, Tuple[str, ...]], cmd: str | tuple[str, ...],
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ..., aliases: set[str | tuple[str, ...]] | None = ...,
force_whitespace: Optional[Union[str, bool]] = ..., force_whitespace: str | bool | None = ...,
*, *,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_shell_command( def on_shell_command(
cmd: Union[str, Tuple[str, ...]], cmd: str | tuple[str, ...],
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ..., aliases: set[str | tuple[str, ...]] | None = ...,
parser: Optional[ArgumentParser] = ..., parser: ArgumentParser | None = ...,
*, *,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_regex( def on_regex(
pattern: str, pattern: str,
flags: Union[int, re.RegexFlag] = ..., flags: int | re.RegexFlag = ...,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
*, *,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_type( def on_type(
types: Union[Type[Event], Tuple[Type[Event], ...]], types: type[Event] | tuple[type[Event], ...],
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
*, *,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
class CommandGroup: class CommandGroup:
def __init__( def __init__(
self, self,
cmd: Union[str, Tuple[str, ...]], cmd: str | tuple[str, ...],
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
): ... ): ...
def command( def command(
self, self,
cmd: Union[str, Tuple[str, ...]], cmd: str | tuple[str, ...],
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ..., aliases: set[str | tuple[str, ...]] | None = ...,
force_whitespace: Optional[Union[str, bool]] = ..., force_whitespace: str | bool | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def shell_command( def shell_command(
self, self,
cmd: Union[str, Tuple[str, ...]], cmd: str | tuple[str, ...],
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ..., aliases: set[str | tuple[str, ...]] | None = ...,
parser: Optional[ArgumentParser] = ..., parser: ArgumentParser | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
class MatcherGroup: class MatcherGroup:
def __init__( def __init__(
self, self,
*, *,
type: str = ..., type: str = ...,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
): ... ): ...
def on( def on(
self, self,
*, *,
type: str = ..., type: str = ...,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_metaevent( def on_metaevent(
self, self,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_message( def on_message(
self, self,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_notice( def on_notice(
self, self,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_request( def on_request(
self, self,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_startswith( def on_startswith(
self, self,
msg: Union[str, Tuple[str, ...]], msg: str | tuple[str, ...],
*, *,
ignorecase: bool = ..., ignorecase: bool = ...,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_endswith( def on_endswith(
self, self,
msg: Union[str, Tuple[str, ...]], msg: str | tuple[str, ...],
*, *,
ignorecase: bool = ..., ignorecase: bool = ...,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_fullmatch( def on_fullmatch(
self, self,
msg: Union[str, Tuple[str, ...]], msg: str | tuple[str, ...],
*, *,
ignorecase: bool = ..., ignorecase: bool = ...,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_keyword( def on_keyword(
self, self,
keywords: Set[str], keywords: set[str],
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_command( def on_command(
self, self,
cmd: Union[str, Tuple[str, ...]], cmd: str | tuple[str, ...],
aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ..., aliases: set[str | tuple[str, ...]] | None = ...,
force_whitespace: Optional[Union[str, bool]] = ..., force_whitespace: str | bool | None = ...,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_shell_command( def on_shell_command(
self, self,
cmd: Union[str, Tuple[str, ...]], cmd: str | tuple[str, ...],
aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ..., aliases: set[str | tuple[str, ...]] | None = ...,
parser: Optional[ArgumentParser] = ..., parser: ArgumentParser | None = ...,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_regex( def on_regex(
self, self,
pattern: str, pattern: str,
flags: Union[int, re.RegexFlag] = ..., flags: int | re.RegexFlag = ...,
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...
def on_type( def on_type(
self, self,
types: Union[Type[Event], Tuple[Type[Event]]], types: type[Event] | tuple[type[Event]],
*, *,
rule: Optional[Union[Rule, T_RuleChecker]] = ..., rule: Rule | T_RuleChecker | None = ...,
permission: Optional[Union[Permission, T_PermissionChecker]] = ..., permission: Permission | T_PermissionChecker | None = ...,
handlers: Optional[List[Union[T_Handler, Dependent]]] = ..., handlers: list[T_Handler | Dependent] | None = ...,
temp: bool = ..., temp: bool = ...,
expire_time: Optional[Union[datetime, timedelta]] = ..., expire_time: datetime | timedelta | None = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[T_State] = ..., state: T_State | None = ...,
) -> Type[Matcher]: ... ) -> type[Matcher]: ...

View File

@ -26,7 +26,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)
if event_id := _running_matcher.get(session_id, None): if event_id := _running_matcher.get(session_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

View File

@ -1,7 +1,8 @@
"""本模块是 {ref}`nonebot.matcher.Matcher.rule` 的类型定义。 """本模块是 {ref}`nonebot.matcher.Matcher.rule` 的类型定义。
每个事件响应器 {ref}`nonebot.matcher.Matcher` 拥有一个匹配规则 {ref}`nonebot.rule.Rule` 每个{ref}`事件响应器 <nonebot.matcher.Matcher>`拥有一个
其中是 `RuleChecker` 的集合只有当所有 `RuleChecker` 检查结果为 `True` 时继续运行 {ref}`nonebot.rule.Rule`其中是 `RuleChecker` 的集合
只有当所有 `RuleChecker` 检查结果为 `True` 时继续运行
FrontMatter: FrontMatter:
sidebar_position: 5 sidebar_position: 5
@ -60,20 +61,19 @@ from nonebot.consts import (
T = TypeVar("T") T = TypeVar("T")
CMD_RESULT = TypedDict(
"CMD_RESULT",
{
"command": Optional[Tuple[str, ...]],
"raw_command": Optional[str],
"command_arg": Optional[Message],
"command_start": Optional[str],
"command_whitespace": Optional[str],
},
)
TRIE_VALUE = NamedTuple( class CMD_RESULT(TypedDict):
"TRIE_VALUE", [("command_start", str), ("command", Tuple[str, ...])] command: Optional[Tuple[str, ...]]
) raw_command: Optional[str]
command_arg: Optional[Message]
command_start: Optional[str]
command_whitespace: Optional[str]
class TRIE_VALUE(NamedTuple):
command_start: str
command: Tuple[str, ...]
parser_message: ContextVar[str] = ContextVar("parser_message") parser_message: ContextVar[str] = ContextVar("parser_message")
@ -406,7 +406,7 @@ def command(
force_whitespace: 是否强制命令后必须有指定空白符 force_whitespace: 是否强制命令后必须有指定空白符
用法: 用法:
使用默认 `command_start`, `command_sep` 配置 使用默认 `command_start`, `command_sep` 配置情况下
命令 `("test",)` 可以匹配: `/test` 开头的消息 命令 `("test",)` 可以匹配: `/test` 开头的消息
命令 `("test", "sub")` 可以匹配: `/test.sub` 开头的消息 命令 `("test", "sub")` 可以匹配: `/test.sub` 开头的消息
@ -441,6 +441,8 @@ def command(
class ArgumentParser(ArgParser): class ArgumentParser(ArgParser):
"""`shell_like` 命令参数解析器,解析出错时不会退出程序。 """`shell_like` 命令参数解析器,解析出错时不会退出程序。
支持 {ref}`nonebot.adapters.Message` 富文本解析
用法: 用法:
用法与 `argparse.ArgumentParser` 相同 用法与 `argparse.ArgumentParser` 相同
参考文档: [argparse](https://docs.python.org/3/library/argparse.html) 参考文档: [argparse](https://docs.python.org/3/library/argparse.html)
@ -588,10 +590,14 @@ def shell_command(
根据配置里提供的 {ref}``command_start` <nonebot.config.Config.command_start>`, 根据配置里提供的 {ref}``command_start` <nonebot.config.Config.command_start>`,
{ref}``command_sep` <nonebot.config.Config.command_sep>` 判断消息是否为命令 {ref}``command_sep` <nonebot.config.Config.command_sep>` 判断消息是否为命令
可以通过 {ref}`nonebot.params.Command` 获取匹配成功的命令: `("test",)` 可以通过 {ref}`nonebot.params.Command` 获取匹配成功的命令
通过 {ref}`nonebot.params.RawCommand` 获取匹配成功的原始命令文本: `"/test"` : `("test",)`
通过 {ref}`nonebot.params.ShellCommandArgv` 获取解析前的参数列表: `["arg", "-h"]` 通过 {ref}`nonebot.params.RawCommand` 获取匹配成功的原始命令文本
通过 {ref}`nonebot.params.ShellCommandArgs` 获取解析后的参数字典: `{"arg": "arg", "h": True}` : `"/test"`
通过 {ref}`nonebot.params.ShellCommandArgv` 获取解析前的参数列表
: `["arg", "-h"]`
通过 {ref}`nonebot.params.ShellCommandArgs` 获取解析后的参数字典
: `{"arg": "arg", "h": True}`
:::warning 警告 :::warning 警告
如果参数解析失败则通过 {ref}`nonebot.params.ShellCommandArgs` 如果参数解析失败则通过 {ref}`nonebot.params.ShellCommandArgs`
@ -603,7 +609,8 @@ def shell_command(
parser: {ref}`nonebot.rule.ArgumentParser` 对象 parser: {ref}`nonebot.rule.ArgumentParser` 对象
用法: 用法:
使用默认 `command_start`, `command_sep` 配置更多示例参考 `argparse` 标准库文档 使用默认 `command_start`, `command_sep` 配置更多示例参考
[argparse](https://docs.python.org/3/library/argparse.html) 标准库文档
```python ```python
from nonebot.rule import ArgumentParser from nonebot.rule import ArgumentParser
@ -698,7 +705,8 @@ def regex(regex: str, flags: Union[int, re.RegexFlag] = 0) -> Rule:
::: :::
:::tip 提示 :::tip 提示
正则表达式匹配使用 `EventMessage` `str` 字符串而非 `EventMessage` `PlainText` 纯文本字符串 正则表达式匹配使用 `EventMessage` `str` 字符串
而非 `EventMessage` `PlainText` 纯文本字符串
::: :::
""" """

View File

@ -1,17 +1,16 @@
"""本模块定义了 NoneBot 模块中共享的一些类型。 """本模块定义了 NoneBot 模块中共享的一些类型。
下面的文档中类型部分使用 Python Type Hint 语法 使用 Python Type Hint 语法
参考 [`PEP 484`](https://www.python.org/dev/peps/pep-0484/), 参考 [`PEP 484`](https://www.python.org/dev/peps/pep-0484/),
[`PEP 526`](https://www.python.org/dev/peps/pep-0526/) [`PEP 526`](https://www.python.org/dev/peps/pep-0526/)
[`typing`](https://docs.python.org/3/library/typing.html) [`typing`](https://docs.python.org/3/library/typing.html)
除了 Python 内置的类型下面还出现了如下 NoneBot 自定类型实际上它们是 Python 内置类型的别名
FrontMatter: FrontMatter:
sidebar_position: 11 sidebar_position: 11
description: nonebot.typing 模块 description: nonebot.typing 模块
""" """
from typing_extensions import ParamSpec, TypeAlias
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Any, Any,
@ -30,8 +29,9 @@ if TYPE_CHECKING:
from nonebot.permission import Permission from nonebot.permission import Permission
T = TypeVar("T") T = TypeVar("T")
P = ParamSpec("P")
T_Wrapped = TypeVar("T_Wrapped", bound=Callable) T_Wrapped: TypeAlias = Callable[P, T]
def overrides(InterfaceClass: object) -> Callable[[T_Wrapped], T_Wrapped]: def overrides(InterfaceClass: object) -> Callable[[T_Wrapped], T_Wrapped]:
@ -45,13 +45,13 @@ def overrides(InterfaceClass: object) -> Callable[[T_Wrapped], T_Wrapped]:
# state # state
T_State = Dict[Any, Any] T_State: TypeAlias = Dict[Any, Any]
"""事件处理状态 State 类型""" """事件处理状态 State 类型"""
_DependentCallable = Union[Callable[..., T], Callable[..., Awaitable[T]]] _DependentCallable: TypeAlias = Union[Callable[..., T], Callable[..., Awaitable[T]]]
# driver hooks # driver hooks
T_BotConnectionHook = _DependentCallable[Any] T_BotConnectionHook: TypeAlias = _DependentCallable[Any]
"""Bot 连接建立时钩子函数 """Bot 连接建立时钩子函数
依赖参数: 依赖参数:
@ -60,7 +60,7 @@ T_BotConnectionHook = _DependentCallable[Any]
- BotParam: Bot 对象 - BotParam: Bot 对象
- DefaultParam: 带有默认值的参数 - DefaultParam: 带有默认值的参数
""" """
T_BotDisconnectionHook = _DependentCallable[Any] T_BotDisconnectionHook: TypeAlias = _DependentCallable[Any]
"""Bot 连接断开时钩子函数 """Bot 连接断开时钩子函数
依赖参数: 依赖参数:
@ -71,15 +71,15 @@ T_BotDisconnectionHook = _DependentCallable[Any]
""" """
# api hooks # api hooks
T_CallingAPIHook = Callable[["Bot", str, Dict[str, Any]], Awaitable[Any]] T_CallingAPIHook: TypeAlias = Callable[["Bot", str, Dict[str, Any]], Awaitable[Any]]
"""`bot.call_api` 钩子函数""" """`bot.call_api` 钩子函数"""
T_CalledAPIHook = Callable[ T_CalledAPIHook: TypeAlias = Callable[
["Bot", Optional[Exception], str, Dict[str, Any], Any], Awaitable[Any] ["Bot", Optional[Exception], str, Dict[str, Any], Any], Awaitable[Any]
] ]
"""`bot.call_api` 后执行的函数,参数分别为 bot, exception, api, data, result""" """`bot.call_api` 后执行的函数,参数分别为 bot, exception, api, data, result"""
# event hooks # event hooks
T_EventPreProcessor = _DependentCallable[Any] T_EventPreProcessor: TypeAlias = _DependentCallable[Any]
"""事件预处理函数 EventPreProcessor 类型 """事件预处理函数 EventPreProcessor 类型
依赖参数: 依赖参数:
@ -90,7 +90,7 @@ T_EventPreProcessor = _DependentCallable[Any]
- StateParam: State 对象 - StateParam: State 对象
- DefaultParam: 带有默认值的参数 - DefaultParam: 带有默认值的参数
""" """
T_EventPostProcessor = _DependentCallable[Any] T_EventPostProcessor: TypeAlias = _DependentCallable[Any]
"""事件预处理函数 EventPostProcessor 类型 """事件预处理函数 EventPostProcessor 类型
依赖参数: 依赖参数:
@ -103,7 +103,7 @@ T_EventPostProcessor = _DependentCallable[Any]
""" """
# matcher run hooks # matcher run hooks
T_RunPreProcessor = _DependentCallable[Any] T_RunPreProcessor: TypeAlias = _DependentCallable[Any]
"""事件响应器运行前预处理函数 RunPreProcessor 类型 """事件响应器运行前预处理函数 RunPreProcessor 类型
依赖参数: 依赖参数:
@ -115,7 +115,7 @@ T_RunPreProcessor = _DependentCallable[Any]
- MatcherParam: Matcher 对象 - MatcherParam: Matcher 对象
- DefaultParam: 带有默认值的参数 - DefaultParam: 带有默认值的参数
""" """
T_RunPostProcessor = _DependentCallable[Any] T_RunPostProcessor: TypeAlias = _DependentCallable[Any]
"""事件响应器运行后后处理函数 RunPostProcessor 类型 """事件响应器运行后后处理函数 RunPostProcessor 类型
依赖参数: 依赖参数:
@ -130,7 +130,7 @@ T_RunPostProcessor = _DependentCallable[Any]
""" """
# rule, permission # rule, permission
T_RuleChecker = _DependentCallable[bool] T_RuleChecker: TypeAlias = _DependentCallable[bool]
"""RuleChecker 即判断是否响应事件的处理函数。 """RuleChecker 即判断是否响应事件的处理函数。
依赖参数: 依赖参数:
@ -141,7 +141,7 @@ T_RuleChecker = _DependentCallable[bool]
- StateParam: State 对象 - StateParam: State 对象
- DefaultParam: 带有默认值的参数 - DefaultParam: 带有默认值的参数
""" """
T_PermissionChecker = _DependentCallable[bool] T_PermissionChecker: TypeAlias = _DependentCallable[bool]
"""PermissionChecker 即判断事件是否满足权限的处理函数。 """PermissionChecker 即判断事件是否满足权限的处理函数。
依赖参数: 依赖参数:
@ -152,10 +152,11 @@ T_PermissionChecker = _DependentCallable[bool]
- DefaultParam: 带有默认值的参数 - DefaultParam: 带有默认值的参数
""" """
T_Handler = _DependentCallable[Any] T_Handler: TypeAlias = _DependentCallable[Any]
"""Handler 处理函数。""" """Handler 处理函数。"""
T_TypeUpdater = _DependentCallable[str] T_TypeUpdater: TypeAlias = _DependentCallable[str]
"""TypeUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新响应的事件类型。默认会更新为 `message`。 """TypeUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新响应的事件类型。
默认会更新为 `message`
依赖参数: 依赖参数:
@ -166,8 +167,9 @@ T_TypeUpdater = _DependentCallable[str]
- MatcherParam: Matcher 对象 - MatcherParam: Matcher 对象
- DefaultParam: 带有默认值的参数 - DefaultParam: 带有默认值的参数
""" """
T_PermissionUpdater = _DependentCallable["Permission"] T_PermissionUpdater: TypeAlias = _DependentCallable["Permission"]
"""PermissionUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新会话对象权限。默认会更新为当前事件的触发对象。 """PermissionUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新会话对象权限。
默认会更新为当前事件的触发对象
依赖参数: 依赖参数:
@ -178,5 +180,5 @@ T_PermissionUpdater = _DependentCallable["Permission"]
- MatcherParam: Matcher 对象 - MatcherParam: Matcher 对象
- DefaultParam: 带有默认值的参数 - DefaultParam: 带有默认值的参数
""" """
T_DependencyCache = Dict[_DependentCallable[Any], "Task[Any]"] T_DependencyCache: TypeAlias = Dict[_DependentCallable[Any], "Task[Any]"]
"""依赖缓存, 用于存储依赖函数的返回值""" """依赖缓存, 用于存储依赖函数的返回值"""

View File

@ -63,7 +63,8 @@ def generic_check_issubclass(
- 如果 cls `typing.Union` `types.UnionType` 类型 - 如果 cls `typing.Union` `types.UnionType` 类型
则会检查其中的所有类型是否是 class_or_tuple 中一个类型的子类或 None 则会检查其中的所有类型是否是 class_or_tuple 中一个类型的子类或 None
- 如果 cls `typing.TypeVar` 类型 - 如果 cls `typing.TypeVar` 类型
则会检查其 `__bound__` `__constraints__` 是否是 class_or_tuple 中一个类型的子类或 None 则会检查其 `__bound__` `__constraints__`
是否是 class_or_tuple 中一个类型的子类或 None
""" """
try: try:
return issubclass(cls, class_or_tuple) return issubclass(cls, class_or_tuple)
@ -171,6 +172,17 @@ async def run_coro_with_catch(
exc: Tuple[Type[Exception], ...], exc: Tuple[Type[Exception], ...],
return_on_err: Optional[R] = None, return_on_err: Optional[R] = None,
) -> Optional[Union[T, R]]: ) -> Optional[Union[T, R]]:
"""运行协程并当遇到指定异常时返回指定值。
参数:
coro: 要运行的协程
exc: 要捕获的异常
return_on_err: 当发生异常时返回的值
返回:
协程的返回值或发生异常时的指定值
"""
try: try:
return await coro return await coro
except exc: except exc:
@ -210,7 +222,7 @@ def resolve_dot_notation(
class DataclassEncoder(json.JSONEncoder): class DataclassEncoder(json.JSONEncoder):
"""在JSON序列化 {ref}`nonebot.adapters.Message` (List[Dataclass]) 时使用的 `JSONEncoder`""" """可以序列化 {ref}`nonebot.adapters.Message`(List[Dataclass]) 的 `JSONEncoder`"""
@overrides(json.JSONEncoder) @overrides(json.JSONEncoder)
def default(self, o): def default(self, o):
@ -228,6 +240,8 @@ def logger_wrapper(logger_name: str):
返回: 返回:
日志记录函数 日志记录函数
日志记录函数的参数:
- level: 日志等级 - level: 日志等级
- message: 日志信息 - message: 日志信息
- exception: 异常信息 - exception: 异常信息

431
poetry.lock generated
View File

@ -759,39 +759,36 @@ testing = ["pre-commit"]
[[package]] [[package]]
name = "fastapi" name = "fastapi"
version = "0.95.2" version = "0.98.0"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
optional = true optional = true
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "fastapi-0.95.2-py3-none-any.whl", hash = "sha256:d374dbc4ef2ad9b803899bd3360d34c534adc574546e25314ab72c0c4411749f"}, {file = "fastapi-0.98.0-py3-none-any.whl", hash = "sha256:f4165fb1fe3610c52cb1b8282c1480de9c34bc270f56a965aa93a884c350d605"},
{file = "fastapi-0.95.2.tar.gz", hash = "sha256:4d9d3e8c71c73f11874bcf5e33626258d143252e329a01002f767306c64fb982"}, {file = "fastapi-0.98.0.tar.gz", hash = "sha256:0d3c18886f652038262b5898fec6b09f4ca92ee23e9d9b1d1d24e429f84bf27b"},
] ]
[package.dependencies] [package.dependencies]
pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0"
starlette = ">=0.27.0,<0.28.0" starlette = ">=0.27.0,<0.28.0"
[package.extras] [package.extras]
all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
dev = ["pre-commit (>=2.17.0,<3.0.0)", "ruff (==0.0.138)", "uvicorn[standard] (>=0.12.0,<0.21.0)"]
doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer-cli (>=0.0.13,<0.0.14)", "typer[all] (>=0.6.1,<0.8.0)"]
test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6.5.0,<8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.7)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.138)", "sqlalchemy (>=1.3.18,<1.4.43)", "types-orjson (==3.6.2)", "types-ujson (==5.7.0.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"]
[[package]] [[package]]
name = "filelock" name = "filelock"
version = "3.12.0" version = "3.12.2"
description = "A platform independent file lock." description = "A platform independent file lock."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"},
{file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"},
] ]
[package.extras] [package.extras]
docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"]
[[package]] [[package]]
name = "frozenlist" name = "frozenlist"
@ -1073,13 +1070,13 @@ files = [
[[package]] [[package]]
name = "importlib-metadata" name = "importlib-metadata"
version = "6.6.0" version = "6.7.0"
description = "Read metadata from Python packages" description = "Read metadata from Python packages"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"}, {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"},
{file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"}, {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"},
] ]
[package.dependencies] [package.dependencies]
@ -1088,7 +1085,7 @@ zipp = ">=0.5"
[package.extras] [package.extras]
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
perf = ["ipython"] perf = ["ipython"]
testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
[[package]] [[package]]
name = "iniconfig" name = "iniconfig"
@ -1146,53 +1143,6 @@ MarkupSafe = ">=2.0"
[package.extras] [package.extras]
i18n = ["Babel (>=2.7)"] i18n = ["Babel (>=2.7)"]
[[package]]
name = "libcst"
version = "0.4.10"
description = "A concrete syntax tree with AST-like properties for Python 3.5, 3.6, 3.7, 3.8, 3.9, and 3.10 programs."
optional = false
python-versions = ">=3.7"
files = [
{file = "libcst-0.4.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8fa0ec646ed7bce984d0ee9dbf514af278050bdb16a4fb986e916ace534eebc6"},
{file = "libcst-0.4.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3cb3b7821eac00713844cda079583230c546a589b22ed5f03f2ddc4f985c384b"},
{file = "libcst-0.4.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7acfa747112ae40b032739661abd7c81aff37191294f7c2dab8bbd72372e78f"},
{file = "libcst-0.4.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1312e293b864ef3cb4b09534ed5f104c2dc45b680233c68bf76237295041c781"},
{file = "libcst-0.4.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76884b1afe475e8e68e704bf26eb9f9a2867029643e58f2f26a0286e3b6e998e"},
{file = "libcst-0.4.10-cp310-cp310-win_amd64.whl", hash = "sha256:1069b808a711db5cd47538f27eb2c73206317aa0d8b5a3500b23aab24f86eb2e"},
{file = "libcst-0.4.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:50be085346a35812535c7f876319689e15a7bfd1bd8efae8fd70589281d944b6"},
{file = "libcst-0.4.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb9f10e5763e361e8bd8ff765fc0f1bcf744f242ff8b6d3e50ffec4dda3972ac"},
{file = "libcst-0.4.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfeeabb528b5df7b4be1817b584ce79e9a1a66687bd72f6de9c22272462812f1"},
{file = "libcst-0.4.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5648aeae8c90a2abab1f7b1bf205769a0179ed2cfe1ea7f681f6885e87b8b193"},
{file = "libcst-0.4.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a144f20aff4643b00374facf8409d30c7935db8176e5b2a07e1fd44004db2c1f"},
{file = "libcst-0.4.10-cp311-cp311-win_amd64.whl", hash = "sha256:a10adc2e8ea2dda2b70eabec631ead2fc4a7a7ab633d6c2b690823c698b8431a"},
{file = "libcst-0.4.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58fe90458a26a55358207f74abf8a05dff51d662069f070b4bd308a000a80c09"},
{file = "libcst-0.4.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:999fbbe467f61cbce9e6e054f86cd1c5ffa3740fd3dc8ebdd600db379f699256"},
{file = "libcst-0.4.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83ee7e7be4efac4c140a97d772e1f6b3553f98fa5f46ad78df5dfe51e5a4aa4d"},
{file = "libcst-0.4.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:158478e8f45578fb26621b3dc0fe275f9e004297e9afdcf08936ecda05681174"},
{file = "libcst-0.4.10-cp37-cp37m-win_amd64.whl", hash = "sha256:5ed101fee1af7abea3684fcff7fab5b170ceea4040756f54c15c870539daec66"},
{file = "libcst-0.4.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:349f2b4ee4b982fe254c65c78d941fc96299f3c422b79f95ef8c7bba2b7f0f90"},
{file = "libcst-0.4.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7cfa4d4beb84d0d63247aca27f1a15c63984512274c5b23040f8b4ba511036d7"},
{file = "libcst-0.4.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24582506da24e31f2644f862f11413a6b80fbad68d15194bfcc3f7dfebf2ec5e"},
{file = "libcst-0.4.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cdf2d0157438d3d52d310b0b6be31ff99bed19de489b2ebd3e2a4cd9946da45"},
{file = "libcst-0.4.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a677103d2f1ab0e50bc3a7cc6c96c7d64bcbac826d785e4cbf5ee9aaa9fcfa25"},
{file = "libcst-0.4.10-cp38-cp38-win_amd64.whl", hash = "sha256:a8fdfd4a7d301adb785aa4b98e4a7cca45c5ff8cfb460b485d081efcfaaeeab7"},
{file = "libcst-0.4.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b1569d87536bed4e9c11dd5c94a137dc0bce2a2b05961489c6016bf4521bb7cf"},
{file = "libcst-0.4.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:72dff8783ac79cd10f2bd2fde0b28f262e9a22718ae26990948ba6131b85ca8b"},
{file = "libcst-0.4.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76adc53660ef094ff83f77a2550a7e00d1cab8e5e63336e071c17c09b5a89fe2"},
{file = "libcst-0.4.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3e9d9fdd9a9b9b8991936ff1c07527ce7ef396c8233280ba9a7137e72c2e48e"},
{file = "libcst-0.4.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e1b4cbaf7b1cdad5fa3eababe42d5b46c0d52afe13c5ba4eac2495fc57630ea"},
{file = "libcst-0.4.10-cp39-cp39-win_amd64.whl", hash = "sha256:bcbd07cec3d7a7be6f0299b0c246e085e3d6cc8af367e2c96059183b97c2e2fe"},
{file = "libcst-0.4.10.tar.gz", hash = "sha256:b98a829d96e8b209fb761b00cd1bacc27c70eae77d00e57976e5ae2c718c3f81"},
]
[package.dependencies]
pyyaml = ">=5.2"
typing-extensions = ">=3.7.4.2"
typing-inspect = ">=0.4.0"
[package.extras]
dev = ["Sphinx (>=5.1.1)", "black (==23.1.0)", "build (>=0.10.0)", "coverage (>=4.5.4)", "fixit (==0.1.1)", "flake8 (>=3.7.8,<5)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jinja2 (==3.1.2)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<0.14)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "pyre-check (==0.9.10)", "setuptools-rust (>=1.5.2)", "setuptools-scm (>=6.0.1)", "slotscheck (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.1.0)", "usort (==1.0.6)"]
[[package]] [[package]]
name = "loguru" name = "loguru"
version = "0.7.0" version = "0.7.0"
@ -1213,61 +1163,61 @@ dev = ["Sphinx (==5.3.0)", "colorama (==0.4.5)", "colorama (==0.4.6)", "freezegu
[[package]] [[package]]
name = "markupsafe" name = "markupsafe"
version = "2.1.2" version = "2.1.3"
description = "Safely add untrusted strings to HTML/XML markup." description = "Safely add untrusted strings to HTML/XML markup."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"}, {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"},
{file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"}, {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"},
{file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"}, {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"},
{file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"}, {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"},
{file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"}, {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"},
{file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"}, {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"},
{file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"}, {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"},
{file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"}, {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"},
{file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"}, {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"},
{file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"}, {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"},
{file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"}, {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"},
{file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"}, {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"},
{file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"}, {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"},
{file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"}, {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"},
{file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"}, {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"},
{file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"}, {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"},
{file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"}, {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"},
{file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"}, {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
{file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
{file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
{file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
{file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
{file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
{file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"},
{file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"},
{file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"},
{file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"},
{file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"},
{file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"},
{file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"}, {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"},
{file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"}, {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"},
{file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"}, {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"},
{file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"}, {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"},
{file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"}, {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"},
{file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"}, {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"},
{file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"}, {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"},
{file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"}, {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"},
{file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"}, {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"},
{file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"}, {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"},
{file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"}, {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"},
{file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"}, {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"},
{file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"}, {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"},
{file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"}, {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"},
{file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"}, {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"},
{file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"}, {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"},
{file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"}, {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"},
{file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"}, {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"},
{file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"}, {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"},
{file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"}, {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"},
{file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
] ]
[[package]] [[package]]
@ -1366,13 +1316,13 @@ files = [
[[package]] [[package]]
name = "nb-autodoc" name = "nb-autodoc"
version = "1.0.0a5" version = "1.0.0a7"
description = "Powerful API Documentation Generator." description = "Python API documentation tool supporting the modern PEPs and typing features."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "nb-autodoc-1.0.0a5.tar.gz", hash = "sha256:9341a2a231f9c1e97a040ee8701ff2e800ba742a1f1e548f7c92fbaa5d618e8b"}, {file = "nb-autodoc-1.0.0a7.tar.gz", hash = "sha256:16cf127a3574dcd1e7e495ce992406bb2783245062033fef54b741fdf9b29f7e"},
{file = "nb_autodoc-1.0.0a5-py3-none-any.whl", hash = "sha256:2158758d1d1cc959082f201719f0d343659306ef776546cd60f5b932b0f03488"}, {file = "nb_autodoc-1.0.0a7-py3-none-any.whl", hash = "sha256:789a17c0fa5e4c071cf65402d59444828b56b245aa7ec01c80640ce6bbe347b3"},
] ]
[package.dependencies] [package.dependencies]
@ -1395,13 +1345,13 @@ setuptools = "*"
[[package]] [[package]]
name = "nonebug" name = "nonebug"
version = "0.3.3" version = "0.3.4"
description = "nonebot2 test framework" description = "nonebot2 test framework"
optional = false optional = false
python-versions = ">=3.8,<4.0" python-versions = ">=3.8,<4.0"
files = [ files = [
{file = "nonebug-0.3.3-py3-none-any.whl", hash = "sha256:c3e53e9fe0859083512b78b1af5c29c2ba73b86957fac6a028f094a64a04ea5a"}, {file = "nonebug-0.3.4-py3-none-any.whl", hash = "sha256:d6ebbde934d463141497e3162e26371b7e266d39f8cac0aa1bccc0e4542dd48b"},
{file = "nonebug-0.3.3.tar.gz", hash = "sha256:3ef520e60c9af97fc4f4dbddcc46723aedb8a127b84369b49d2e9a40bea5b799"}, {file = "nonebug-0.3.4.tar.gz", hash = "sha256:11d106dff3fe0d5fa029b9745f701770bcc484be048e72722bb17bb00f84753d"},
] ]
[package.dependencies] [package.dependencies]
@ -1452,39 +1402,39 @@ files = [
[[package]] [[package]]
name = "pathspec" name = "pathspec"
version = "0.9.0" version = "0.11.1"
description = "Utility library for gitignore style pattern matching of file paths." description = "Utility library for gitignore style pattern matching of file paths."
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" python-versions = ">=3.7"
files = [ files = [
{file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"},
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"},
] ]
[[package]] [[package]]
name = "platformdirs" name = "platformdirs"
version = "3.5.1" version = "3.8.0"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "platformdirs-3.5.1-py3-none-any.whl", hash = "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5"}, {file = "platformdirs-3.8.0-py3-none-any.whl", hash = "sha256:ca9ed98ce73076ba72e092b23d3c93ea6c4e186b3f1c3dad6edd98ff6ffcca2e"},
{file = "platformdirs-3.5.1.tar.gz", hash = "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f"}, {file = "platformdirs-3.8.0.tar.gz", hash = "sha256:b0cabcb11063d21a0b261d557acb0a9d2126350e63b70cdf7db6347baea456dc"},
] ]
[package.extras] [package.extras]
docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"]
[[package]] [[package]]
name = "pluggy" name = "pluggy"
version = "1.0.0" version = "1.2.0"
description = "plugin and hook calling mechanisms for python" description = "plugin and hook calling mechanisms for python"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.7"
files = [ files = [
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"},
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"},
] ]
[package.extras] [package.extras]
@ -1493,13 +1443,13 @@ testing = ["pytest", "pytest-benchmark"]
[[package]] [[package]]
name = "pre-commit" name = "pre-commit"
version = "3.3.2" version = "3.3.3"
description = "A framework for managing and maintaining multi-language pre-commit hooks." description = "A framework for managing and maintaining multi-language pre-commit hooks."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "pre_commit-3.3.2-py2.py3-none-any.whl", hash = "sha256:8056bc52181efadf4aac792b1f4f255dfd2fb5a350ded7335d251a68561e8cb6"}, {file = "pre_commit-3.3.3-py2.py3-none-any.whl", hash = "sha256:10badb65d6a38caff29703362271d7dca483d01da88f9d7e05d0b97171c136cb"},
{file = "pre_commit-3.3.2.tar.gz", hash = "sha256:66e37bec2d882de1f17f88075047ef8962581f83c234ac08da21a0c58953d1f0"}, {file = "pre_commit-3.3.3.tar.gz", hash = "sha256:a2256f489cd913d575c145132ae196fe335da32d91a8294b7afe6622335dd023"},
] ]
[package.dependencies] [package.dependencies]
@ -1601,24 +1551,6 @@ cffi = ">=1.5.0"
[package.extras] [package.extras]
idna = ["idna (>=2.1)"] idna = ["idna (>=2.1)"]
[[package]]
name = "pycln"
version = "2.1.4"
description = "A formatter for finding and removing unused import statements."
optional = false
python-versions = ">=3.6.2,<4"
files = [
{file = "pycln-2.1.4-py3-none-any.whl", hash = "sha256:e541becc3f831e17f89285e7d6a430c6b7f59b434aaa6e46ed08fe8e944f16fc"},
{file = "pycln-2.1.4.tar.gz", hash = "sha256:223008181056dcde37b4d6ecece488d17f902a2af7fd9bb2ec9d679477d0ccfc"},
]
[package.dependencies]
libcst = {version = ">=0.3.10,<0.5.0", markers = "python_version >= \"3.7\""}
pathspec = ">=0.9.0,<0.10.0"
pyyaml = ">=5.3.1,<7.0.0"
tomlkit = ">=0.11.1,<0.12.0"
typer = ">=0.4.1,<0.10.0"
[[package]] [[package]]
name = "pycparser" name = "pycparser"
version = "2.21" version = "2.21"
@ -1632,47 +1564,47 @@ files = [
[[package]] [[package]]
name = "pydantic" name = "pydantic"
version = "1.10.8" version = "1.10.9"
description = "Data validation and settings management using python type hints" description = "Data validation and settings management using python type hints"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "pydantic-1.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1243d28e9b05003a89d72e7915fdb26ffd1d39bdd39b00b7dbe4afae4b557f9d"}, {file = "pydantic-1.10.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e692dec4a40bfb40ca530e07805b1208c1de071a18d26af4a2a0d79015b352ca"},
{file = "pydantic-1.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0ab53b609c11dfc0c060d94335993cc2b95b2150e25583bec37a49b2d6c6c3f"}, {file = "pydantic-1.10.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c52eb595db83e189419bf337b59154bdcca642ee4b2a09e5d7797e41ace783f"},
{file = "pydantic-1.10.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9613fadad06b4f3bc5db2653ce2f22e0de84a7c6c293909b48f6ed37b83c61f"}, {file = "pydantic-1.10.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:939328fd539b8d0edf244327398a667b6b140afd3bf7e347cf9813c736211896"},
{file = "pydantic-1.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df7800cb1984d8f6e249351139667a8c50a379009271ee6236138a22a0c0f319"}, {file = "pydantic-1.10.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b48d3d634bca23b172f47f2335c617d3fcb4b3ba18481c96b7943a4c634f5c8d"},
{file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0c6fafa0965b539d7aab0a673a046466d23b86e4b0e8019d25fd53f4df62c277"}, {file = "pydantic-1.10.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f0b7628fb8efe60fe66fd4adadd7ad2304014770cdc1f4934db41fe46cc8825f"},
{file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e82d4566fcd527eae8b244fa952d99f2ca3172b7e97add0b43e2d97ee77f81ab"}, {file = "pydantic-1.10.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e1aa5c2410769ca28aa9a7841b80d9d9a1c5f223928ca8bec7e7c9a34d26b1d4"},
{file = "pydantic-1.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:ab523c31e22943713d80d8d342d23b6f6ac4b792a1e54064a8d0cf78fd64e800"}, {file = "pydantic-1.10.9-cp310-cp310-win_amd64.whl", hash = "sha256:eec39224b2b2e861259d6f3c8b6290d4e0fbdce147adb797484a42278a1a486f"},
{file = "pydantic-1.10.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:666bdf6066bf6dbc107b30d034615d2627e2121506c555f73f90b54a463d1f33"}, {file = "pydantic-1.10.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d111a21bbbfd85c17248130deac02bbd9b5e20b303338e0dbe0faa78330e37e0"},
{file = "pydantic-1.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:35db5301b82e8661fa9c505c800d0990bc14e9f36f98932bb1d248c0ac5cada5"}, {file = "pydantic-1.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e9aec8627a1a6823fc62fb96480abe3eb10168fd0d859ee3d3b395105ae19a7"},
{file = "pydantic-1.10.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90c1e29f447557e9e26afb1c4dbf8768a10cc676e3781b6a577841ade126b85"}, {file = "pydantic-1.10.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07293ab08e7b4d3c9d7de4949a0ea571f11e4557d19ea24dd3ae0c524c0c334d"},
{file = "pydantic-1.10.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93e766b4a8226e0708ef243e843105bf124e21331694367f95f4e3b4a92bbb3f"}, {file = "pydantic-1.10.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ee829b86ce984261d99ff2fd6e88f2230068d96c2a582f29583ed602ef3fc2c"},
{file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88f195f582851e8db960b4a94c3e3ad25692c1c1539e2552f3df7a9e972ef60e"}, {file = "pydantic-1.10.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4b466a23009ff5cdd7076eb56aca537c745ca491293cc38e72bf1e0e00de5b91"},
{file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:34d327c81e68a1ecb52fe9c8d50c8a9b3e90d3c8ad991bfc8f953fb477d42fb4"}, {file = "pydantic-1.10.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7847ca62e581e6088d9000f3c497267868ca2fa89432714e21a4fb33a04d52e8"},
{file = "pydantic-1.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:d532bf00f381bd6bc62cabc7d1372096b75a33bc197a312b03f5838b4fb84edd"}, {file = "pydantic-1.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:7845b31959468bc5b78d7b95ec52fe5be32b55d0d09983a877cca6aedc51068f"},
{file = "pydantic-1.10.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d5b8641c24886d764a74ec541d2fc2c7fb19f6da2a4001e6d580ba4a38f7878"}, {file = "pydantic-1.10.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:517a681919bf880ce1dac7e5bc0c3af1e58ba118fd774da2ffcd93c5f96eaece"},
{file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b1f6cb446470b7ddf86c2e57cd119a24959af2b01e552f60705910663af09a4"}, {file = "pydantic-1.10.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67195274fd27780f15c4c372f4ba9a5c02dad6d50647b917b6a92bf00b3d301a"},
{file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c33b60054b2136aef8cf190cd4c52a3daa20b2263917c49adad20eaf381e823b"}, {file = "pydantic-1.10.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2196c06484da2b3fded1ab6dbe182bdabeb09f6318b7fdc412609ee2b564c49a"},
{file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1952526ba40b220b912cdc43c1c32bcf4a58e3f192fa313ee665916b26befb68"}, {file = "pydantic-1.10.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6257bb45ad78abacda13f15bde5886efd6bf549dd71085e64b8dcf9919c38b60"},
{file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bb14388ec45a7a0dc429e87def6396f9e73c8c77818c927b6a60706603d5f2ea"}, {file = "pydantic-1.10.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3283b574b01e8dbc982080d8287c968489d25329a463b29a90d4157de4f2baaf"},
{file = "pydantic-1.10.8-cp37-cp37m-win_amd64.whl", hash = "sha256:16f8c3e33af1e9bb16c7a91fc7d5fa9fe27298e9f299cff6cb744d89d573d62c"}, {file = "pydantic-1.10.9-cp37-cp37m-win_amd64.whl", hash = "sha256:5f8bbaf4013b9a50e8100333cc4e3fa2f81214033e05ac5aa44fa24a98670a29"},
{file = "pydantic-1.10.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ced8375969673929809d7f36ad322934c35de4af3b5e5b09ec967c21f9f7887"}, {file = "pydantic-1.10.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9cd67fb763248cbe38f0593cd8611bfe4b8ad82acb3bdf2b0898c23415a1f82"},
{file = "pydantic-1.10.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93e6bcfccbd831894a6a434b0aeb1947f9e70b7468f274154d03d71fabb1d7c6"}, {file = "pydantic-1.10.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f50e1764ce9353be67267e7fd0da08349397c7db17a562ad036aa7c8f4adfdb6"},
{file = "pydantic-1.10.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:191ba419b605f897ede9892f6c56fb182f40a15d309ef0142212200a10af4c18"}, {file = "pydantic-1.10.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73ef93e5e1d3c8e83f1ff2e7fdd026d9e063c7e089394869a6e2985696693766"},
{file = "pydantic-1.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:052d8654cb65174d6f9490cc9b9a200083a82cf5c3c5d3985db765757eb3b375"}, {file = "pydantic-1.10.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:128d9453d92e6e81e881dd7e2484e08d8b164da5507f62d06ceecf84bf2e21d3"},
{file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ceb6a23bf1ba4b837d0cfe378329ad3f351b5897c8d4914ce95b85fba96da5a1"}, {file = "pydantic-1.10.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ad428e92ab68798d9326bb3e5515bc927444a3d71a93b4a2ca02a8a5d795c572"},
{file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f2e754d5566f050954727c77f094e01793bcb5725b663bf628fa6743a5a9108"}, {file = "pydantic-1.10.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fab81a92f42d6d525dd47ced310b0c3e10c416bbfae5d59523e63ea22f82b31e"},
{file = "pydantic-1.10.8-cp38-cp38-win_amd64.whl", hash = "sha256:6a82d6cda82258efca32b40040228ecf43a548671cb174a1e81477195ed3ed56"}, {file = "pydantic-1.10.9-cp38-cp38-win_amd64.whl", hash = "sha256:963671eda0b6ba6926d8fc759e3e10335e1dc1b71ff2a43ed2efd6996634dafb"},
{file = "pydantic-1.10.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e59417ba8a17265e632af99cc5f35ec309de5980c440c255ab1ca3ae96a3e0e"}, {file = "pydantic-1.10.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:970b1bdc6243ef663ba5c7e36ac9ab1f2bfecb8ad297c9824b542d41a750b298"},
{file = "pydantic-1.10.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84d80219c3f8d4cad44575e18404099c76851bc924ce5ab1c4c8bb5e2a2227d0"}, {file = "pydantic-1.10.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7e1d5290044f620f80cf1c969c542a5468f3656de47b41aa78100c5baa2b8276"},
{file = "pydantic-1.10.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e4148e635994d57d834be1182a44bdb07dd867fa3c2d1b37002000646cc5459"}, {file = "pydantic-1.10.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83fcff3c7df7adff880622a98022626f4f6dbce6639a88a15a3ce0f96466cb60"},
{file = "pydantic-1.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12f7b0bf8553e310e530e9f3a2f5734c68699f42218bf3568ef49cd9b0e44df4"}, {file = "pydantic-1.10.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0da48717dc9495d3a8f215e0d012599db6b8092db02acac5e0d58a65248ec5bc"},
{file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42aa0c4b5c3025483240a25b09f3c09a189481ddda2ea3a831a9d25f444e03c1"}, {file = "pydantic-1.10.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0a2aabdc73c2a5960e87c3ffebca6ccde88665616d1fd6d3db3178ef427b267a"},
{file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17aef11cc1b997f9d574b91909fed40761e13fac438d72b81f902226a69dac01"}, {file = "pydantic-1.10.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9863b9420d99dfa9c064042304868e8ba08e89081428a1c471858aa2af6f57c4"},
{file = "pydantic-1.10.8-cp39-cp39-win_amd64.whl", hash = "sha256:66a703d1983c675a6e0fed8953b0971c44dba48a929a2000a493c3772eb61a5a"}, {file = "pydantic-1.10.9-cp39-cp39-win_amd64.whl", hash = "sha256:e7c9900b43ac14110efa977be3da28931ffc74c27e96ee89fbcaaf0b0fe338e1"},
{file = "pydantic-1.10.8-py3-none-any.whl", hash = "sha256:7456eb22ed9aaa24ff3e7b4757da20d9e5ce2a81018c1b3ebd81a0b88a18f3b2"}, {file = "pydantic-1.10.9-py3-none-any.whl", hash = "sha256:6cafde02f6699ce4ff643417d1a9223716ec25e228ddc3b436fe7e2d25a1f305"},
{file = "pydantic-1.10.8.tar.gz", hash = "sha256:1410275520dfa70effadf4c21811d755e7ef9bb1f1d077a21958153a92c8d9ca"}, {file = "pydantic-1.10.9.tar.gz", hash = "sha256:95c70da2cd3b6ddf3b9645ecaa8d98f3d80c606624b6d245558d202cd23ea3be"},
] ]
[package.dependencies] [package.dependencies]
@ -1696,13 +1628,13 @@ files = [
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "7.3.1" version = "7.4.0"
description = "pytest: simple powerful testing with Python" description = "pytest: simple powerful testing with Python"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"},
{file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"},
] ]
[package.dependencies] [package.dependencies]
@ -1714,7 +1646,7 @@ pluggy = ">=0.12,<2.0"
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
[package.extras] [package.extras]
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
[[package]] [[package]]
name = "pytest-asyncio" name = "pytest-asyncio"
@ -1882,15 +1814,41 @@ urllib3 = ">=1.21.1,<3"
socks = ["PySocks (>=1.5.6,!=1.5.7)"] socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
[[package]]
name = "ruff"
version = "0.0.272"
description = "An extremely fast Python linter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
{file = "ruff-0.0.272-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:ae9b57546e118660175d45d264b87e9b4c19405c75b587b6e4d21e6a17bf4fdf"},
{file = "ruff-0.0.272-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:1609b864a8d7ee75a8c07578bdea0a7db75a144404e75ef3162e0042bfdc100d"},
{file = "ruff-0.0.272-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee76b4f05fcfff37bd6ac209d1370520d509ea70b5a637bdf0a04d0c99e13dff"},
{file = "ruff-0.0.272-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:48eccf225615e106341a641f826b15224b8a4240b84269ead62f0afd6d7e2d95"},
{file = "ruff-0.0.272-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:677284430ac539bb23421a2b431b4ebc588097ef3ef918d0e0a8d8ed31fea216"},
{file = "ruff-0.0.272-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:9c4bfb75456a8e1efe14c52fcefb89cfb8f2a0d31ed8d804b82c6cf2dc29c42c"},
{file = "ruff-0.0.272-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86bc788245361a8148ff98667da938a01e1606b28a45e50ac977b09d3ad2c538"},
{file = "ruff-0.0.272-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b2ea68d2aa69fff1b20b67636b1e3e22a6a39e476c880da1282c3e4bf6ee5a"},
{file = "ruff-0.0.272-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd2bbe337a3f84958f796c77820d55ac2db1e6753f39d1d1baed44e07f13f96d"},
{file = "ruff-0.0.272-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d5a208f8ef0e51d4746930589f54f9f92f84bb69a7d15b1de34ce80a7681bc00"},
{file = "ruff-0.0.272-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:905ff8f3d6206ad56fcd70674453527b9011c8b0dc73ead27618426feff6908e"},
{file = "ruff-0.0.272-py3-none-musllinux_1_2_i686.whl", hash = "sha256:19643d448f76b1eb8a764719072e9c885968971bfba872e14e7257e08bc2f2b7"},
{file = "ruff-0.0.272-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:691d72a00a99707a4e0b2846690961157aef7b17b6b884f6b4420a9f25cd39b5"},
{file = "ruff-0.0.272-py3-none-win32.whl", hash = "sha256:dc406e5d756d932da95f3af082814d2467943631a587339ee65e5a4f4fbe83eb"},
{file = "ruff-0.0.272-py3-none-win_amd64.whl", hash = "sha256:a37ec80e238ead2969b746d7d1b6b0d31aa799498e9ba4281ab505b93e1f4b28"},
{file = "ruff-0.0.272-py3-none-win_arm64.whl", hash = "sha256:06b8ee4eb8711ab119db51028dd9f5384b44728c23586424fd6e241a5b9c4a3b"},
{file = "ruff-0.0.272.tar.gz", hash = "sha256:273a01dc8c3c4fd4c2af7ea7a67c8d39bb09bce466e640dd170034da75d14cab"},
]
[[package]] [[package]]
name = "setuptools" name = "setuptools"
version = "67.8.0" version = "68.0.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages" description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"},
{file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"},
] ]
[package.extras] [package.extras]
@ -1949,73 +1907,26 @@ files = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
] ]
[[package]]
name = "tomlkit"
version = "0.11.8"
description = "Style preserving TOML library"
optional = false
python-versions = ">=3.7"
files = [
{file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"},
{file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"},
]
[[package]]
name = "typer"
version = "0.9.0"
description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
optional = false
python-versions = ">=3.6"
files = [
{file = "typer-0.9.0-py3-none-any.whl", hash = "sha256:5d96d986a21493606a358cae4461bd8cdf83cbf33a5aa950ae629ca3b51467ee"},
{file = "typer-0.9.0.tar.gz", hash = "sha256:50922fd79aea2f4751a8e0408ff10d2662bd0c8bbfa84755a699f3bada2978b2"},
]
[package.dependencies]
click = ">=7.1.1,<9.0.0"
typing-extensions = ">=3.7.4.3"
[package.extras]
all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"]
dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"]
doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"]
test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"]
[[package]] [[package]]
name = "typing-extensions" name = "typing-extensions"
version = "4.6.2" version = "4.6.3"
description = "Backported and Experimental Type Hints for Python 3.7+" description = "Backported and Experimental Type Hints for Python 3.7+"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "typing_extensions-4.6.2-py3-none-any.whl", hash = "sha256:3a8b36f13dd5fdc5d1b16fe317f5668545de77fa0b8e02006381fd49d731ab98"}, {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"},
{file = "typing_extensions-4.6.2.tar.gz", hash = "sha256:06006244c70ac8ee83fa8282cb188f697b8db25bc8b4df07be1873c43897060c"}, {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"},
] ]
[[package]]
name = "typing-inspect"
version = "0.9.0"
description = "Runtime inspection utilities for typing module."
optional = false
python-versions = "*"
files = [
{file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"},
{file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"},
]
[package.dependencies]
mypy-extensions = ">=0.3.0"
typing-extensions = ">=3.7.4"
[[package]] [[package]]
name = "urllib3" name = "urllib3"
version = "2.0.2" version = "2.0.3"
description = "HTTP library with thread-safe connection pooling, file post, and more." description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "urllib3-2.0.2-py3-none-any.whl", hash = "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"}, {file = "urllib3-2.0.3-py3-none-any.whl", hash = "sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1"},
{file = "urllib3-2.0.2.tar.gz", hash = "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc"}, {file = "urllib3-2.0.3.tar.gz", hash = "sha256:bee28b5e56addb8226c96f7f13ac28cb4c301dd5ea8a6ca179c0b9835e032825"},
] ]
[package.extras] [package.extras]
@ -2095,23 +2006,23 @@ test = ["Cython (>=0.29.32,<0.30.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "my
[[package]] [[package]]
name = "virtualenv" name = "virtualenv"
version = "20.23.0" version = "20.23.1"
description = "Virtual Python Environment builder" description = "Virtual Python Environment builder"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "virtualenv-20.23.0-py3-none-any.whl", hash = "sha256:6abec7670e5802a528357fdc75b26b9f57d5d92f29c5462ba0fbe45feacc685e"}, {file = "virtualenv-20.23.1-py3-none-any.whl", hash = "sha256:34da10f14fea9be20e0fd7f04aba9732f84e593dac291b757ce42e3368a39419"},
{file = "virtualenv-20.23.0.tar.gz", hash = "sha256:a85caa554ced0c0afbd0d638e7e2d7b5f92d23478d05d17a76daeac8f279f924"}, {file = "virtualenv-20.23.1.tar.gz", hash = "sha256:8ff19a38c1021c742148edc4f81cb43d7f8c6816d2ede2ab72af5b84c749ade1"},
] ]
[package.dependencies] [package.dependencies]
distlib = ">=0.3.6,<1" distlib = ">=0.3.6,<1"
filelock = ">=3.11,<4" filelock = ">=3.12,<4"
platformdirs = ">=3.2,<4" platformdirs = ">=3.5.1,<4"
[package.extras] [package.extras]
docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.7.1)", "time-machine (>=2.9)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezer (>=0.4.6)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.8)", "time-machine (>=2.9)"]
[[package]] [[package]]
name = "watchfiles" name = "watchfiles"
@ -2395,4 +2306,4 @@ websockets = ["websockets"]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.8" python-versions = "^3.8"
content-hash = "cf0a75f5173e6eb0fa3cd9d8901d4149e104094d08bce7e298d6f8c92954803d" content-hash = "70f20d112a2bbc1300d2cca814b516f45a190d9837b53d90b9cdb005f64eb180"

View File

@ -43,7 +43,7 @@ httpx = { version = ">=0.20.0,<1.0.0", extras = ["http2"], optional = true }
uvicorn = { version = ">=0.20.0,<1.0.0", extras = ["standard"], optional = true } uvicorn = { version = ">=0.20.0,<1.0.0", extras = ["standard"], optional = true }
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pycln = "^2.1.2" ruff = "^0.0.272"
isort = "^5.10.1" isort = "^5.10.1"
black = "^23.1.0" black = "^23.1.0"
nonemoji = "^0.1.2" nonemoji = "^0.1.2"
@ -92,9 +92,16 @@ force_sort_within_sections = true
src_paths = ["nonebot", "tests"] src_paths = ["nonebot", "tests"]
extra_standard_library = ["typing_extensions"] extra_standard_library = ["typing_extensions"]
[tool.pycln] [tool.ruff]
path = "." select = ["E", "W", "F", "UP", "C", "T", "PYI", "PT", "Q"]
all = false ignore = ["E402", "C901"]
line-length = 88
target-version = "py38"
[tool.ruff.flake8-pytest-style]
fixture-parentheses = false
mark-parentheses = false
[tool.pyright] [tool.pyright]
reportShadowedImports = false reportShadowedImports = false

View File

@ -1 +1,3 @@
assert False import pytest
pytest.fail("should not be imported")

View File

@ -1,6 +1,5 @@
from pathlib import Path from pathlib import Path
import nonebot
from nonebot.plugin import PluginManager, _managers from nonebot.plugin import PluginManager, _managers
manager = PluginManager( manager = PluginManager(

View File

@ -1 +1 @@
from .nested_subplugin2 import a # nopycln: import from .nested_subplugin2 import a # noqa: F401

View File

@ -1,4 +1,4 @@
from nonebot.adapters import Event, Message from nonebot.adapters import Message
from nonebot.params import Arg, ArgStr, ArgPlainText from nonebot.params import Arg, ArgStr, ArgPlainText

View File

@ -1 +1 @@
from . import matchers from . import matchers as matchers

View File

@ -4,4 +4,5 @@ test_require = require("export").test
from plugins.export import test from plugins.export import test
assert test is test_require and test() == "export", "Export Require Error" assert test is test_require, "Export Require Error"
assert test() == "export", "Export Require Error"

View File

@ -176,7 +176,8 @@ async def test_http_client(driver: Driver, server_url: URL):
content="test", content="test",
) )
response = await driver.request(request) response = await driver.request(request)
assert response.status_code == 200 and response.content assert response.status_code == 200
assert response.content
data = json.loads(response.content) data = json.loads(response.content)
assert data["method"] == "POST" assert data["method"] == "POST"
assert data["args"] == {"param": "test"} assert data["args"] == {"param": "test"}
@ -187,7 +188,8 @@ async def test_http_client(driver: Driver, server_url: URL):
# post with data body # post with data body
request = Request("POST", server_url, data={"form": "test"}) request = Request("POST", server_url, data={"form": "test"})
response = await driver.request(request) response = await driver.request(request)
assert response.status_code == 200 and response.content assert response.status_code == 200
assert response.content
data = json.loads(response.content) data = json.loads(response.content)
assert data["method"] == "POST" assert data["method"] == "POST"
assert data["form"] == {"form": "test"} assert data["form"] == {"form": "test"}
@ -195,7 +197,8 @@ async def test_http_client(driver: Driver, server_url: URL):
# post with json body # post with json body
request = Request("POST", server_url, json={"json": "test"}) request = Request("POST", server_url, json={"json": "test"})
response = await driver.request(request) response = await driver.request(request)
assert response.status_code == 200 and response.content assert response.status_code == 200
assert response.content
data = json.loads(response.content) data = json.loads(response.content)
assert data["method"] == "POST" assert data["method"] == "POST"
assert data["json"] == {"json": "test"} assert data["json"] == {"json": "test"}
@ -208,7 +211,8 @@ async def test_http_client(driver: Driver, server_url: URL):
files={"test": ("test.txt", b"test")}, files={"test": ("test.txt", b"test")},
) )
response = await driver.request(request) response = await driver.request(request)
assert response.status_code == 200 and response.content assert response.status_code == 200
assert response.content
data = json.loads(response.content) data = json.loads(response.content)
assert data["method"] == "POST" assert data["method"] == "POST"
assert data["form"] == {"form": "test"} assert data["form"] == {"form": "test"}
@ -219,7 +223,7 @@ async def test_http_client(driver: Driver, server_url: URL):
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize( @pytest.mark.parametrize(
"driver, driver_type", ("driver", "driver_type"),
[ [
pytest.param( pytest.param(
"nonebot.drivers.fastapi:Driver+nonebot.drivers.aiohttp:Mixin", "nonebot.drivers.fastapi:Driver+nonebot.drivers.aiohttp:Mixin",

View File

@ -34,7 +34,7 @@ async def test_init():
async def test_get_driver(app: App, monkeypatch: pytest.MonkeyPatch): async def test_get_driver(app: App, monkeypatch: pytest.MonkeyPatch):
with monkeypatch.context() as m: with monkeypatch.context() as m:
m.setattr(nonebot, "_driver", None) m.setattr(nonebot, "_driver", None)
with pytest.raises(ValueError): with pytest.raises(ValueError, match="initialized"):
get_driver() get_driver()
@ -63,7 +63,7 @@ async def test_get_adapter(app: App, monkeypatch: pytest.MonkeyPatch):
assert get_adapters() == {adapter_name: adapter} assert get_adapters() == {adapter_name: adapter}
assert get_adapter(adapter_name) is adapter assert get_adapter(adapter_name) is adapter
assert get_adapter(adapter.__class__) is adapter assert get_adapter(adapter.__class__) is adapter
with pytest.raises(ValueError): with pytest.raises(ValueError, match="registered"):
get_adapter("not exist") get_adapter("not exist")
@ -74,7 +74,8 @@ async def test_run(app: App, monkeypatch: pytest.MonkeyPatch):
def mock_run(*args, **kwargs): def mock_run(*args, **kwargs):
nonlocal runned nonlocal runned
runned = True runned = True
assert args == ("arg",) and kwargs == {"kwarg": "kwarg"} assert args == ("arg",)
assert kwargs == {"kwarg": "kwarg"}
driver = get_driver() driver = get_driver()
@ -89,7 +90,7 @@ async def test_run(app: App, monkeypatch: pytest.MonkeyPatch):
async def test_get_bot(app: App, monkeypatch: pytest.MonkeyPatch): async def test_get_bot(app: App, monkeypatch: pytest.MonkeyPatch):
driver = get_driver() driver = get_driver()
with pytest.raises(ValueError): with pytest.raises(ValueError, match="no bots"):
get_bot() get_bot()
with monkeypatch.context() as m: with monkeypatch.context() as m:

View File

@ -120,7 +120,7 @@ async def test_matcher_overload(app: App):
async def test_matcher_destroy(app: App): async def test_matcher_destroy(app: App):
from plugins.matcher.matcher_process import test_destroy from plugins.matcher.matcher_process import test_destroy
async with app.test_matcher(test_destroy) as ctx: async with app.test_matcher(test_destroy):
assert len(matchers) == 1 assert len(matchers) == 1
assert len(matchers[test_destroy.priority]) == 1 assert len(matchers[test_destroy.priority]) == 1
assert matchers[test_destroy.priority][0] is test_destroy assert matchers[test_destroy.priority][0] is test_destroy

View File

@ -33,6 +33,8 @@ from nonebot.consts import (
CMD_WHITESPACE_KEY, CMD_WHITESPACE_KEY,
) )
UNKNOWN_PARAM = "Unknown parameter"
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_depend(app: App): async def test_depend(app: App):
@ -50,7 +52,8 @@ async def test_depend(app: App):
async with app.test_dependent(depends, allow_types=[DependParam]) as ctx: async with app.test_dependent(depends, allow_types=[DependParam]) as ctx:
ctx.should_return(1) ctx.should_return(1)
assert len(runned) == 1 and runned[0] == 1 assert len(runned) == 1
assert runned[0] == 1
runned.clear() runned.clear()
@ -59,7 +62,8 @@ async def test_depend(app: App):
event_next = make_fake_event()() event_next = make_fake_event()()
ctx.receive_event(bot, event_next) ctx.receive_event(bot, event_next)
assert len(runned) == 2 and runned[0] == runned[1] == 1 assert len(runned) == 2
assert runned[0] == runned[1] == 1
runned.clear() runned.clear()
@ -105,16 +109,15 @@ async def test_bot(app: App):
ctx.pass_params(bot=bot) ctx.pass_params(bot=bot)
ctx.should_return(bot) ctx.should_return(bot)
with pytest.raises(ValueError): with pytest.raises(ValueError, match=UNKNOWN_PARAM):
async with app.test_dependent(not_legacy_bot, allow_types=[BotParam]) as ctx: app.test_dependent(not_legacy_bot, allow_types=[BotParam])
...
async with app.test_dependent(sub_bot, allow_types=[BotParam]) as ctx: async with app.test_dependent(sub_bot, allow_types=[BotParam]) as ctx:
bot = ctx.create_bot(base=FooBot) bot = ctx.create_bot(base=FooBot)
ctx.pass_params(bot=bot) ctx.pass_params(bot=bot)
ctx.should_return(bot) ctx.should_return(bot)
with pytest.raises(TypeMisMatch): with pytest.raises(TypeMisMatch): # noqa: PT012
async with app.test_dependent(sub_bot, allow_types=[BotParam]) as ctx: async with app.test_dependent(sub_bot, allow_types=[BotParam]) as ctx:
bot = ctx.create_bot() bot = ctx.create_bot()
ctx.pass_params(bot=bot) ctx.pass_params(bot=bot)
@ -134,9 +137,8 @@ async def test_bot(app: App):
ctx.pass_params(bot=bot) ctx.pass_params(bot=bot)
ctx.should_return(bot) ctx.should_return(bot)
with pytest.raises(ValueError): with pytest.raises(ValueError, match=UNKNOWN_PARAM):
async with app.test_dependent(not_bot, allow_types=[BotParam]) as ctx: app.test_dependent(not_bot, allow_types=[BotParam])
...
@pytest.mark.asyncio @pytest.mark.asyncio
@ -169,17 +171,14 @@ async def test_event(app: App):
ctx.pass_params(event=fake_event) ctx.pass_params(event=fake_event)
ctx.should_return(fake_event) ctx.should_return(fake_event)
with pytest.raises(ValueError): with pytest.raises(ValueError, match=UNKNOWN_PARAM):
async with app.test_dependent( app.test_dependent(not_legacy_event, allow_types=[EventParam])
not_legacy_event, allow_types=[EventParam]
) as ctx:
...
async with app.test_dependent(sub_event, allow_types=[EventParam]) as ctx: async with app.test_dependent(sub_event, allow_types=[EventParam]) as ctx:
ctx.pass_params(event=fake_fooevent) ctx.pass_params(event=fake_fooevent)
ctx.should_return(fake_fooevent) ctx.should_return(fake_fooevent)
with pytest.raises(TypeMisMatch): with pytest.raises(TypeMisMatch): # noqa: PT012
async with app.test_dependent(sub_event, allow_types=[EventParam]) as ctx: async with app.test_dependent(sub_event, allow_types=[EventParam]) as ctx:
ctx.pass_params(event=fake_event) ctx.pass_params(event=fake_event)
@ -195,9 +194,8 @@ async def test_event(app: App):
ctx.pass_params(event=fake_event) ctx.pass_params(event=fake_event)
ctx.should_return(fake_event) ctx.should_return(fake_event)
with pytest.raises(ValueError): with pytest.raises(ValueError, match=UNKNOWN_PARAM):
async with app.test_dependent(not_event, allow_types=[EventParam]) as ctx: app.test_dependent(not_event, allow_types=[EventParam])
...
async with app.test_dependent( async with app.test_dependent(
event_type, allow_types=[EventParam, DependParam] event_type, allow_types=[EventParam, DependParam]
@ -274,11 +272,8 @@ async def test_state(app: App):
ctx.pass_params(state=fake_state) ctx.pass_params(state=fake_state)
ctx.should_return(fake_state) ctx.should_return(fake_state)
with pytest.raises(ValueError): with pytest.raises(ValueError, match=UNKNOWN_PARAM):
async with app.test_dependent( app.test_dependent(not_legacy_state, allow_types=[StateParam])
not_legacy_state, allow_types=[StateParam]
) as ctx:
...
async with app.test_dependent( async with app.test_dependent(
command, allow_types=[StateParam, DependParam] command, allow_types=[StateParam, DependParam]
@ -398,17 +393,14 @@ async def test_matcher(app: App):
ctx.pass_params(matcher=fake_matcher) ctx.pass_params(matcher=fake_matcher)
ctx.should_return(fake_matcher) ctx.should_return(fake_matcher)
with pytest.raises(ValueError): with pytest.raises(ValueError, match=UNKNOWN_PARAM):
async with app.test_dependent( app.test_dependent(not_legacy_matcher, allow_types=[MatcherParam])
not_legacy_matcher, allow_types=[MatcherParam]
) as ctx:
...
async with app.test_dependent(sub_matcher, allow_types=[MatcherParam]) as ctx: async with app.test_dependent(sub_matcher, allow_types=[MatcherParam]) as ctx:
ctx.pass_params(matcher=foo_matcher) ctx.pass_params(matcher=foo_matcher)
ctx.should_return(foo_matcher) ctx.should_return(foo_matcher)
with pytest.raises(TypeMisMatch): with pytest.raises(TypeMisMatch): # noqa: PT012
async with app.test_dependent(sub_matcher, allow_types=[MatcherParam]) as ctx: async with app.test_dependent(sub_matcher, allow_types=[MatcherParam]) as ctx:
ctx.pass_params(matcher=fake_matcher) ctx.pass_params(matcher=fake_matcher)
@ -426,9 +418,8 @@ async def test_matcher(app: App):
ctx.pass_params(matcher=fake_matcher) ctx.pass_params(matcher=fake_matcher)
ctx.should_return(fake_matcher) ctx.should_return(fake_matcher)
with pytest.raises(ValueError): with pytest.raises(ValueError, match=UNKNOWN_PARAM):
async with app.test_dependent(not_matcher, allow_types=[MatcherParam]) as ctx: app.test_dependent(not_matcher, allow_types=[MatcherParam])
...
event = make_fake_event()() event = make_fake_event()()
fake_matcher.set_receive("test", event) fake_matcher.set_receive("test", event)

View File

@ -47,15 +47,15 @@ async def test_permission(app: App):
async with app.test_api() as ctx: async with app.test_api() as ctx:
bot = ctx.create_bot() bot = ctx.create_bot()
assert await Permission(falsy)(bot, event) == False assert await Permission(falsy)(bot, event) is False
assert await Permission(truthy)(bot, event) == True assert await Permission(truthy)(bot, event) is True
assert await Permission(skipped)(bot, event) == False assert await Permission(skipped)(bot, event) is False
assert await Permission(truthy, falsy)(bot, event) == True assert await Permission(truthy, falsy)(bot, event) is True
assert await Permission(truthy, skipped)(bot, event) == True assert await Permission(truthy, skipped)(bot, event) is True
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize("type, expected", [("message", True), ("notice", False)]) @pytest.mark.parametrize(("type", "expected"), [("message", True), ("notice", False)])
async def test_message(type: str, expected: bool): async def test_message(type: str, expected: bool):
dependent = list(MESSAGE.checkers)[0] dependent = list(MESSAGE.checkers)[0]
checker = dependent.call checker = dependent.call
@ -67,7 +67,7 @@ async def test_message(type: str, expected: bool):
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize("type, expected", [("message", False), ("notice", True)]) @pytest.mark.parametrize(("type", "expected"), [("message", False), ("notice", True)])
async def test_notice(type: str, expected: bool): async def test_notice(type: str, expected: bool):
dependent = list(NOTICE.checkers)[0] dependent = list(NOTICE.checkers)[0]
checker = dependent.call checker = dependent.call
@ -79,7 +79,7 @@ async def test_notice(type: str, expected: bool):
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize("type, expected", [("message", False), ("request", True)]) @pytest.mark.parametrize(("type", "expected"), [("message", False), ("request", True)])
async def test_request(type: str, expected: bool): async def test_request(type: str, expected: bool):
dependent = list(REQUEST.checkers)[0] dependent = list(REQUEST.checkers)[0]
checker = dependent.call checker = dependent.call
@ -91,7 +91,9 @@ async def test_request(type: str, expected: bool):
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize("type, expected", [("message", False), ("meta_event", True)]) @pytest.mark.parametrize(
("type", "expected"), [("message", False), ("meta_event", True)]
)
async def test_metaevent(type: str, expected: bool): async def test_metaevent(type: str, expected: bool):
dependent = list(METAEVENT.checkers)[0] dependent = list(METAEVENT.checkers)[0]
checker = dependent.call checker = dependent.call
@ -104,7 +106,7 @@ async def test_metaevent(type: str, expected: bool):
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize( @pytest.mark.parametrize(
"type, user_id, expected", ("type", "user_id", "expected"),
[ [
("message", "test", True), ("message", "test", True),
("message", "foo", False), ("message", "foo", False),
@ -128,7 +130,7 @@ async def test_superuser(app: App, type: str, user_id: str, expected: bool):
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize( @pytest.mark.parametrize(
"session_ids, session_id, expected", ("session_ids", "session_id", "expected"),
[ [
(("user", "foo"), "user", True), (("user", "foo"), "user", True),
(("user", "foo"), "bar", False), (("user", "foo"), "bar", False),

View File

@ -49,7 +49,9 @@ async def test_load_nested_plugin():
parent_plugin = nonebot.get_plugin("nested") parent_plugin = nonebot.get_plugin("nested")
sub_plugin = nonebot.get_plugin("nested_subplugin") sub_plugin = nonebot.get_plugin("nested_subplugin")
sub_plugin2 = nonebot.get_plugin("nested_subplugin2") sub_plugin2 = nonebot.get_plugin("nested_subplugin2")
assert parent_plugin and sub_plugin and sub_plugin2 assert parent_plugin
assert sub_plugin
assert sub_plugin2
assert sub_plugin.parent_plugin is parent_plugin assert sub_plugin.parent_plugin is parent_plugin
assert sub_plugin2.parent_plugin is parent_plugin assert sub_plugin2.parent_plugin is parent_plugin
assert parent_plugin.sub_plugins == {sub_plugin, sub_plugin2} assert parent_plugin.sub_plugins == {sub_plugin, sub_plugin2}
@ -67,7 +69,7 @@ async def test_load_json():
async def test_load_toml(): async def test_load_toml():
nonebot.load_from_toml("./plugins.toml") nonebot.load_from_toml("./plugins.toml")
with pytest.raises(ValueError): with pytest.raises(ValueError, match="Cannot find"):
nonebot.load_from_toml("./plugins.empty.toml") nonebot.load_from_toml("./plugins.empty.toml")
with pytest.raises(TypeError): with pytest.raises(TypeError):

View File

@ -20,7 +20,7 @@ from nonebot.rule import (
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize( @pytest.mark.parametrize(
"matcher_name, pre_rule_factory, has_permission", ("matcher_name", "pre_rule_factory", "has_permission"),
[ [
pytest.param("matcher_on", None, True), pytest.param("matcher_on", None, True),
pytest.param("matcher_on_metaevent", None, False), pytest.param("matcher_on_metaevent", None, False),

View File

@ -74,11 +74,11 @@ async def test_rule(app: App):
async with app.test_api() as ctx: async with app.test_api() as ctx:
bot = ctx.create_bot() bot = ctx.create_bot()
assert await Rule(falsy)(bot, event, {}) == False assert await Rule(falsy)(bot, event, {}) is False
assert await Rule(truthy)(bot, event, {}) == True assert await Rule(truthy)(bot, event, {}) is True
assert await Rule(skipped)(bot, event, {}) == False assert await Rule(skipped)(bot, event, {}) is False
assert await Rule(truthy, falsy)(bot, event, {}) == False assert await Rule(truthy, falsy)(bot, event, {}) is False
assert await Rule(truthy, skipped)(bot, event, {}) == False assert await Rule(truthy, skipped)(bot, event, {}) is False
@pytest.mark.asyncio @pytest.mark.asyncio
@ -118,7 +118,7 @@ async def test_trie(app: App):
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize( @pytest.mark.parametrize(
"msg, ignorecase, type, text, expected", ("msg", "ignorecase", "type", "text", "expected"),
[ [
("prefix", False, "message", "prefix_", True), ("prefix", False, "message", "prefix_", True),
("prefix", False, "message", "Prefix_", False), ("prefix", False, "message", "Prefix_", False),
@ -158,7 +158,7 @@ async def test_startswith(
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize( @pytest.mark.parametrize(
"msg, ignorecase, type, text, expected", ("msg", "ignorecase", "type", "text", "expected"),
[ [
("suffix", False, "message", "_suffix", True), ("suffix", False, "message", "_suffix", True),
("suffix", False, "message", "_Suffix", False), ("suffix", False, "message", "_Suffix", False),
@ -198,7 +198,7 @@ async def test_endswith(
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize( @pytest.mark.parametrize(
"msg, ignorecase, type, text, expected", ("msg", "ignorecase", "type", "text", "expected"),
[ [
("fullmatch", False, "message", "fullmatch", True), ("fullmatch", False, "message", "fullmatch", True),
("fullmatch", False, "message", "Fullmatch", False), ("fullmatch", False, "message", "Fullmatch", False),
@ -238,7 +238,7 @@ async def test_fullmatch(
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize( @pytest.mark.parametrize(
"kws, type, text, expected", ("kws", "type", "text", "expected"),
[ [
(("key",), "message", "_key_", True), (("key",), "message", "_key_", True),
(("key", "foo"), "message", "_foo_", True), (("key", "foo"), "message", "_foo_", True),
@ -270,26 +270,26 @@ async def test_keyword(
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize( @pytest.mark.parametrize(
"cmds, force_whitespace, cmd, whitespace, arg_text, expected", ("cmds", "force_whitespace", "cmd", "whitespace", "arg_text", "expected"),
[ [
# command tests # command tests
[(("help",),), None, ("help",), None, None, True], ((("help",),), None, ("help",), None, None, True),
[(("help",),), None, ("foo",), None, None, False], ((("help",),), None, ("foo",), None, None, False),
[(("help", "foo"),), None, ("help", "foo"), None, None, True], ((("help", "foo"),), None, ("help", "foo"), None, None, True),
[(("help", "foo"),), None, ("help", "bar"), None, None, False], ((("help", "foo"),), None, ("help", "bar"), None, None, False),
[(("help",), ("foo",)), None, ("help",), None, None, True], ((("help",), ("foo",)), None, ("help",), None, None, True),
[(("help",), ("foo",)), None, ("bar",), None, None, False], ((("help",), ("foo",)), None, ("bar",), None, None, False),
# whitespace tests # whitespace tests
[(("help",),), True, ("help",), " ", "arg", True], ((("help",),), True, ("help",), " ", "arg", True),
[(("help",),), True, ("help",), None, "arg", False], ((("help",),), True, ("help",), None, "arg", False),
[(("help",),), True, ("help",), None, None, True], ((("help",),), True, ("help",), None, None, True),
[(("help",),), False, ("help",), " ", "arg", False], ((("help",),), False, ("help",), " ", "arg", False),
[(("help",),), False, ("help",), None, "arg", True], ((("help",),), False, ("help",), None, "arg", True),
[(("help",),), False, ("help",), None, None, True], ((("help",),), False, ("help",), None, None, True),
[(("help",),), " ", ("help",), " ", "arg", True], ((("help",),), " ", ("help",), " ", "arg", True),
[(("help",),), " ", ("help",), "\n", "arg", False], ((("help",),), " ", ("help",), "\n", "arg", False),
[(("help",),), " ", ("help",), None, "arg", False], ((("help",),), " ", ("help",), None, "arg", False),
[(("help",),), " ", ("help",), None, None, True], ((("help",),), " ", ("help",), None, None, True),
], ],
) )
async def test_command( async def test_command(
@ -424,7 +424,7 @@ async def test_shell_command():
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize( @pytest.mark.parametrize(
"pattern, type, text, expected, matched", ("pattern", "type", "text", "expected", "matched"),
[ [
( (
r"(?P<key>key\d)", r"(?P<key>key\d)",

View File

@ -16,21 +16,21 @@ async def test_matcher_mutex():
event_3 = make_fake_event(_session_id=None)() event_3 = make_fake_event(_session_id=None)()
async with am(event) as ctx: async with am(event) as ctx:
assert ctx == False assert ctx is False
assert not _running_matcher assert not _running_matcher
async with am(event) as ctx: async with am(event) as ctx:
async with am(event_1) as ctx_1: async with am(event_1) as ctx_1:
assert ctx == False assert ctx is False
assert ctx_1 == True assert ctx_1 is True
assert not _running_matcher assert not _running_matcher
async with am(event) as ctx: async with am(event) as ctx:
async with am(event_2) as ctx_2: async with am(event_2) as ctx_2:
assert ctx == False assert ctx is False
assert ctx_2 == False assert ctx_2 is False
assert not _running_matcher assert not _running_matcher
async with am(event_3) as ctx_3: async with am(event_3) as ctx_3:
assert ctx_3 == False assert ctx_3 is False
assert not _running_matcher assert not _running_matcher

View File

@ -118,7 +118,9 @@ def test_dataclass_encoder():
ms = FakeMessageSegment.nested(FakeMessage(FakeMessageSegment.text("text"))) ms = FakeMessageSegment.nested(FakeMessage(FakeMessageSegment.text("text")))
s = json.dumps(ms, cls=DataclassEncoder) s = json.dumps(ms, cls=DataclassEncoder)
assert ( assert s == (
s "{"
== '{"type": "node", "data": {"content": [{"type": "text", "data": {"text": "text"}}]}}' '"type": "node", '
'"data": {"content": [{"type": "text", "data": {"text": "text"}}]}'
"}"
) )