mirror of
https://github.com/nonebot/nonebot2.git
synced 2026-04-15 04:57:25 +00:00
💥 Remove: 移除 Python 3.9 支持 (#3860)
This commit is contained in:
@@ -47,7 +47,7 @@ FrontMatter:
|
||||
|
||||
from importlib.metadata import version
|
||||
import os
|
||||
from typing import Any, Optional, TypeVar, Union, overload
|
||||
from typing import Any, TypeVar, overload
|
||||
|
||||
import loguru
|
||||
|
||||
@@ -65,7 +65,7 @@ except Exception: # pragma: no cover
|
||||
|
||||
A = TypeVar("A", bound=Adapter)
|
||||
|
||||
_driver: Optional[Driver] = None
|
||||
_driver: Driver | None = None
|
||||
|
||||
|
||||
def get_driver() -> Driver:
|
||||
@@ -112,7 +112,7 @@ def get_adapter(name: type[A]) -> A:
|
||||
"""
|
||||
|
||||
|
||||
def get_adapter(name: Union[str, type[Adapter]]) -> Adapter:
|
||||
def get_adapter(name: str | type[Adapter]) -> Adapter:
|
||||
"""获取已注册的 {ref}`nonebot.adapters.Adapter` 实例。
|
||||
|
||||
异常:
|
||||
@@ -196,7 +196,7 @@ def get_asgi() -> Any:
|
||||
return driver.asgi
|
||||
|
||||
|
||||
def get_bot(self_id: Optional[str] = None) -> Bot:
|
||||
def get_bot(self_id: str | None = None) -> Bot:
|
||||
"""获取一个连接到 NoneBot 的 {ref}`nonebot.adapters.Bot` 对象。
|
||||
|
||||
当提供 `self_id` 时,此函数是 `get_bots()[self_id]` 的简写;
|
||||
@@ -277,7 +277,7 @@ def _log_patcher(record: "loguru.Record"):
|
||||
)
|
||||
|
||||
|
||||
def init(*, _env_file: Optional[DOTENV_TYPE] = None, **kwargs: Any) -> None:
|
||||
def init(*, _env_file: DOTENV_TYPE | None = None, **kwargs: Any) -> None:
|
||||
"""初始化 NoneBot 以及 全局 {ref}`nonebot.drivers.Driver` 对象。
|
||||
|
||||
NoneBot 将会从 .env 文件中读取环境信息,并使用相应的 env 文件配置。
|
||||
|
||||
@@ -9,23 +9,22 @@ FrontMatter:
|
||||
description: nonebot.compat 模块
|
||||
"""
|
||||
|
||||
from collections.abc import Generator
|
||||
from collections.abc import Callable, Generator
|
||||
from dataclasses import dataclass, is_dataclass
|
||||
from functools import cached_property, wraps
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Annotated,
|
||||
Any,
|
||||
Callable,
|
||||
Generic,
|
||||
Literal,
|
||||
Optional,
|
||||
Protocol,
|
||||
TypeVar,
|
||||
Union,
|
||||
get_args,
|
||||
get_origin,
|
||||
overload,
|
||||
)
|
||||
from typing_extensions import ParamSpec, Self, get_args, get_origin, is_typeddict
|
||||
from typing_extensions import ParamSpec, Self, is_typeddict
|
||||
|
||||
from pydantic import VERSION, BaseModel
|
||||
|
||||
@@ -129,7 +128,7 @@ if PYDANTIC_V2: # pragma: pydantic-v2
|
||||
|
||||
@classmethod
|
||||
def _inherit_construct(
|
||||
cls, field_info: Optional[BaseFieldInfo] = None, **kwargs: Any
|
||||
cls, field_info: BaseFieldInfo | None = None, **kwargs: Any
|
||||
) -> Self:
|
||||
init_kwargs = {}
|
||||
if field_info:
|
||||
@@ -158,7 +157,7 @@ if PYDANTIC_V2: # pragma: pydantic-v2
|
||||
|
||||
@classmethod
|
||||
def construct(
|
||||
cls, name: str, annotation: Any, field_info: Optional[FieldInfo] = None
|
||||
cls, name: str, annotation: Any, field_info: FieldInfo | None = None
|
||||
) -> Self:
|
||||
"""Construct a ModelField from given infos."""
|
||||
return cls._construct(name, annotation, field_info or FieldInfo())
|
||||
@@ -231,8 +230,8 @@ if PYDANTIC_V2: # pragma: pydantic-v2
|
||||
|
||||
def model_dump(
|
||||
model: BaseModel,
|
||||
include: Optional[set[str]] = None,
|
||||
exclude: Optional[set[str]] = None,
|
||||
include: set[str] | None = None,
|
||||
exclude: set[str] | None = None,
|
||||
by_alias: bool = False,
|
||||
exclude_unset: bool = False,
|
||||
exclude_defaults: bool = False,
|
||||
@@ -251,7 +250,7 @@ if PYDANTIC_V2: # pragma: pydantic-v2
|
||||
"""Validate data with given type."""
|
||||
return TypeAdapter(type_).validate_python(data)
|
||||
|
||||
def type_validate_json(type_: type[T], data: Union[str, bytes]) -> T:
|
||||
def type_validate_json(type_: type[T], data: str | bytes) -> T:
|
||||
"""Validate JSON with given type."""
|
||||
return TypeAdapter(type_).validate_json(data)
|
||||
|
||||
@@ -317,7 +316,7 @@ else: # pragma: pydantic-v1
|
||||
|
||||
@classmethod
|
||||
def _inherit_construct(
|
||||
cls, field_info: Optional[BaseFieldInfo] = None, **kwargs: Any
|
||||
cls, field_info: BaseFieldInfo | None = None, **kwargs: Any
|
||||
):
|
||||
if field_info:
|
||||
init_kwargs = {
|
||||
@@ -350,7 +349,7 @@ else: # pragma: pydantic-v1
|
||||
|
||||
@classmethod
|
||||
def construct(
|
||||
cls, name: str, annotation: Any, field_info: Optional[FieldInfo] = None
|
||||
cls, name: str, annotation: Any, field_info: FieldInfo | None = None
|
||||
) -> Self:
|
||||
"""Construct a ModelField from given infos.
|
||||
|
||||
@@ -375,7 +374,7 @@ else: # pragma: pydantic-v1
|
||||
self,
|
||||
type: type[T],
|
||||
*,
|
||||
config: Optional[ConfigDict] = ...,
|
||||
config: ConfigDict | None = ...,
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
@@ -383,14 +382,14 @@ else: # pragma: pydantic-v1
|
||||
self,
|
||||
type: Any,
|
||||
*,
|
||||
config: Optional[ConfigDict] = ...,
|
||||
config: ConfigDict | None = ...,
|
||||
) -> None: ...
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: Any,
|
||||
*,
|
||||
config: Optional[ConfigDict] = None,
|
||||
config: ConfigDict | None = None,
|
||||
) -> None:
|
||||
self.type = type
|
||||
self.config = config
|
||||
@@ -398,7 +397,7 @@ else: # pragma: pydantic-v1
|
||||
def validate_python(self, value: Any) -> T:
|
||||
return type_validate_python(self.type, value)
|
||||
|
||||
def validate_json(self, value: Union[str, bytes]) -> T:
|
||||
def validate_json(self, value: str | bytes) -> T:
|
||||
return type_validate_json(self.type, value)
|
||||
|
||||
@overload
|
||||
@@ -407,7 +406,7 @@ else: # pragma: pydantic-v1
|
||||
/,
|
||||
*fields: str,
|
||||
mode: Literal["before"],
|
||||
check_fields: Optional[bool] = None,
|
||||
check_fields: bool | None = None,
|
||||
): ...
|
||||
|
||||
@overload
|
||||
@@ -416,7 +415,7 @@ else: # pragma: pydantic-v1
|
||||
/,
|
||||
*fields: str,
|
||||
mode: Literal["after"] = ...,
|
||||
check_fields: Optional[bool] = None,
|
||||
check_fields: bool | None = None,
|
||||
): ...
|
||||
|
||||
def field_validator(
|
||||
@@ -424,7 +423,7 @@ else: # pragma: pydantic-v1
|
||||
/,
|
||||
*fields: str,
|
||||
mode: Literal["before", "after"] = "after",
|
||||
check_fields: Optional[bool] = None,
|
||||
check_fields: bool | None = None,
|
||||
):
|
||||
if mode == "before":
|
||||
return validator(
|
||||
@@ -458,8 +457,8 @@ else: # pragma: pydantic-v1
|
||||
|
||||
def model_dump(
|
||||
model: BaseModel,
|
||||
include: Optional[set[str]] = None,
|
||||
exclude: Optional[set[str]] = None,
|
||||
include: set[str] | None = None,
|
||||
exclude: set[str] | None = None,
|
||||
by_alias: bool = False,
|
||||
exclude_unset: bool = False,
|
||||
exclude_defaults: bool = False,
|
||||
@@ -490,7 +489,7 @@ else: # pragma: pydantic-v1
|
||||
"""Validate data with given type."""
|
||||
return parse_obj_as(type_, data)
|
||||
|
||||
def type_validate_json(type_: type[T], data: Union[str, bytes]) -> T:
|
||||
def type_validate_json(type_: type[T], data: str | bytes) -> T:
|
||||
"""Validate JSON with given type."""
|
||||
return parse_raw_as(type_, data)
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@ from ipaddress import IPv4Address
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Optional, Union
|
||||
from typing_extensions import TypeAlias, get_args, get_origin
|
||||
from typing import TYPE_CHECKING, Any, TypeAlias, get_args, get_origin
|
||||
|
||||
from dotenv import dotenv_values
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -41,9 +40,7 @@ from nonebot.log import logger
|
||||
from nonebot.typing import origin_is_union
|
||||
from nonebot.utils import deep_update, lenient_issubclass, type_is_complex
|
||||
|
||||
DOTENV_TYPE: TypeAlias = Union[
|
||||
Path, str, list[Union[Path, str]], tuple[Union[Path, str], ...]
|
||||
]
|
||||
DOTENV_TYPE: TypeAlias = Path | str | list[Path | str] | tuple[Path | str, ...]
|
||||
|
||||
ENV_FILE_SENTINEL = Path("")
|
||||
|
||||
@@ -84,10 +81,10 @@ class DotEnvSettingsSource(BaseSettingsSource):
|
||||
def __init__(
|
||||
self,
|
||||
settings_cls: type[BaseModel],
|
||||
env_file: Optional[DOTENV_TYPE],
|
||||
env_file: DOTENV_TYPE | None,
|
||||
env_file_encoding: str,
|
||||
case_sensitive: Optional[bool] = False,
|
||||
env_nested_delimiter: Optional[str] = None,
|
||||
case_sensitive: bool | None = False,
|
||||
env_nested_delimiter: str | None = None,
|
||||
) -> None:
|
||||
super().__init__(settings_cls)
|
||||
self.env_file = env_file
|
||||
@@ -108,17 +105,17 @@ class DotEnvSettingsSource(BaseSettingsSource):
|
||||
return False, False
|
||||
|
||||
def _parse_env_vars(
|
||||
self, env_vars: Mapping[str, Optional[str]]
|
||||
) -> dict[str, Optional[str]]:
|
||||
self, env_vars: Mapping[str, str | None]
|
||||
) -> dict[str, str | None]:
|
||||
return {
|
||||
self._apply_case_sensitive(key): value for key, value in env_vars.items()
|
||||
}
|
||||
|
||||
def _read_env_file(self, file_path: Path) -> dict[str, Optional[str]]:
|
||||
def _read_env_file(self, file_path: Path) -> dict[str, str | None]:
|
||||
file_vars = dotenv_values(file_path, encoding=self.env_file_encoding)
|
||||
return self._parse_env_vars(file_vars)
|
||||
|
||||
def _read_env_files(self) -> dict[str, Optional[str]]:
|
||||
def _read_env_files(self) -> dict[str, str | None]:
|
||||
env_files = self.env_file
|
||||
if env_files is None:
|
||||
return {}
|
||||
@@ -126,16 +123,14 @@ class DotEnvSettingsSource(BaseSettingsSource):
|
||||
if isinstance(env_files, (str, os.PathLike)):
|
||||
env_files = [env_files]
|
||||
|
||||
dotenv_vars: dict[str, Optional[str]] = {}
|
||||
dotenv_vars: dict[str, str | None] = {}
|
||||
for env_file in env_files:
|
||||
env_path = Path(env_file).expanduser()
|
||||
if env_path.is_file():
|
||||
dotenv_vars.update(self._read_env_file(env_path))
|
||||
return dotenv_vars
|
||||
|
||||
def _next_field(
|
||||
self, field: Optional[ModelField], key: str
|
||||
) -> Optional[ModelField]:
|
||||
def _next_field(self, field: ModelField | None, key: str) -> ModelField | None:
|
||||
if not field or origin_is_union(get_origin(field.annotation)):
|
||||
return None
|
||||
elif field.annotation and lenient_issubclass(field.annotation, BaseModel):
|
||||
@@ -147,8 +142,8 @@ class DotEnvSettingsSource(BaseSettingsSource):
|
||||
def _explode_env_vars(
|
||||
self,
|
||||
field: ModelField,
|
||||
env_vars: dict[str, Optional[str]],
|
||||
env_file_vars: dict[str, Optional[str]],
|
||||
env_vars: dict[str, str | None],
|
||||
env_file_vars: dict[str, str | None],
|
||||
) -> dict[str, Any]:
|
||||
if self.env_nested_delimiter is None:
|
||||
return {}
|
||||
@@ -164,7 +159,7 @@ class DotEnvSettingsSource(BaseSettingsSource):
|
||||
|
||||
_, *keys, last_key = env_name.split(self.env_nested_delimiter)
|
||||
env_var = result
|
||||
target_field: Optional[ModelField] = field
|
||||
target_field: ModelField | None = field
|
||||
for key in keys:
|
||||
target_field = self._next_field(target_field, key)
|
||||
env_var = env_var.setdefault(key, {})
|
||||
@@ -293,18 +288,18 @@ class DotEnvSettingsSource(BaseSettingsSource):
|
||||
if PYDANTIC_V2: # pragma: pydantic-v2
|
||||
|
||||
class SettingsConfig(ConfigDict, total=False):
|
||||
env_file: Optional[DOTENV_TYPE]
|
||||
env_file: DOTENV_TYPE | None
|
||||
env_file_encoding: str
|
||||
case_sensitive: bool
|
||||
env_nested_delimiter: Optional[str]
|
||||
env_nested_delimiter: str | None
|
||||
|
||||
else: # pragma: pydantic-v1
|
||||
|
||||
class SettingsConfig(ConfigDict):
|
||||
env_file: Optional[DOTENV_TYPE]
|
||||
env_file: DOTENV_TYPE | None
|
||||
env_file_encoding: str
|
||||
case_sensitive: bool
|
||||
env_nested_delimiter: Optional[str]
|
||||
env_nested_delimiter: str | None
|
||||
|
||||
|
||||
class BaseSettings(BaseModel):
|
||||
@@ -332,9 +327,9 @@ class BaseSettings(BaseModel):
|
||||
|
||||
def __init__(
|
||||
__settings_self__, # pyright: ignore[reportSelfClsParameterName]
|
||||
_env_file: Optional[DOTENV_TYPE] = ENV_FILE_SENTINEL,
|
||||
_env_file_encoding: Optional[str] = None,
|
||||
_env_nested_delimiter: Optional[str] = None,
|
||||
_env_file: DOTENV_TYPE | None = ENV_FILE_SENTINEL,
|
||||
_env_file_encoding: str | None = None,
|
||||
_env_nested_delimiter: str | None = None,
|
||||
**values: Any,
|
||||
) -> None:
|
||||
settings_config = model_config(__settings_self__.__class__)
|
||||
@@ -372,9 +367,9 @@ class BaseSettings(BaseModel):
|
||||
def _settings_build_values(
|
||||
settings_cls: type[BaseModel],
|
||||
init_kwargs: dict[str, Any],
|
||||
env_file: Optional[DOTENV_TYPE],
|
||||
env_file: DOTENV_TYPE | None,
|
||||
env_file_encoding: str,
|
||||
env_nested_delimiter: Optional[str],
|
||||
env_nested_delimiter: str | None,
|
||||
) -> dict[str, Any]:
|
||||
init_settings = InitSettingsSource(settings_cls, init_kwargs=init_kwargs)
|
||||
env_settings = DotEnvSettingsSource(
|
||||
@@ -409,7 +404,7 @@ class Config(BaseSettings):
|
||||
"""
|
||||
|
||||
if TYPE_CHECKING:
|
||||
_env_file: Optional[DOTENV_TYPE] = ".env", ".env.prod"
|
||||
_env_file: DOTENV_TYPE | None = ".env", ".env.prod"
|
||||
|
||||
# nonebot configs
|
||||
driver: str = "~fastapi"
|
||||
@@ -425,7 +420,7 @@ class Config(BaseSettings):
|
||||
"""NoneBot {ref}`nonebot.drivers.ReverseDriver` 服务端监听的 IP/主机名。"""
|
||||
port: int = Field(default=8080, ge=1, le=65535)
|
||||
"""NoneBot {ref}`nonebot.drivers.ReverseDriver` 服务端监听的端口。"""
|
||||
log_level: Union[int, str] = LegacyUnionField(default="INFO")
|
||||
log_level: int | str = LegacyUnionField(default="INFO")
|
||||
"""NoneBot 日志输出等级,可以为 `int` 类型等级或等级名称。
|
||||
|
||||
参考 [记录日志](https://nonebot.dev/docs/appendices/log),[loguru 日志等级](https://loguru.readthedocs.io/en/stable/api/logger.html#levels)。
|
||||
@@ -442,7 +437,7 @@ class Config(BaseSettings):
|
||||
"""
|
||||
|
||||
# bot connection configs
|
||||
api_timeout: Optional[float] = 30.0
|
||||
api_timeout: float | None = 30.0
|
||||
"""API 请求超时时间,单位: 秒。"""
|
||||
|
||||
# bot runtime configs
|
||||
|
||||
@@ -8,11 +8,11 @@ FrontMatter:
|
||||
"""
|
||||
|
||||
import abc
|
||||
from collections.abc import Awaitable, Iterable
|
||||
from collections.abc import Awaitable, Callable, Iterable
|
||||
from dataclasses import dataclass, field
|
||||
from functools import partial
|
||||
import inspect
|
||||
from typing import Any, Callable, Generic, Optional, TypeVar, cast
|
||||
from typing import Any, Generic, TypeVar, cast
|
||||
|
||||
import anyio
|
||||
from exceptiongroup import BaseExceptionGroup, catch
|
||||
@@ -47,13 +47,13 @@ class Param(abc.ABC, FieldInfo):
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, param: inspect.Parameter, allow_types: tuple[type["Param"], ...]
|
||||
) -> Optional["Param"]:
|
||||
) -> "Param | None":
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def _check_parameterless(
|
||||
cls, value: Any, allow_types: tuple[type["Param"], ...]
|
||||
) -> Optional["Param"]:
|
||||
) -> "Param | None":
|
||||
return
|
||||
|
||||
@abc.abstractmethod
|
||||
@@ -92,7 +92,7 @@ class Dependent(Generic[R]):
|
||||
)
|
||||
|
||||
async def __call__(self, **kwargs: Any) -> R:
|
||||
exception: Optional[BaseExceptionGroup[SkippedException]] = None
|
||||
exception: BaseExceptionGroup[SkippedException] | None = None
|
||||
|
||||
def _handle_skipped(exc_group: BaseExceptionGroup[SkippedException]):
|
||||
nonlocal exception
|
||||
@@ -167,7 +167,7 @@ class Dependent(Generic[R]):
|
||||
cls,
|
||||
*,
|
||||
call: _DependentCallable[R],
|
||||
parameterless: Optional[Iterable[Any]] = None,
|
||||
parameterless: Iterable[Any] | None = None,
|
||||
allow_types: Iterable[type[Param]],
|
||||
) -> "Dependent[R]":
|
||||
allow_types = tuple(allow_types)
|
||||
|
||||
@@ -6,8 +6,9 @@ FrontMatter:
|
||||
description: nonebot.dependencies.utils 模块
|
||||
"""
|
||||
|
||||
from collections.abc import Callable
|
||||
import inspect
|
||||
from typing import Any, Callable, ForwardRef, cast
|
||||
from typing import Any, ForwardRef, cast
|
||||
from typing_extensions import TypeAliasType
|
||||
|
||||
from loguru import logger
|
||||
|
||||
@@ -19,7 +19,7 @@ FrontMatter:
|
||||
|
||||
from collections.abc import AsyncGenerator
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import TYPE_CHECKING, Optional, Union
|
||||
from typing import TYPE_CHECKING
|
||||
from typing_extensions import override
|
||||
|
||||
from multidict import CIMultiDict
|
||||
@@ -62,11 +62,11 @@ class Session(HTTPClientSession):
|
||||
params: QueryTypes = None,
|
||||
headers: HeaderTypes = None,
|
||||
cookies: CookieTypes = None,
|
||||
version: Union[str, HTTPVersion] = HTTPVersion.H11,
|
||||
version: str | HTTPVersion = HTTPVersion.H11,
|
||||
timeout: TimeoutTypes = None,
|
||||
proxy: Optional[str] = None,
|
||||
proxy: str | None = None,
|
||||
):
|
||||
self._client: Optional[aiohttp.ClientSession] = None
|
||||
self._client: aiohttp.ClientSession | None = None
|
||||
|
||||
self._params = URL.build(query=params).query if params is not None else None
|
||||
|
||||
@@ -279,9 +279,9 @@ class Mixin(HTTPClientMixin, WebSocketClientMixin):
|
||||
params: QueryTypes = None,
|
||||
headers: HeaderTypes = None,
|
||||
cookies: CookieTypes = None,
|
||||
version: Union[str, HTTPVersion] = HTTPVersion.H11,
|
||||
version: str | HTTPVersion = HTTPVersion.H11,
|
||||
timeout: TimeoutTypes = None,
|
||||
proxy: Optional[str] = None,
|
||||
proxy: str | None = None,
|
||||
) -> Session:
|
||||
return Session(
|
||||
params=params,
|
||||
|
||||
@@ -20,7 +20,7 @@ FrontMatter:
|
||||
import contextlib
|
||||
from functools import wraps
|
||||
import logging
|
||||
from typing import Any, Optional, Union
|
||||
from typing import Any
|
||||
from typing_extensions import override
|
||||
|
||||
from pydantic import BaseModel
|
||||
@@ -63,23 +63,23 @@ def catch_closed(func):
|
||||
class Config(BaseModel):
|
||||
"""FastAPI 驱动框架设置,详情参考 FastAPI 文档"""
|
||||
|
||||
fastapi_openapi_url: Optional[str] = None
|
||||
fastapi_openapi_url: str | None = None
|
||||
"""`openapi.json` 地址,默认为 `None` 即关闭"""
|
||||
fastapi_docs_url: Optional[str] = None
|
||||
fastapi_docs_url: str | None = None
|
||||
"""`swagger` 地址,默认为 `None` 即关闭"""
|
||||
fastapi_redoc_url: Optional[str] = None
|
||||
fastapi_redoc_url: str | None = None
|
||||
"""`redoc` 地址,默认为 `None` 即关闭"""
|
||||
fastapi_include_adapter_schema: bool = True
|
||||
"""是否包含适配器路由的 schema,默认为 `True`"""
|
||||
fastapi_reload: bool = False
|
||||
"""开启/关闭冷重载"""
|
||||
fastapi_reload_dirs: Optional[list[str]] = None
|
||||
fastapi_reload_dirs: list[str] | None = None
|
||||
"""重载监控文件夹列表,默认为 uvicorn 默认值"""
|
||||
fastapi_reload_delay: float = 0.25
|
||||
"""重载延迟,默认为 uvicorn 默认值"""
|
||||
fastapi_reload_includes: Optional[list[str]] = None
|
||||
fastapi_reload_includes: list[str] | None = None
|
||||
"""要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值"""
|
||||
fastapi_reload_excludes: Optional[list[str]] = None
|
||||
fastapi_reload_excludes: list[str] | None = None
|
||||
"""不要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值"""
|
||||
fastapi_extra: dict[str, Any] = {}
|
||||
"""传递给 `FastAPI` 的其他参数。"""
|
||||
@@ -160,10 +160,10 @@ class Driver(BaseDriver, ASGIMixin):
|
||||
@override
|
||||
def run(
|
||||
self,
|
||||
host: Optional[str] = None,
|
||||
port: Optional[int] = None,
|
||||
host: str | None = None,
|
||||
port: int | None = None,
|
||||
*args,
|
||||
app: Optional[str] = None,
|
||||
app: str | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""使用 `uvicorn` 启动 FastAPI"""
|
||||
@@ -206,8 +206,8 @@ class Driver(BaseDriver, ASGIMixin):
|
||||
with contextlib.suppress(Exception):
|
||||
json = await request.json()
|
||||
|
||||
data: Optional[dict] = None
|
||||
files: Optional[list[tuple[str, FileTypes]]] = None
|
||||
data: dict | None = None
|
||||
files: list[tuple[str, FileTypes]] | None = None
|
||||
with contextlib.suppress(Exception):
|
||||
form = await request.form()
|
||||
data = {}
|
||||
@@ -280,7 +280,7 @@ class FastAPIWebSocket(BaseWebSocket):
|
||||
await self.websocket.close(code, reason)
|
||||
|
||||
@override
|
||||
async def receive(self) -> Union[str, bytes]:
|
||||
async def receive(self) -> str | bytes:
|
||||
# assert self.websocket.application_state == WebSocketState.CONNECTED
|
||||
msg = await self.websocket.receive()
|
||||
if msg["type"] == "websocket.disconnect":
|
||||
|
||||
@@ -18,7 +18,7 @@ FrontMatter:
|
||||
"""
|
||||
|
||||
from collections.abc import AsyncGenerator
|
||||
from typing import TYPE_CHECKING, Optional, Union
|
||||
from typing import TYPE_CHECKING
|
||||
from typing_extensions import override
|
||||
|
||||
from multidict import CIMultiDict
|
||||
@@ -58,11 +58,11 @@ class Session(HTTPClientSession):
|
||||
params: QueryTypes = None,
|
||||
headers: HeaderTypes = None,
|
||||
cookies: CookieTypes = None,
|
||||
version: Union[str, HTTPVersion] = HTTPVersion.H11,
|
||||
version: str | HTTPVersion = HTTPVersion.H11,
|
||||
timeout: TimeoutTypes = None,
|
||||
proxy: Optional[str] = None,
|
||||
proxy: str | None = None,
|
||||
):
|
||||
self._client: Optional[httpx.AsyncClient] = None
|
||||
self._client: httpx.AsyncClient | None = None
|
||||
|
||||
self._params = (
|
||||
tuple(URL.build(query=params).query.items()) if params is not None else None
|
||||
@@ -216,9 +216,9 @@ class Mixin(HTTPClientMixin):
|
||||
params: QueryTypes = None,
|
||||
headers: HeaderTypes = None,
|
||||
cookies: CookieTypes = None,
|
||||
version: Union[str, HTTPVersion] = HTTPVersion.H11,
|
||||
version: str | HTTPVersion = HTTPVersion.H11,
|
||||
timeout: TimeoutTypes = None,
|
||||
proxy: Optional[str] = None,
|
||||
proxy: str | None = None,
|
||||
) -> Session:
|
||||
return Session(
|
||||
params=params,
|
||||
|
||||
@@ -12,7 +12,6 @@ FrontMatter:
|
||||
"""
|
||||
|
||||
import signal
|
||||
from typing import Optional
|
||||
from typing_extensions import override
|
||||
|
||||
import anyio
|
||||
@@ -112,7 +111,7 @@ class Driver(BaseDriver):
|
||||
if not self.should_exit.is_set():
|
||||
logger.info("Application startup completed.")
|
||||
|
||||
async def _listen_exit(self, tg: Optional[TaskGroup] = None):
|
||||
async def _listen_exit(self, tg: TaskGroup | None = None):
|
||||
await self.should_exit.wait()
|
||||
|
||||
if tg is not None:
|
||||
|
||||
@@ -19,7 +19,7 @@ FrontMatter:
|
||||
|
||||
import asyncio
|
||||
from functools import wraps
|
||||
from typing import Any, Optional, Union, cast
|
||||
from typing import Any, cast
|
||||
from typing_extensions import override
|
||||
|
||||
from pydantic import BaseModel
|
||||
@@ -65,13 +65,13 @@ class Config(BaseModel):
|
||||
|
||||
quart_reload: bool = False
|
||||
"""开启/关闭冷重载"""
|
||||
quart_reload_dirs: Optional[list[str]] = None
|
||||
quart_reload_dirs: list[str] | None = None
|
||||
"""重载监控文件夹列表,默认为 uvicorn 默认值"""
|
||||
quart_reload_delay: float = 0.25
|
||||
"""重载延迟,默认为 uvicorn 默认值"""
|
||||
quart_reload_includes: Optional[list[str]] = None
|
||||
quart_reload_includes: list[str] | None = None
|
||||
"""要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值"""
|
||||
quart_reload_excludes: Optional[list[str]] = None
|
||||
quart_reload_excludes: list[str] | None = None
|
||||
"""不要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值"""
|
||||
quart_extra: dict[str, Any] = {}
|
||||
"""传递给 `Quart` 的其他参数。"""
|
||||
@@ -141,10 +141,10 @@ class Driver(BaseDriver, ASGIMixin):
|
||||
@override
|
||||
def run(
|
||||
self,
|
||||
host: Optional[str] = None,
|
||||
port: Optional[int] = None,
|
||||
host: str | None = None,
|
||||
port: int | None = None,
|
||||
*args,
|
||||
app: Optional[str] = None,
|
||||
app: str | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""使用 `uvicorn` 启动 Quart"""
|
||||
@@ -257,7 +257,7 @@ class WebSocket(BaseWebSocket):
|
||||
|
||||
@override
|
||||
@catch_closed
|
||||
async def receive(self) -> Union[str, bytes]:
|
||||
async def receive(self) -> str | bytes:
|
||||
return await self.websocket.receive()
|
||||
|
||||
@override
|
||||
|
||||
@@ -17,12 +17,12 @@ FrontMatter:
|
||||
description: nonebot.drivers.websockets 模块
|
||||
"""
|
||||
|
||||
from collections.abc import AsyncGenerator
|
||||
from collections.abc import AsyncGenerator, Callable
|
||||
from contextlib import asynccontextmanager
|
||||
from functools import wraps
|
||||
import logging
|
||||
from types import CoroutineType
|
||||
from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union
|
||||
from typing import TYPE_CHECKING, Any, TypeVar
|
||||
from typing_extensions import ParamSpec, override
|
||||
|
||||
from nonebot.drivers import Request, Timeout, WebSocketClientMixin, combine_driver
|
||||
@@ -108,7 +108,7 @@ class WebSocket(BaseWebSocket):
|
||||
|
||||
@override
|
||||
@catch_closed
|
||||
async def receive(self) -> Union[str, bytes]:
|
||||
async def receive(self) -> str | bytes:
|
||||
return await self.websocket.recv()
|
||||
|
||||
@override
|
||||
|
||||
@@ -31,7 +31,7 @@ FrontMatter:
|
||||
description: nonebot.exception 模块
|
||||
"""
|
||||
|
||||
from typing import Any, Optional
|
||||
from typing import Any
|
||||
|
||||
from nonebot.compat import ModelField
|
||||
|
||||
@@ -47,7 +47,7 @@ class NoneBotException(Exception):
|
||||
class ParserExit(NoneBotException):
|
||||
"""{ref}`nonebot.rule.shell_command` 处理消息失败时返回的异常。"""
|
||||
|
||||
def __init__(self, status: int = 0, message: Optional[str] = None) -> None:
|
||||
def __init__(self, status: int = 0, message: str | None = None) -> None:
|
||||
self.status = status
|
||||
self.message = message
|
||||
|
||||
@@ -232,7 +232,7 @@ class DriverException(NoneBotException):
|
||||
class WebSocketClosed(DriverException):
|
||||
"""WebSocket 连接已关闭。"""
|
||||
|
||||
def __init__(self, code: int, reason: Optional[str] = None) -> None:
|
||||
def __init__(self, code: int, reason: str | None = None) -> None:
|
||||
self.code = code
|
||||
self.reason = reason
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import abc
|
||||
from functools import partial
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, Optional, Protocol, Union
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, Protocol
|
||||
|
||||
import anyio
|
||||
from exceptiongroup import BaseExceptionGroup, catch
|
||||
@@ -77,7 +77,7 @@ class Bot(abc.ABC):
|
||||
|
||||
result: Any = None
|
||||
skip_calling_api: bool = False
|
||||
exception: Optional[Exception] = None
|
||||
exception: Exception | None = None
|
||||
|
||||
if self._calling_api_hook:
|
||||
logger.debug("Running CallingAPI hooks...")
|
||||
@@ -180,7 +180,7 @@ class Bot(abc.ABC):
|
||||
async def send(
|
||||
self,
|
||||
event: "Event",
|
||||
message: Union[str, "Message", "MessageSegment"],
|
||||
message: "str | Message | MessageSegment",
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""调用机器人基础发送消息接口
|
||||
|
||||
@@ -5,11 +5,9 @@ from dataclasses import asdict, dataclass, field
|
||||
from typing import ( # noqa: UP035
|
||||
Any,
|
||||
Generic,
|
||||
Optional,
|
||||
SupportsIndex,
|
||||
Type,
|
||||
TypeVar,
|
||||
Union,
|
||||
overload,
|
||||
)
|
||||
from typing_extensions import Self
|
||||
@@ -51,10 +49,10 @@ class MessageSegment(abc.ABC, Generic[TM]):
|
||||
) -> bool:
|
||||
return not self == other
|
||||
|
||||
def __add__(self, other: Union[str, Self, Iterable[Self]]) -> TM:
|
||||
def __add__(self, other: str | Self | Iterable[Self]) -> TM:
|
||||
return self.get_message_class()(self) + other
|
||||
|
||||
def __radd__(self, other: Union[str, Self, Iterable[Self]]) -> TM:
|
||||
def __radd__(self, other: str | Self | Iterable[Self]) -> TM:
|
||||
return self.get_message_class()(other) + self
|
||||
|
||||
@classmethod
|
||||
@@ -87,7 +85,7 @@ class MessageSegment(abc.ABC, Generic[TM]):
|
||||
def items(self):
|
||||
return asdict(self).items()
|
||||
|
||||
def join(self, iterable: Iterable[Union[Self, TM]]) -> TM:
|
||||
def join(self, iterable: Iterable[Self | TM]) -> TM:
|
||||
return self.get_message_class()(self).join(iterable)
|
||||
|
||||
def copy(self) -> Self:
|
||||
@@ -109,7 +107,7 @@ class Message(list[TMS], abc.ABC):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: Union[str, None, Iterable[TMS], TMS] = None,
|
||||
message: str | None | Iterable[TMS] | TMS = None,
|
||||
):
|
||||
super().__init__()
|
||||
if message is None:
|
||||
@@ -124,7 +122,7 @@ class Message(list[TMS], abc.ABC):
|
||||
self.extend(self._construct(message)) # pragma: no cover
|
||||
|
||||
@classmethod
|
||||
def template(cls, format_string: Union[str, TM]) -> MessageTemplate[Self]:
|
||||
def template(cls, format_string: str | TM) -> MessageTemplate[Self]:
|
||||
"""创建消息模板。
|
||||
|
||||
用法和 `str.format` 大致相同,支持以 `Message` 对象作为消息模板并输出消息对象。
|
||||
@@ -177,17 +175,17 @@ class Message(list[TMS], abc.ABC):
|
||||
raise NotImplementedError
|
||||
|
||||
def __add__( # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
self, other: Union[str, TMS, Iterable[TMS]]
|
||||
self, other: str | TMS | Iterable[TMS]
|
||||
) -> Self:
|
||||
result = self.copy()
|
||||
result += other
|
||||
return result
|
||||
|
||||
def __radd__(self, other: Union[str, TMS, Iterable[TMS]]) -> Self:
|
||||
def __radd__(self, other: str | TMS | Iterable[TMS]) -> Self:
|
||||
result = self.__class__(other)
|
||||
return result + self
|
||||
|
||||
def __iadd__(self, other: Union[str, TMS, Iterable[TMS]]) -> Self:
|
||||
def __iadd__(self, other: str | TMS | Iterable[TMS]) -> Self:
|
||||
if isinstance(other, str):
|
||||
self.extend(self._construct(other))
|
||||
elif isinstance(other, MessageSegment):
|
||||
@@ -255,14 +253,8 @@ class Message(list[TMS], abc.ABC):
|
||||
|
||||
def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
self,
|
||||
args: Union[
|
||||
str,
|
||||
tuple[str, int],
|
||||
tuple[str, slice],
|
||||
int,
|
||||
slice,
|
||||
],
|
||||
) -> Union[TMS, Self]:
|
||||
args: str | tuple[str, int] | tuple[str, slice] | int | slice,
|
||||
) -> TMS | Self:
|
||||
arg1, arg2 = args if isinstance(args, tuple) else (args, None)
|
||||
if isinstance(arg1, int) and arg2 is None:
|
||||
return super().__getitem__(arg1)
|
||||
@@ -278,7 +270,7 @@ class Message(list[TMS], abc.ABC):
|
||||
raise ValueError("Incorrect arguments to slice") # pragma: no cover
|
||||
|
||||
def __contains__( # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
self, value: Union[TMS, str]
|
||||
self, value: TMS | str
|
||||
) -> bool:
|
||||
"""检查消息段是否存在
|
||||
|
||||
@@ -291,11 +283,11 @@ class Message(list[TMS], abc.ABC):
|
||||
return next((seg for seg in self if seg.type == value), None) is not None
|
||||
return super().__contains__(value)
|
||||
|
||||
def has(self, value: Union[TMS, str]) -> bool:
|
||||
def has(self, value: TMS | str) -> bool:
|
||||
"""与 {ref}``__contains__` <nonebot.adapters.Message.__contains__>` 相同"""
|
||||
return value in self
|
||||
|
||||
def index(self, value: Union[TMS, str], *args: SupportsIndex) -> int:
|
||||
def index(self, value: TMS | str, *args: SupportsIndex) -> int:
|
||||
"""索引消息段
|
||||
|
||||
参数:
|
||||
@@ -315,7 +307,7 @@ class Message(list[TMS], abc.ABC):
|
||||
return super().index(first_segment, *args)
|
||||
return super().index(value, *args)
|
||||
|
||||
def get(self, type_: str, count: Optional[int] = None) -> Self:
|
||||
def get(self, type_: str, count: int | None = None) -> Self:
|
||||
"""获取指定类型的消息段
|
||||
|
||||
参数:
|
||||
@@ -339,7 +331,7 @@ class Message(list[TMS], abc.ABC):
|
||||
filtered.append(seg)
|
||||
return filtered
|
||||
|
||||
def count(self, value: Union[TMS, str]) -> int:
|
||||
def count(self, value: TMS | str) -> int:
|
||||
"""计算指定消息段的个数
|
||||
|
||||
参数:
|
||||
@@ -350,7 +342,7 @@ class Message(list[TMS], abc.ABC):
|
||||
"""
|
||||
return len(self[value]) if isinstance(value, str) else super().count(value)
|
||||
|
||||
def only(self, value: Union[TMS, str]) -> bool:
|
||||
def only(self, value: TMS | str) -> bool:
|
||||
"""检查消息中是否仅包含指定消息段
|
||||
|
||||
参数:
|
||||
@@ -364,7 +356,7 @@ class Message(list[TMS], abc.ABC):
|
||||
return all(seg == value for seg in self)
|
||||
|
||||
def append( # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
self, obj: Union[str, TMS]
|
||||
self, obj: str | TMS
|
||||
) -> Self:
|
||||
"""添加一个消息段到消息数组末尾。
|
||||
|
||||
@@ -380,7 +372,7 @@ class Message(list[TMS], abc.ABC):
|
||||
return self
|
||||
|
||||
def extend( # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
self, obj: Union[Self, Iterable[TMS]]
|
||||
self, obj: Self | Iterable[TMS]
|
||||
) -> Self:
|
||||
"""拼接一个消息数组或多个消息段到消息数组末尾。
|
||||
|
||||
@@ -391,7 +383,7 @@ class Message(list[TMS], abc.ABC):
|
||||
self.append(segment)
|
||||
return self
|
||||
|
||||
def join(self, iterable: Iterable[Union[TMS, Self]]) -> Self:
|
||||
def join(self, iterable: Iterable[TMS | Self]) -> Self:
|
||||
"""将多个消息连接并将自身作为分割
|
||||
|
||||
参数:
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
from _string import formatter_field_name_split # type: ignore
|
||||
from collections.abc import Mapping, Sequence
|
||||
from collections.abc import Callable, Mapping, Sequence
|
||||
import functools
|
||||
from string import Formatter
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Callable,
|
||||
Generic,
|
||||
Optional,
|
||||
TypeAlias,
|
||||
TypeVar,
|
||||
Union,
|
||||
cast,
|
||||
overload,
|
||||
)
|
||||
from typing_extensions import TypeAlias
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .message import Message, MessageSegment
|
||||
@@ -50,15 +47,15 @@ class MessageTemplate(Formatter, Generic[TF]):
|
||||
@overload
|
||||
def __init__(
|
||||
self: "MessageTemplate[TM]",
|
||||
template: Union[str, TM],
|
||||
template: str | TM,
|
||||
factory: type[TM],
|
||||
private_getattr: bool = False,
|
||||
) -> None: ...
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
template: Union[str, TM],
|
||||
factory: Union[type[str], type[TM]] = str,
|
||||
template: str | TM,
|
||||
factory: type[str] | type[TM] = str,
|
||||
private_getattr: bool = False,
|
||||
) -> None:
|
||||
self.template: TF = template # type: ignore
|
||||
@@ -70,7 +67,7 @@ class MessageTemplate(Formatter, Generic[TF]):
|
||||
return f"MessageTemplate({self.template!r}, factory={self.factory!r})"
|
||||
|
||||
def add_format_spec(
|
||||
self, spec: FormatSpecFunc_T, name: Optional[str] = None
|
||||
self, spec: FormatSpecFunc_T, name: str | None = None
|
||||
) -> FormatSpecFunc_T:
|
||||
name = name or spec.__name__
|
||||
if name in self.format_specs:
|
||||
@@ -126,7 +123,7 @@ class MessageTemplate(Formatter, Generic[TF]):
|
||||
format_string: str,
|
||||
args: Sequence[Any],
|
||||
kwargs: Mapping[str, Any],
|
||||
used_args: set[Union[int, str]],
|
||||
used_args: set[int | str],
|
||||
auto_arg_index: int = 0,
|
||||
) -> tuple[TF, int]:
|
||||
results: list[Any] = [self.factory()]
|
||||
@@ -180,7 +177,7 @@ class MessageTemplate(Formatter, Generic[TF]):
|
||||
|
||||
def get_field(
|
||||
self, field_name: str, args: Sequence[Any], kwargs: Mapping[str, Any]
|
||||
) -> tuple[Any, Union[int, str]]:
|
||||
) -> tuple[Any, int | str]:
|
||||
first, rest = formatter_field_name_split(field_name)
|
||||
obj = self.get_value(first, args, kwargs)
|
||||
|
||||
@@ -192,7 +189,7 @@ class MessageTemplate(Formatter, Generic[TF]):
|
||||
return obj, first
|
||||
|
||||
def format_field(self, value: Any, format_spec: str) -> Any:
|
||||
formatter: Optional[FormatSpecFunc] = self.format_specs.get(format_spec)
|
||||
formatter: FormatSpecFunc | None = self.format_specs.get(format_spec)
|
||||
if formatter is None and not issubclass(self.factory, str):
|
||||
segment_class: type["MessageSegment"] = self.factory.get_segment_class()
|
||||
method = getattr(segment_class, format_spec, None)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from collections.abc import Awaitable, Iterable
|
||||
from collections.abc import Awaitable, Callable, Iterable
|
||||
from types import TracebackType
|
||||
from typing import Any, Callable, Optional, Union, cast
|
||||
from typing_extensions import TypeAlias
|
||||
from typing import Any, TypeAlias, cast
|
||||
|
||||
import anyio
|
||||
from anyio.abc import TaskGroup
|
||||
@@ -11,12 +10,12 @@ from nonebot.utils import is_coroutine_callable, run_sync
|
||||
|
||||
SYNC_LIFESPAN_FUNC: TypeAlias = Callable[[], Any]
|
||||
ASYNC_LIFESPAN_FUNC: TypeAlias = Callable[[], Awaitable[Any]]
|
||||
LIFESPAN_FUNC: TypeAlias = Union[SYNC_LIFESPAN_FUNC, ASYNC_LIFESPAN_FUNC]
|
||||
LIFESPAN_FUNC: TypeAlias = SYNC_LIFESPAN_FUNC | ASYNC_LIFESPAN_FUNC
|
||||
|
||||
|
||||
class Lifespan:
|
||||
def __init__(self) -> None:
|
||||
self._task_group: Optional[TaskGroup] = None
|
||||
self._task_group: TaskGroup | None = None
|
||||
|
||||
self._startup_funcs: list[LIFESPAN_FUNC] = []
|
||||
self._ready_funcs: list[LIFESPAN_FUNC] = []
|
||||
@@ -72,9 +71,9 @@ class Lifespan:
|
||||
async def shutdown(
|
||||
self,
|
||||
*,
|
||||
exc_type: Optional[type[BaseException]] = None,
|
||||
exc_val: Optional[BaseException] = None,
|
||||
exc_tb: Optional[TracebackType] = None,
|
||||
exc_type: type[BaseException] | None = None,
|
||||
exc_val: BaseException | None = None,
|
||||
exc_tb: TracebackType | None = None,
|
||||
) -> None:
|
||||
if self._shutdown_funcs:
|
||||
# reverse shutdown funcs to ensure stack order
|
||||
@@ -93,8 +92,8 @@ class Lifespan:
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[type[BaseException]],
|
||||
exc_val: Optional[BaseException],
|
||||
exc_tb: Optional[TracebackType],
|
||||
exc_type: type[BaseException] | None,
|
||||
exc_val: BaseException | None,
|
||||
exc_tb: TracebackType | None,
|
||||
) -> None:
|
||||
await self.shutdown(exc_type=exc_type, exc_val=exc_val, exc_tb=exc_tb)
|
||||
|
||||
@@ -2,8 +2,8 @@ import abc
|
||||
from collections.abc import AsyncGenerator
|
||||
from contextlib import AsyncExitStack, asynccontextmanager
|
||||
from types import TracebackType
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, Optional, Union
|
||||
from typing_extensions import Self, TypeAlias
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, TypeAlias
|
||||
from typing_extensions import Self
|
||||
|
||||
from anyio import CancelScope, create_task_group
|
||||
from anyio.abc import TaskGroup
|
||||
@@ -245,9 +245,9 @@ class HTTPClientSession(abc.ABC):
|
||||
params: QueryTypes = None,
|
||||
headers: HeaderTypes = None,
|
||||
cookies: CookieTypes = None,
|
||||
version: Union[str, HTTPVersion] = HTTPVersion.H11,
|
||||
version: str | HTTPVersion = HTTPVersion.H11,
|
||||
timeout: TimeoutTypes = None,
|
||||
proxy: Optional[str] = None,
|
||||
proxy: str | None = None,
|
||||
):
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -283,9 +283,9 @@ class HTTPClientSession(abc.ABC):
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[type[BaseException]],
|
||||
exc: Optional[BaseException],
|
||||
tb: Optional[TracebackType],
|
||||
exc_type: type[BaseException] | None,
|
||||
exc: BaseException | None,
|
||||
tb: TracebackType | None,
|
||||
) -> None:
|
||||
await self.close()
|
||||
|
||||
@@ -315,9 +315,9 @@ class HTTPClientMixin(ForwardMixin):
|
||||
params: QueryTypes = None,
|
||||
headers: HeaderTypes = None,
|
||||
cookies: CookieTypes = None,
|
||||
version: Union[str, HTTPVersion] = HTTPVersion.H11,
|
||||
version: str | HTTPVersion = HTTPVersion.H11,
|
||||
timeout: TimeoutTypes = None,
|
||||
proxy: Optional[str] = None,
|
||||
proxy: str | None = None,
|
||||
) -> HTTPClientSession:
|
||||
"""获取一个 HTTP 会话"""
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import TYPE_CHECKING, TypeVar, Union, overload
|
||||
from typing import TYPE_CHECKING, TypeVar, overload
|
||||
|
||||
from .abstract import Driver, Mixin
|
||||
|
||||
@@ -21,7 +21,7 @@ def combine_driver(
|
||||
|
||||
def combine_driver(
|
||||
driver: type[D], *mixins: type[Mixin]
|
||||
) -> Union[type[D], type["CombinedDriver"]]:
|
||||
) -> type[D] | type["CombinedDriver"]:
|
||||
"""将一个驱动器和多个混入类合并。"""
|
||||
# check first
|
||||
if not issubclass(driver, Driver):
|
||||
|
||||
@@ -1,48 +1,51 @@
|
||||
import abc
|
||||
from collections.abc import Awaitable, Iterator, Mapping, MutableMapping
|
||||
from collections.abc import Awaitable, Callable, Iterator, Mapping, MutableMapping
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from http.cookiejar import Cookie, CookieJar
|
||||
from typing import IO, Any, Callable, Optional, Union
|
||||
from typing_extensions import TypeAlias
|
||||
from typing import IO, Any, TypeAlias
|
||||
import urllib.request
|
||||
|
||||
from multidict import CIMultiDict
|
||||
from yarl import URL as URL
|
||||
|
||||
RawURL: TypeAlias = tuple[bytes, bytes, Optional[int], bytes]
|
||||
|
||||
SimpleQuery: TypeAlias = Union[str, int, float]
|
||||
QueryVariable: TypeAlias = Union[SimpleQuery, list[SimpleQuery]]
|
||||
QueryTypes: TypeAlias = Union[
|
||||
None, str, Mapping[str, QueryVariable], list[tuple[str, SimpleQuery]]
|
||||
]
|
||||
@dataclass
|
||||
class Timeout:
|
||||
"""Request 超时配置。"""
|
||||
|
||||
HeaderTypes: TypeAlias = Union[
|
||||
None,
|
||||
CIMultiDict[str],
|
||||
dict[str, str],
|
||||
list[tuple[str, str]],
|
||||
]
|
||||
total: float | None = None
|
||||
connect: float | None = None
|
||||
read: float | None = None
|
||||
|
||||
CookieTypes: TypeAlias = Union[
|
||||
None, "Cookies", CookieJar, dict[str, str], list[tuple[str, str]]
|
||||
]
|
||||
|
||||
ContentTypes: TypeAlias = Union[str, bytes, None]
|
||||
DataTypes: TypeAlias = Union[dict, None]
|
||||
FileContent: TypeAlias = Union[IO[bytes], bytes]
|
||||
FileType: TypeAlias = tuple[Optional[str], FileContent, Optional[str]]
|
||||
FileTypes: TypeAlias = Union[
|
||||
# file (or bytes)
|
||||
FileContent,
|
||||
# (filename, file (or bytes))
|
||||
tuple[Optional[str], FileContent],
|
||||
# (filename, file (or bytes), content_type)
|
||||
FileType,
|
||||
]
|
||||
FilesTypes: TypeAlias = Union[dict[str, FileTypes], list[tuple[str, FileTypes]], None]
|
||||
TimeoutTypes: TypeAlias = Union[float, "Timeout", None]
|
||||
RawURL: TypeAlias = tuple[bytes, bytes, int | None, bytes]
|
||||
|
||||
SimpleQuery: TypeAlias = str | int | float
|
||||
QueryVariable: TypeAlias = SimpleQuery | list[SimpleQuery]
|
||||
QueryTypes: TypeAlias = (
|
||||
None | str | Mapping[str, QueryVariable] | list[tuple[str, SimpleQuery]]
|
||||
)
|
||||
|
||||
HeaderTypes: TypeAlias = (
|
||||
None | CIMultiDict[str] | dict[str, str] | list[tuple[str, str]]
|
||||
)
|
||||
|
||||
CookieTypes: TypeAlias = (
|
||||
"None | Cookies | CookieJar | dict[str, str] | list[tuple[str, str]]"
|
||||
)
|
||||
|
||||
ContentTypes: TypeAlias = str | bytes | None
|
||||
DataTypes: TypeAlias = dict | None
|
||||
FileContent: TypeAlias = IO[bytes] | bytes
|
||||
FileType: TypeAlias = tuple[str | None, FileContent, str | None]
|
||||
FileTypes: TypeAlias = (
|
||||
FileContent # file (or bytes)
|
||||
| tuple[str | None, FileContent] # (filename, file (or bytes))
|
||||
| FileType # (filename, file (or bytes), content_type)
|
||||
)
|
||||
FilesTypes: TypeAlias = dict[str, FileTypes] | list[tuple[str, FileTypes]] | None
|
||||
TimeoutTypes: TypeAlias = float | Timeout | None
|
||||
|
||||
|
||||
class HTTPVersion(Enum):
|
||||
@@ -51,20 +54,11 @@ class HTTPVersion(Enum):
|
||||
H2 = "2"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Timeout:
|
||||
"""Request 超时配置。"""
|
||||
|
||||
total: Optional[float] = None
|
||||
connect: Optional[float] = None
|
||||
read: Optional[float] = None
|
||||
|
||||
|
||||
class Request:
|
||||
def __init__(
|
||||
self,
|
||||
method: Union[str, bytes],
|
||||
url: Union["URL", str, RawURL],
|
||||
method: str | bytes,
|
||||
url: "URL | str | RawURL",
|
||||
*,
|
||||
params: QueryTypes = None,
|
||||
headers: HeaderTypes = None,
|
||||
@@ -73,9 +67,9 @@ class Request:
|
||||
data: DataTypes = None,
|
||||
json: Any = None,
|
||||
files: FilesTypes = None,
|
||||
version: Union[str, HTTPVersion] = HTTPVersion.H11,
|
||||
version: str | HTTPVersion = HTTPVersion.H11,
|
||||
timeout: TimeoutTypes = None,
|
||||
proxy: Optional[str] = None,
|
||||
proxy: str | None = None,
|
||||
):
|
||||
# method
|
||||
self.method: str = (
|
||||
@@ -88,7 +82,7 @@ class Request:
|
||||
# timeout
|
||||
self.timeout: TimeoutTypes = timeout
|
||||
# proxy
|
||||
self.proxy: Optional[str] = proxy
|
||||
self.proxy: str | None = proxy
|
||||
|
||||
# url
|
||||
if isinstance(url, tuple):
|
||||
@@ -117,7 +111,7 @@ class Request:
|
||||
self.content: ContentTypes = content
|
||||
self.data: DataTypes = data
|
||||
self.json: Any = json
|
||||
self.files: Optional[list[tuple[str, FileType]]] = None
|
||||
self.files: list[tuple[str, FileType]] | None = None
|
||||
if files:
|
||||
self.files = []
|
||||
files_ = files.items() if isinstance(files, dict) else files
|
||||
@@ -140,7 +134,7 @@ class Response:
|
||||
*,
|
||||
headers: HeaderTypes = None,
|
||||
content: ContentTypes = None,
|
||||
request: Optional[Request] = None,
|
||||
request: Request | None = None,
|
||||
):
|
||||
# status code
|
||||
self.status_code: int = status_code
|
||||
@@ -153,7 +147,7 @@ class Response:
|
||||
self.content: ContentTypes = content
|
||||
|
||||
# request
|
||||
self.request: Optional[Request] = request
|
||||
self.request: Request | None = request
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.__class__.__name__}(status_code={self.status_code!r})"
|
||||
@@ -183,7 +177,7 @@ class WebSocket(abc.ABC):
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
async def receive(self) -> Union[str, bytes]:
|
||||
async def receive(self) -> str | bytes:
|
||||
"""接收一条 WebSocket text/bytes 信息"""
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -197,7 +191,7 @@ class WebSocket(abc.ABC):
|
||||
"""接收一条 WebSocket binary 信息"""
|
||||
raise NotImplementedError
|
||||
|
||||
async def send(self, data: Union[str, bytes]) -> None:
|
||||
async def send(self, data: str | bytes) -> None:
|
||||
"""发送一条 WebSocket text/bytes 信息"""
|
||||
if isinstance(data, str):
|
||||
await self.send_text(data)
|
||||
@@ -258,11 +252,11 @@ class Cookies(MutableMapping):
|
||||
def get( # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
self,
|
||||
name: str,
|
||||
default: Optional[str] = None,
|
||||
domain: Optional[str] = None,
|
||||
path: Optional[str] = None,
|
||||
) -> Optional[str]:
|
||||
value: Optional[str] = None
|
||||
default: str | None = None,
|
||||
domain: str | None = None,
|
||||
path: str | None = None,
|
||||
) -> str | None:
|
||||
value: str | None = None
|
||||
for cookie in self.jar:
|
||||
if (
|
||||
cookie.name == name
|
||||
@@ -277,7 +271,7 @@ class Cookies(MutableMapping):
|
||||
return default if value is None else value
|
||||
|
||||
def delete(
|
||||
self, name: str, domain: Optional[str] = None, path: Optional[str] = None
|
||||
self, name: str, domain: str | None = None, path: str | None = None
|
||||
) -> None:
|
||||
if domain is not None and path is not None:
|
||||
return self.jar.clear(domain, path, name)
|
||||
@@ -293,7 +287,7 @@ class Cookies(MutableMapping):
|
||||
for cookie in remove:
|
||||
self.jar.clear(cookie.domain, cookie.path, cookie.name)
|
||||
|
||||
def clear(self, domain: Optional[str] = None, path: Optional[str] = None) -> None:
|
||||
def clear(self, domain: str | None = None, path: str | None = None) -> None:
|
||||
self.jar.clear(domain, path)
|
||||
|
||||
def update( # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from collections.abc import ItemsView, Iterator, KeysView, MutableMapping, ValuesView
|
||||
from typing import TYPE_CHECKING, Optional, TypeVar, Union, overload
|
||||
from typing import TYPE_CHECKING, TypeVar, overload
|
||||
|
||||
from .provider import DEFAULT_PROVIDER_CLASS, MatcherProvider
|
||||
|
||||
@@ -52,7 +52,7 @@ class MatcherManager(MutableMapping[int, list[type["Matcher"]]]):
|
||||
return self.provider.items()
|
||||
|
||||
@overload
|
||||
def get(self, key: int) -> Optional[list[type["Matcher"]]]: ...
|
||||
def get(self, key: int) -> list[type["Matcher"]] | None: ...
|
||||
|
||||
@overload
|
||||
def get(
|
||||
@@ -60,11 +60,11 @@ class MatcherManager(MutableMapping[int, list[type["Matcher"]]]):
|
||||
) -> list[type["Matcher"]]: ...
|
||||
|
||||
@overload
|
||||
def get(self, key: int, default: T) -> Union[list[type["Matcher"]], T]: ...
|
||||
def get(self, key: int, default: T) -> list[type["Matcher"]] | T: ...
|
||||
|
||||
def get(
|
||||
self, key: int, default: Optional[T] = None
|
||||
) -> Optional[Union[list[type["Matcher"]], T]]:
|
||||
self, key: int, default: T | None = None
|
||||
) -> list[type["Matcher"]] | T | None:
|
||||
return self.provider.get(key, default)
|
||||
|
||||
def pop( # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
|
||||
@@ -13,10 +13,8 @@ from typing import ( # noqa: UP035
|
||||
Callable,
|
||||
ClassVar,
|
||||
NoReturn,
|
||||
Optional,
|
||||
Type,
|
||||
TypeVar,
|
||||
Union,
|
||||
overload,
|
||||
)
|
||||
from typing_extensions import Self
|
||||
@@ -87,15 +85,15 @@ current_handler: ContextVar[Dependent[Any]] = ContextVar("current_handler")
|
||||
class MatcherSource:
|
||||
"""Matcher 源代码上下文信息"""
|
||||
|
||||
plugin_id: Optional[str] = None
|
||||
plugin_id: str | None = None
|
||||
"""事件响应器所在插件标识符"""
|
||||
module_name: Optional[str] = None
|
||||
module_name: str | None = None
|
||||
"""事件响应器所在插件模块的路径名"""
|
||||
lineno: Optional[int] = None
|
||||
lineno: int | None = None
|
||||
"""事件响应器所在行号"""
|
||||
|
||||
@property
|
||||
def plugin(self) -> Optional["Plugin"]:
|
||||
def plugin(self) -> "Plugin | None":
|
||||
"""事件响应器所在插件"""
|
||||
from nonebot.plugin import get_plugin
|
||||
|
||||
@@ -103,17 +101,17 @@ class MatcherSource:
|
||||
return get_plugin(self.plugin_id)
|
||||
|
||||
@property
|
||||
def plugin_name(self) -> Optional[str]:
|
||||
def plugin_name(self) -> str | None:
|
||||
"""事件响应器所在插件名"""
|
||||
return self.plugin and self.plugin.name
|
||||
|
||||
@property
|
||||
def module(self) -> Optional[ModuleType]:
|
||||
def module(self) -> ModuleType | None:
|
||||
if self.module_name is not None:
|
||||
return sys.modules.get(self.module_name)
|
||||
|
||||
@property
|
||||
def file(self) -> Optional[Path]:
|
||||
def file(self) -> Path | None:
|
||||
if self.module is not None and (file := inspect.getsourcefile(self.module)):
|
||||
return Path(file).absolute()
|
||||
|
||||
@@ -121,8 +119,8 @@ class MatcherSource:
|
||||
class MatcherMeta(type):
|
||||
if TYPE_CHECKING:
|
||||
type: str
|
||||
_source: Optional[MatcherSource]
|
||||
module_name: Optional[str]
|
||||
_source: MatcherSource | None
|
||||
module_name: str | None
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
@@ -140,7 +138,7 @@ class MatcherMeta(type):
|
||||
class Matcher(metaclass=MatcherMeta):
|
||||
"""事件响应器类"""
|
||||
|
||||
_source: ClassVar[Optional[MatcherSource]] = None
|
||||
_source: ClassVar[MatcherSource | None] = None
|
||||
|
||||
type: ClassVar[str] = ""
|
||||
"""事件响应器类型"""
|
||||
@@ -156,15 +154,15 @@ class Matcher(metaclass=MatcherMeta):
|
||||
"""事件响应器是否阻止事件传播"""
|
||||
temp: ClassVar[bool] = False
|
||||
"""事件响应器是否为临时"""
|
||||
expire_time: ClassVar[Optional[datetime]] = None
|
||||
expire_time: ClassVar[datetime | None] = None
|
||||
"""事件响应器过期时间点"""
|
||||
|
||||
_default_state: ClassVar[T_State] = {}
|
||||
"""事件响应器默认状态"""
|
||||
|
||||
_default_type_updater: ClassVar[Optional[Dependent[str]]] = None
|
||||
_default_type_updater: ClassVar[Dependent[str] | None] = None
|
||||
"""事件响应器类型更新函数"""
|
||||
_default_permission_updater: ClassVar[Optional[Dependent[Permission]]] = None
|
||||
_default_permission_updater: ClassVar[Dependent[Permission] | None] = None
|
||||
"""事件响应器权限更新函数"""
|
||||
|
||||
HANDLER_PARAM_TYPES: ClassVar[tuple[Type[Param], ...]] = ( # noqa: UP006
|
||||
@@ -197,22 +195,22 @@ class Matcher(metaclass=MatcherMeta):
|
||||
def new(
|
||||
cls,
|
||||
type_: str = "",
|
||||
rule: Optional[Rule] = None,
|
||||
permission: Optional[Permission] = None,
|
||||
handlers: Optional[list[Union[T_Handler, Dependent[Any]]]] = None,
|
||||
rule: Rule | None = None,
|
||||
permission: Permission | None = None,
|
||||
handlers: list[T_Handler | Dependent[Any]] | None = None,
|
||||
temp: bool = False,
|
||||
priority: int = 1,
|
||||
block: bool = False,
|
||||
*,
|
||||
plugin: Optional["Plugin"] = None,
|
||||
module: Optional[ModuleType] = None,
|
||||
source: Optional[MatcherSource] = None,
|
||||
expire_time: Optional[Union[datetime, timedelta]] = None,
|
||||
default_state: Optional[T_State] = None,
|
||||
default_type_updater: Optional[Union[T_TypeUpdater, Dependent[str]]] = None,
|
||||
default_permission_updater: Optional[
|
||||
Union[T_PermissionUpdater, Dependent[Permission]]
|
||||
] = None,
|
||||
plugin: "Plugin | None" = None,
|
||||
module: ModuleType | None = None,
|
||||
source: MatcherSource | None = None,
|
||||
expire_time: datetime | timedelta | None = None,
|
||||
default_state: T_State | None = None,
|
||||
default_type_updater: T_TypeUpdater | Dependent[str] | None = None,
|
||||
default_permission_updater: T_PermissionUpdater
|
||||
| Dependent[Permission]
|
||||
| None = None,
|
||||
) -> Type[Self]: # noqa: UP006
|
||||
"""
|
||||
创建一个新的事件响应器,并存储至 `matchers <#matchers>`_
|
||||
@@ -332,27 +330,27 @@ class Matcher(metaclass=MatcherMeta):
|
||||
matchers[cls.priority].remove(cls)
|
||||
|
||||
@classproperty
|
||||
def plugin(cls) -> Optional["Plugin"]:
|
||||
def plugin(cls) -> "Plugin | None":
|
||||
"""事件响应器所在插件"""
|
||||
return cls._source and cls._source.plugin
|
||||
|
||||
@classproperty
|
||||
def plugin_id(cls) -> Optional[str]:
|
||||
def plugin_id(cls) -> str | None:
|
||||
"""事件响应器所在插件标识符"""
|
||||
return cls._source and cls._source.plugin_id
|
||||
|
||||
@classproperty
|
||||
def plugin_name(cls) -> Optional[str]:
|
||||
def plugin_name(cls) -> str | None:
|
||||
"""事件响应器所在插件名"""
|
||||
return cls._source and cls._source.plugin_name
|
||||
|
||||
@classproperty
|
||||
def module(cls) -> Optional[ModuleType]:
|
||||
def module(cls) -> ModuleType | None:
|
||||
"""事件响应器所在插件模块"""
|
||||
return cls._source and cls._source.module
|
||||
|
||||
@classproperty
|
||||
def module_name(cls) -> Optional[str]:
|
||||
def module_name(cls) -> str | None:
|
||||
"""事件响应器所在插件模块路径"""
|
||||
return cls._source and cls._source.module_name
|
||||
|
||||
@@ -361,8 +359,8 @@ class Matcher(metaclass=MatcherMeta):
|
||||
cls,
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
) -> bool:
|
||||
"""检查是否满足触发权限
|
||||
|
||||
@@ -386,8 +384,8 @@ class Matcher(metaclass=MatcherMeta):
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
) -> bool:
|
||||
"""检查是否满足匹配规则
|
||||
|
||||
@@ -432,7 +430,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
|
||||
@classmethod
|
||||
def append_handler(
|
||||
cls, handler: T_Handler, parameterless: Optional[Iterable[Any]] = None
|
||||
cls, handler: T_Handler, parameterless: Iterable[Any] | None = None
|
||||
) -> Dependent[Any]:
|
||||
handler_ = Dependent[Any].parse(
|
||||
call=handler,
|
||||
@@ -444,7 +442,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
|
||||
@classmethod
|
||||
def handle(
|
||||
cls, parameterless: Optional[Iterable[Any]] = None
|
||||
cls, parameterless: Iterable[Any] | None = None
|
||||
) -> Callable[[T_Handler], T_Handler]:
|
||||
"""装饰一个函数来向事件响应器直接添加一个处理函数
|
||||
|
||||
@@ -460,7 +458,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
|
||||
@classmethod
|
||||
def receive(
|
||||
cls, id: str = "", parameterless: Optional[Iterable[Any]] = None
|
||||
cls, id: str = "", parameterless: Iterable[Any] | None = None
|
||||
) -> Callable[[T_Handler], T_Handler]:
|
||||
"""装饰一个函数来指示 NoneBot 在接收用户新的一条消息后继续运行该函数
|
||||
|
||||
@@ -503,8 +501,8 @@ class Matcher(metaclass=MatcherMeta):
|
||||
def got(
|
||||
cls,
|
||||
key: str,
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
parameterless: Optional[Iterable[Any]] = None,
|
||||
prompt: str | Message | MessageSegment | MessageTemplate | None = None,
|
||||
parameterless: Iterable[Any] | None = None,
|
||||
) -> Callable[[T_Handler], T_Handler]:
|
||||
"""装饰一个函数来指示 NoneBot 获取一个参数 `key`
|
||||
|
||||
@@ -550,7 +548,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
@classmethod
|
||||
async def send(
|
||||
cls,
|
||||
message: Union[str, Message, MessageSegment, MessageTemplate],
|
||||
message: str | Message | MessageSegment | MessageTemplate,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""发送一条消息给当前交互用户
|
||||
@@ -572,7 +570,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
@classmethod
|
||||
async def finish(
|
||||
cls,
|
||||
message: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
message: str | Message | MessageSegment | MessageTemplate | None = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""发送一条消息给当前交互用户并结束当前事件响应器
|
||||
@@ -589,7 +587,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
@classmethod
|
||||
async def pause(
|
||||
cls,
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
prompt: str | Message | MessageSegment | MessageTemplate | None = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续下一个处理函数
|
||||
@@ -613,7 +611,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
@classmethod
|
||||
async def reject(
|
||||
cls,
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
prompt: str | Message | MessageSegment | MessageTemplate | None = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""最近使用 `got` / `receive` 接收的消息不符合预期,
|
||||
@@ -643,7 +641,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
async def reject_arg(
|
||||
cls,
|
||||
key: str,
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
prompt: str | Message | MessageSegment | MessageTemplate | None = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""最近使用 `got` 接收的消息不符合预期,
|
||||
@@ -668,7 +666,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
async def reject_receive(
|
||||
cls,
|
||||
id: str = "",
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
prompt: str | Message | MessageSegment | MessageTemplate | None = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""最近使用 `receive` 接收的消息不符合预期,
|
||||
@@ -698,14 +696,12 @@ class Matcher(metaclass=MatcherMeta):
|
||||
raise SkippedException
|
||||
|
||||
@overload
|
||||
def get_receive(self, id: str) -> Union[Event, None]: ...
|
||||
def get_receive(self, id: str) -> Event | None: ...
|
||||
|
||||
@overload
|
||||
def get_receive(self, id: str, default: T) -> Union[Event, T]: ...
|
||||
def get_receive(self, id: str, default: T) -> Event | T: ...
|
||||
|
||||
def get_receive(
|
||||
self, id: str, default: Optional[T] = None
|
||||
) -> Optional[Union[Event, T]]:
|
||||
def get_receive(self, id: str, default: T | None = None) -> Event | T | None:
|
||||
"""获取一个 `receive` 事件
|
||||
|
||||
如果没有找到对应的事件,返回 `default` 值
|
||||
@@ -718,14 +714,12 @@ class Matcher(metaclass=MatcherMeta):
|
||||
self.state[LAST_RECEIVE_KEY] = event
|
||||
|
||||
@overload
|
||||
def get_last_receive(self) -> Union[Event, None]: ...
|
||||
def get_last_receive(self) -> Event | None: ...
|
||||
|
||||
@overload
|
||||
def get_last_receive(self, default: T) -> Union[Event, T]: ...
|
||||
def get_last_receive(self, default: T) -> Event | T: ...
|
||||
|
||||
def get_last_receive(
|
||||
self, default: Optional[T] = None
|
||||
) -> Optional[Union[Event, T]]:
|
||||
def get_last_receive(self, default: T | None = None) -> Event | T | None:
|
||||
"""获取最近一次 `receive` 事件
|
||||
|
||||
如果没有事件,返回 `default` 值
|
||||
@@ -733,14 +727,12 @@ class Matcher(metaclass=MatcherMeta):
|
||||
return self.state.get(LAST_RECEIVE_KEY, default)
|
||||
|
||||
@overload
|
||||
def get_arg(self, key: str) -> Union[Message, None]: ...
|
||||
def get_arg(self, key: str) -> Message | None: ...
|
||||
|
||||
@overload
|
||||
def get_arg(self, key: str, default: T) -> Union[Message, T]: ...
|
||||
def get_arg(self, key: str, default: T) -> Message | T: ...
|
||||
|
||||
def get_arg(
|
||||
self, key: str, default: Optional[T] = None
|
||||
) -> Optional[Union[Message, T]]:
|
||||
def get_arg(self, key: str, default: T | None = None) -> Message | T | None:
|
||||
"""获取一个 `got` 消息
|
||||
|
||||
如果没有找到对应的消息,返回 `default` 值
|
||||
@@ -758,12 +750,12 @@ class Matcher(metaclass=MatcherMeta):
|
||||
self.state[REJECT_TARGET] = target
|
||||
|
||||
@overload
|
||||
def get_target(self) -> Union[str, None]: ...
|
||||
def get_target(self) -> str | None: ...
|
||||
|
||||
@overload
|
||||
def get_target(self, default: T) -> Union[str, T]: ...
|
||||
def get_target(self, default: T) -> str | T: ...
|
||||
|
||||
def get_target(self, default: Optional[T] = None) -> Optional[Union[str, T]]:
|
||||
def get_target(self, default: T | None = None) -> str | T | None:
|
||||
return self.state.get(REJECT_TARGET, default)
|
||||
|
||||
def stop_propagation(self):
|
||||
@@ -774,8 +766,8 @@ class Matcher(metaclass=MatcherMeta):
|
||||
self,
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
) -> str:
|
||||
updater = self.__class__._default_type_updater
|
||||
return (
|
||||
@@ -795,8 +787,8 @@ class Matcher(metaclass=MatcherMeta):
|
||||
self,
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
) -> Permission:
|
||||
if updater := self.__class__._default_permission_updater:
|
||||
return await updater(
|
||||
@@ -832,8 +824,8 @@ class Matcher(metaclass=MatcherMeta):
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
):
|
||||
logger.trace(
|
||||
f"{self} run with incoming args: "
|
||||
@@ -877,16 +869,14 @@ class Matcher(metaclass=MatcherMeta):
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
):
|
||||
exc: Optional[Union[FinishedException, RejectedException, PausedException]] = (
|
||||
None
|
||||
)
|
||||
exc: FinishedException | RejectedException | PausedException | None = None
|
||||
|
||||
def _handle_special_exception(
|
||||
exc_group: BaseExceptionGroup[
|
||||
Union[FinishedException, RejectedException, PausedException]
|
||||
FinishedException | RejectedException | PausedException
|
||||
],
|
||||
):
|
||||
nonlocal exc
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from collections.abc import Callable
|
||||
from contextlib import AsyncExitStack, asynccontextmanager, contextmanager
|
||||
from enum import Enum
|
||||
import inspect
|
||||
@@ -5,13 +6,12 @@ from typing import (
|
||||
TYPE_CHECKING,
|
||||
Annotated,
|
||||
Any,
|
||||
Callable,
|
||||
Literal,
|
||||
Optional,
|
||||
Union,
|
||||
cast,
|
||||
get_args,
|
||||
get_origin,
|
||||
)
|
||||
from typing_extensions import Self, get_args, get_origin, override
|
||||
from typing_extensions import Self, override
|
||||
|
||||
import anyio
|
||||
from exceptiongroup import BaseExceptionGroup, catch
|
||||
@@ -47,10 +47,10 @@ if TYPE_CHECKING:
|
||||
class DependsInner:
|
||||
def __init__(
|
||||
self,
|
||||
dependency: Optional[T_Handler] = None,
|
||||
dependency: T_Handler | None = None,
|
||||
*,
|
||||
use_cache: bool = True,
|
||||
validate: Union[bool, PydanticFieldInfo] = False,
|
||||
validate: bool | PydanticFieldInfo = False,
|
||||
) -> None:
|
||||
self.dependency = dependency
|
||||
self.use_cache = use_cache
|
||||
@@ -64,10 +64,10 @@ class DependsInner:
|
||||
|
||||
|
||||
def Depends(
|
||||
dependency: Optional[T_Handler] = None,
|
||||
dependency: T_Handler | None = None,
|
||||
*,
|
||||
use_cache: bool = True,
|
||||
validate: Union[bool, PydanticFieldInfo] = False,
|
||||
validate: bool | PydanticFieldInfo = False,
|
||||
) -> Any:
|
||||
"""子依赖装饰器
|
||||
|
||||
@@ -113,7 +113,7 @@ class DependencyCache:
|
||||
def __init__(self):
|
||||
self._state = CacheState.PENDING
|
||||
self._result: Any = None
|
||||
self._exception: Optional[BaseException] = None
|
||||
self._exception: BaseException | None = None
|
||||
self._waiter = anyio.Event()
|
||||
|
||||
def done(self) -> bool:
|
||||
@@ -129,7 +129,7 @@ class DependencyCache:
|
||||
raise self._exception
|
||||
return self._result
|
||||
|
||||
def exception(self) -> Optional[BaseException]:
|
||||
def exception(self) -> BaseException | None:
|
||||
"""获取子依赖异常"""
|
||||
|
||||
if self._state != CacheState.FINISHED:
|
||||
@@ -192,7 +192,7 @@ class DependParam(Param):
|
||||
cls,
|
||||
sub_dependent: Dependent[Any],
|
||||
use_cache: bool,
|
||||
validate: Union[bool, PydanticFieldInfo],
|
||||
validate: bool | PydanticFieldInfo,
|
||||
) -> Self:
|
||||
return cls._inherit_construct(
|
||||
validate if isinstance(validate, PydanticFieldInfo) else None,
|
||||
@@ -205,7 +205,7 @@ class DependParam(Param):
|
||||
@override
|
||||
def _check_param(
|
||||
cls, param: inspect.Parameter, allow_types: tuple[type[Param], ...]
|
||||
) -> Optional[Self]:
|
||||
) -> Self | None:
|
||||
type_annotation, depends_inner = param.annotation, None
|
||||
# extract type annotation and dependency from Annotated
|
||||
if get_origin(param.annotation) is Annotated:
|
||||
@@ -245,7 +245,7 @@ class DependParam(Param):
|
||||
@override
|
||||
def _check_parameterless(
|
||||
cls, value: Any, allow_types: tuple[type[Param], ...]
|
||||
) -> Optional["Param"]:
|
||||
) -> "Param | None":
|
||||
if isinstance(value, DependsInner):
|
||||
assert value.dependency, "Dependency cannot be empty"
|
||||
dependent = Dependent[Any].parse(
|
||||
@@ -256,8 +256,8 @@ class DependParam(Param):
|
||||
@override
|
||||
async def _solve(
|
||||
self,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
use_cache: bool = self.use_cache
|
||||
@@ -267,7 +267,7 @@ class DependParam(Param):
|
||||
call = cast(Callable[..., Any], sub_dependent.call)
|
||||
|
||||
# solve sub dependency with current cache
|
||||
exc: Optional[BaseExceptionGroup[SkippedException]] = None
|
||||
exc: BaseExceptionGroup[SkippedException] | None = None
|
||||
|
||||
def _handle_skipped(exc_group: BaseExceptionGroup[SkippedException]):
|
||||
nonlocal exc
|
||||
@@ -332,9 +332,7 @@ class BotParam(Param):
|
||||
为保证兼容性,本注入还会解析名为 `bot` 且没有类型注解的参数。
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, *args, checker: Optional[ModelField] = None, **kwargs: Any
|
||||
) -> None:
|
||||
def __init__(self, *args, checker: ModelField | None = None, **kwargs: Any) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self.checker = checker
|
||||
|
||||
@@ -349,12 +347,12 @@ class BotParam(Param):
|
||||
@override
|
||||
def _check_param(
|
||||
cls, param: inspect.Parameter, allow_types: tuple[type[Param], ...]
|
||||
) -> Optional[Self]:
|
||||
) -> Self | None:
|
||||
from nonebot.adapters import Bot
|
||||
|
||||
# param type is Bot(s) or subclass(es) of Bot or None
|
||||
if generic_check_issubclass(param.annotation, Bot):
|
||||
checker: Optional[ModelField] = None
|
||||
checker: ModelField | None = None
|
||||
if param.annotation is not Bot:
|
||||
checker = ModelField.construct(
|
||||
name=param.name, annotation=param.annotation, field_info=FieldInfo()
|
||||
@@ -386,9 +384,7 @@ class EventParam(Param):
|
||||
为保证兼容性,本注入还会解析名为 `event` 且没有类型注解的参数。
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, *args, checker: Optional[ModelField] = None, **kwargs: Any
|
||||
) -> None:
|
||||
def __init__(self, *args, checker: ModelField | None = None, **kwargs: Any) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self.checker = checker
|
||||
|
||||
@@ -403,12 +399,12 @@ class EventParam(Param):
|
||||
@override
|
||||
def _check_param(
|
||||
cls, param: inspect.Parameter, allow_types: tuple[type[Param], ...]
|
||||
) -> Optional[Self]:
|
||||
) -> Self | None:
|
||||
from nonebot.adapters import Event
|
||||
|
||||
# param type is Event(s) or subclass(es) of Event or None
|
||||
if generic_check_issubclass(param.annotation, Event):
|
||||
checker: Optional[ModelField] = None
|
||||
checker: ModelField | None = None
|
||||
if param.annotation is not Event:
|
||||
checker = ModelField.construct(
|
||||
name=param.name, annotation=param.annotation, field_info=FieldInfo()
|
||||
@@ -447,7 +443,7 @@ class StateParam(Param):
|
||||
@override
|
||||
def _check_param(
|
||||
cls, param: inspect.Parameter, allow_types: tuple[type[Param], ...]
|
||||
) -> Optional[Self]:
|
||||
) -> Self | None:
|
||||
# param type is T_State
|
||||
if origin_is_annotated(
|
||||
get_origin(param.annotation)
|
||||
@@ -472,9 +468,7 @@ class MatcherParam(Param):
|
||||
为保证兼容性,本注入还会解析名为 `matcher` 且没有类型注解的参数。
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, *args, checker: Optional[ModelField] = None, **kwargs: Any
|
||||
) -> None:
|
||||
def __init__(self, *args, checker: ModelField | None = None, **kwargs: Any) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self.checker = checker
|
||||
|
||||
@@ -489,12 +483,12 @@ class MatcherParam(Param):
|
||||
@override
|
||||
def _check_param(
|
||||
cls, param: inspect.Parameter, allow_types: tuple[type[Param], ...]
|
||||
) -> Optional[Self]:
|
||||
) -> Self | None:
|
||||
from nonebot.matcher import Matcher
|
||||
|
||||
# param type is Matcher(s) or subclass(es) of Matcher or None
|
||||
if generic_check_issubclass(param.annotation, Matcher):
|
||||
checker: Optional[ModelField] = None
|
||||
checker: ModelField | None = None
|
||||
if param.annotation is not Matcher:
|
||||
checker = ModelField.construct(
|
||||
name=param.name, annotation=param.annotation, field_info=FieldInfo()
|
||||
@@ -520,31 +514,31 @@ class MatcherParam(Param):
|
||||
|
||||
class ArgInner:
|
||||
def __init__(
|
||||
self, key: Optional[str], type: Literal["message", "str", "plaintext", "prompt"]
|
||||
self, key: str | None, type: Literal["message", "str", "plaintext", "prompt"]
|
||||
) -> None:
|
||||
self.key: Optional[str] = key
|
||||
self.key: str | None = key
|
||||
self.type: Literal["message", "str", "plaintext", "prompt"] = type
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"ArgInner(key={self.key!r}, type={self.type!r})"
|
||||
|
||||
|
||||
def Arg(key: Optional[str] = None) -> Any:
|
||||
def Arg(key: str | None = None) -> Any:
|
||||
"""Arg 参数消息"""
|
||||
return ArgInner(key, "message")
|
||||
|
||||
|
||||
def ArgStr(key: Optional[str] = None) -> str:
|
||||
def ArgStr(key: str | None = None) -> str:
|
||||
"""Arg 参数消息文本"""
|
||||
return ArgInner(key, "str") # type: ignore
|
||||
|
||||
|
||||
def ArgPlainText(key: Optional[str] = None) -> str:
|
||||
def ArgPlainText(key: str | None = None) -> str:
|
||||
"""Arg 参数消息纯文本"""
|
||||
return ArgInner(key, "plaintext") # type: ignore
|
||||
|
||||
|
||||
def ArgPromptResult(key: Optional[str] = None) -> Any:
|
||||
def ArgPromptResult(key: str | None = None) -> Any:
|
||||
"""`arg` prompt 发送结果"""
|
||||
return ArgInner(key, "prompt")
|
||||
|
||||
@@ -576,7 +570,7 @@ class ArgParam(Param):
|
||||
@override
|
||||
def _check_param(
|
||||
cls, param: inspect.Parameter, allow_types: tuple[type[Param], ...]
|
||||
) -> Optional[Self]:
|
||||
) -> Self | None:
|
||||
if isinstance(param.default, ArgInner):
|
||||
return cls(key=param.default.key or param.name, type=param.default.type)
|
||||
elif get_origin(param.annotation) is Annotated:
|
||||
@@ -598,18 +592,18 @@ class ArgParam(Param):
|
||||
else:
|
||||
raise ValueError(f"Unknown Arg type: {self.type}")
|
||||
|
||||
def _solve_message(self, matcher: "Matcher") -> Optional["Message"]:
|
||||
def _solve_message(self, matcher: "Matcher") -> "Message | None":
|
||||
return matcher.get_arg(self.key)
|
||||
|
||||
def _solve_str(self, matcher: "Matcher") -> Optional[str]:
|
||||
def _solve_str(self, matcher: "Matcher") -> str | None:
|
||||
message = matcher.get_arg(self.key)
|
||||
return str(message) if message is not None else None
|
||||
|
||||
def _solve_plaintext(self, matcher: "Matcher") -> Optional[str]:
|
||||
def _solve_plaintext(self, matcher: "Matcher") -> str | None:
|
||||
message = matcher.get_arg(self.key)
|
||||
return message.extract_plain_text() if message is not None else None
|
||||
|
||||
def _solve_prompt(self, matcher: "Matcher") -> Optional[Any]:
|
||||
def _solve_prompt(self, matcher: "Matcher") -> Any | None:
|
||||
return matcher.state.get(
|
||||
REJECT_PROMPT_RESULT_KEY.format(key=ARG_KEY.format(key=self.key))
|
||||
)
|
||||
@@ -630,7 +624,7 @@ class ExceptionParam(Param):
|
||||
@override
|
||||
def _check_param(
|
||||
cls, param: inspect.Parameter, allow_types: tuple[type[Param], ...]
|
||||
) -> Optional[Self]:
|
||||
) -> Self | None:
|
||||
# param type is Exception(s) or subclass(es) of Exception or None
|
||||
if generic_check_issubclass(param.annotation, Exception):
|
||||
return cls()
|
||||
@@ -639,7 +633,7 @@ class ExceptionParam(Param):
|
||||
return cls()
|
||||
|
||||
@override
|
||||
async def _solve(self, exception: Optional[Exception] = None, **kwargs: Any) -> Any:
|
||||
async def _solve(self, exception: Exception | None = None, **kwargs: Any) -> Any:
|
||||
return exception
|
||||
|
||||
|
||||
@@ -658,7 +652,7 @@ class DefaultParam(Param):
|
||||
@override
|
||||
def _check_param(
|
||||
cls, param: inspect.Parameter, allow_types: tuple[type[Param], ...]
|
||||
) -> Optional[Self]:
|
||||
) -> Self | None:
|
||||
if param.default != param.empty:
|
||||
return cls(default=param.default)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from contextlib import AsyncExitStack
|
||||
from typing import ClassVar, NoReturn, Optional, Union
|
||||
from typing import ClassVar, NoReturn
|
||||
from typing_extensions import Self
|
||||
|
||||
import anyio
|
||||
@@ -38,7 +38,7 @@ class Permission:
|
||||
DefaultParam,
|
||||
]
|
||||
|
||||
def __init__(self, *checkers: Union[T_PermissionChecker, Dependent[bool]]) -> None:
|
||||
def __init__(self, *checkers: T_PermissionChecker | Dependent[bool]) -> None:
|
||||
self.checkers: set[Dependent[bool]] = {
|
||||
(
|
||||
checker
|
||||
@@ -58,8 +58,8 @@ class Permission:
|
||||
self,
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
) -> bool:
|
||||
"""检查是否满足某个权限。
|
||||
|
||||
@@ -95,9 +95,7 @@ class Permission:
|
||||
def __and__(self, other: object) -> NoReturn:
|
||||
raise RuntimeError("And operation between Permissions is not allowed.")
|
||||
|
||||
def __or__(
|
||||
self, other: Optional[Union["Permission", T_PermissionChecker]]
|
||||
) -> "Permission":
|
||||
def __or__(self, other: "Permission | T_PermissionChecker | None") -> "Permission":
|
||||
if other is None:
|
||||
return self
|
||||
elif isinstance(other, Permission):
|
||||
@@ -105,9 +103,7 @@ class Permission:
|
||||
else:
|
||||
return Permission(*self.checkers, other)
|
||||
|
||||
def __ror__(
|
||||
self, other: Optional[Union["Permission", T_PermissionChecker]]
|
||||
) -> "Permission":
|
||||
def __ror__(self, other: "Permission | T_PermissionChecker | None") -> "Permission":
|
||||
if other is None:
|
||||
return self
|
||||
elif isinstance(other, Permission):
|
||||
@@ -126,9 +122,7 @@ class User:
|
||||
|
||||
__slots__ = ("perm", "users")
|
||||
|
||||
def __init__(
|
||||
self, users: tuple[str, ...], perm: Optional[Permission] = None
|
||||
) -> None:
|
||||
def __init__(self, users: tuple[str, ...], perm: Permission | None = None) -> None:
|
||||
self.users = users
|
||||
self.perm = perm
|
||||
|
||||
@@ -149,7 +143,7 @@ class User:
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _clean_permission(cls, perm: Permission) -> Optional[Permission]:
|
||||
def _clean_permission(cls, perm: Permission) -> Permission | None:
|
||||
if len(perm.checkers) == 1 and isinstance(
|
||||
user_perm := next(iter(perm.checkers)).call, cls
|
||||
):
|
||||
@@ -157,7 +151,7 @@ class User:
|
||||
return perm
|
||||
|
||||
@classmethod
|
||||
def from_event(cls, event: Event, perm: Optional[Permission] = None) -> Self:
|
||||
def from_event(cls, event: Event, perm: Permission | None = None) -> Self:
|
||||
"""从事件中获取会话 ID。
|
||||
|
||||
如果 `perm` 中仅有 `User` 类型的权限检查函数,则会去除原有的会话 ID 限制。
|
||||
@@ -169,7 +163,7 @@ class User:
|
||||
return cls((event.get_session_id(),), perm=perm and cls._clean_permission(perm))
|
||||
|
||||
@classmethod
|
||||
def from_permission(cls, *users: str, perm: Optional[Permission] = None) -> Self:
|
||||
def from_permission(cls, *users: str, perm: Permission | None = None) -> Self:
|
||||
"""指定会话与权限。
|
||||
|
||||
如果 `perm` 中仅有 `User` 类型的权限检查函数,则会去除原有的会话 ID 限制。
|
||||
@@ -181,7 +175,7 @@ class User:
|
||||
return cls(users, perm=perm and cls._clean_permission(perm))
|
||||
|
||||
|
||||
def USER(*users: str, perm: Optional[Permission] = None):
|
||||
def USER(*users: str, perm: Permission | None = None):
|
||||
"""匹配当前事件属于指定会话。
|
||||
|
||||
如果 `perm` 中仅有 `User` 类型的权限检查函数,则会去除原有检查函数的会话 ID 限制。
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from contextlib import AsyncExitStack
|
||||
from typing import ClassVar, NoReturn, Optional, Union
|
||||
from typing import ClassVar, NoReturn
|
||||
|
||||
import anyio
|
||||
from exceptiongroup import BaseExceptionGroup, catch
|
||||
@@ -38,7 +38,7 @@ class Rule:
|
||||
DefaultParam,
|
||||
]
|
||||
|
||||
def __init__(self, *checkers: Union[T_RuleChecker, Dependent[bool]]) -> None:
|
||||
def __init__(self, *checkers: T_RuleChecker | Dependent[bool]) -> None:
|
||||
self.checkers: set[Dependent[bool]] = {
|
||||
(
|
||||
checker
|
||||
@@ -59,8 +59,8 @@ class Rule:
|
||||
bot: Bot,
|
||||
event: Event,
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
) -> bool:
|
||||
"""检查是否符合所有规则
|
||||
|
||||
@@ -101,7 +101,7 @@ class Rule:
|
||||
|
||||
return result
|
||||
|
||||
def __and__(self, other: Optional[Union["Rule", T_RuleChecker]]) -> "Rule":
|
||||
def __and__(self, other: "Rule | T_RuleChecker | None") -> "Rule":
|
||||
if other is None:
|
||||
return self
|
||||
elif isinstance(other, Rule):
|
||||
@@ -109,7 +109,7 @@ class Rule:
|
||||
else:
|
||||
return Rule(*self.checkers, other)
|
||||
|
||||
def __rand__(self, other: Optional[Union["Rule", T_RuleChecker]]) -> "Rule":
|
||||
def __rand__(self, other: "Rule | T_RuleChecker | None") -> "Rule":
|
||||
if other is None:
|
||||
return self
|
||||
elif isinstance(other, Rule):
|
||||
|
||||
@@ -9,10 +9,11 @@ FrontMatter:
|
||||
description: nonebot.message 模块
|
||||
"""
|
||||
|
||||
from collections.abc import Callable
|
||||
import contextlib
|
||||
from contextlib import AsyncExitStack
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Any, Callable, Optional
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
import anyio
|
||||
from exceptiongroup import BaseExceptionGroup, catch
|
||||
@@ -153,8 +154,8 @@ async def _apply_event_preprocessors(
|
||||
bot: "Bot",
|
||||
event: "Event",
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
show_log: bool = True,
|
||||
) -> bool:
|
||||
"""运行事件预处理。
|
||||
@@ -210,8 +211,8 @@ async def _apply_event_postprocessors(
|
||||
bot: "Bot",
|
||||
event: "Event",
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
show_log: bool = True,
|
||||
) -> None:
|
||||
"""运行事件后处理。
|
||||
@@ -257,8 +258,8 @@ async def _apply_run_preprocessors(
|
||||
event: "Event",
|
||||
state: T_State,
|
||||
matcher: Matcher,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
) -> bool:
|
||||
"""运行事件响应器运行前处理。
|
||||
|
||||
@@ -315,9 +316,9 @@ async def _apply_run_postprocessors(
|
||||
bot: "Bot",
|
||||
event: "Event",
|
||||
matcher: Matcher,
|
||||
exception: Optional[Exception] = None,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
exception: Exception | None = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
) -> None:
|
||||
"""运行事件响应器运行后处理。
|
||||
|
||||
@@ -365,8 +366,8 @@ async def _check_matcher(
|
||||
bot: "Bot",
|
||||
event: "Event",
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
) -> bool:
|
||||
"""检查事件响应器是否符合运行条件。
|
||||
|
||||
@@ -416,8 +417,8 @@ async def _run_matcher(
|
||||
bot: "Bot",
|
||||
event: "Event",
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
) -> None:
|
||||
"""运行事件响应器。
|
||||
|
||||
@@ -482,8 +483,8 @@ async def check_and_run_matcher(
|
||||
bot: "Bot",
|
||||
event: "Event",
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
stack: AsyncExitStack | None = None,
|
||||
dependency_cache: T_DependencyCache | None = None,
|
||||
) -> None:
|
||||
"""检查并运行事件响应器。
|
||||
|
||||
|
||||
@@ -7,8 +7,9 @@ FrontMatter:
|
||||
description: nonebot.params 模块
|
||||
"""
|
||||
|
||||
from collections.abc import Callable
|
||||
from re import Match
|
||||
from typing import Any, Callable, Literal, Optional, Union, overload
|
||||
from typing import Any, Literal, overload
|
||||
|
||||
from nonebot.adapters import Event, Message, MessageSegment
|
||||
from nonebot.consts import (
|
||||
@@ -136,7 +137,7 @@ def ShellCommandArgs() -> Any:
|
||||
return Depends(_shell_command_args, use_cache=False)
|
||||
|
||||
|
||||
def _shell_command_argv(state: T_State) -> list[Union[str, MessageSegment]]:
|
||||
def _shell_command_argv(state: T_State) -> list[str | MessageSegment]:
|
||||
return state[SHELL_ARGV]
|
||||
|
||||
|
||||
@@ -155,11 +156,11 @@ def RegexMatched() -> Match[str]:
|
||||
|
||||
|
||||
def _regex_str(
|
||||
groups: tuple[Union[str, int], ...],
|
||||
) -> Callable[[T_State], Union[str, tuple[Union[str, Any], ...], Any]]:
|
||||
groups: tuple[str | int, ...],
|
||||
) -> Callable[[T_State], str | tuple[str | Any, ...] | Any]:
|
||||
def _regex_str_dependency(
|
||||
state: T_State,
|
||||
) -> Union[str, tuple[Union[str, Any], ...], Any]:
|
||||
) -> str | tuple[str | Any, ...] | Any:
|
||||
return _regex_matched(state).group(*groups)
|
||||
|
||||
return _regex_str_dependency
|
||||
@@ -170,16 +171,16 @@ def RegexStr(group: Literal[0] = 0, /) -> str: ...
|
||||
|
||||
|
||||
@overload
|
||||
def RegexStr(group: Union[str, int], /) -> Union[str, Any]: ...
|
||||
def RegexStr(group: str | int, /) -> str | Any: ...
|
||||
|
||||
|
||||
@overload
|
||||
def RegexStr(
|
||||
group1: Union[str, int], group2: Union[str, int], /, *groups: Union[str, int]
|
||||
) -> tuple[Union[str, Any], ...]: ...
|
||||
group1: str | int, group2: str | int, /, *groups: str | int
|
||||
) -> tuple[str | Any, ...]: ...
|
||||
|
||||
|
||||
def RegexStr(*groups: Union[str, int]) -> Union[str, tuple[Union[str, Any], ...], Any]:
|
||||
def RegexStr(*groups: str | int) -> str | tuple[str | Any, ...] | Any:
|
||||
"""正则匹配结果文本"""
|
||||
return Depends(_regex_str(groups), use_cache=False)
|
||||
|
||||
@@ -238,7 +239,7 @@ def Keyword() -> str:
|
||||
return Depends(_keyword, use_cache=False)
|
||||
|
||||
|
||||
def Received(id: Optional[str] = None, default: Any = None) -> Any:
|
||||
def Received(id: str | None = None, default: Any = None) -> Any:
|
||||
"""`receive` 事件参数"""
|
||||
|
||||
def _received(matcher: "Matcher") -> Any:
|
||||
@@ -256,7 +257,7 @@ def LastReceived(default: Any = None) -> Any:
|
||||
return Depends(_last_received, use_cache=False)
|
||||
|
||||
|
||||
def ReceivePromptResult(id: Optional[str] = None) -> Any:
|
||||
def ReceivePromptResult(id: str | None = None) -> Any:
|
||||
"""`receive` prompt 发送结果"""
|
||||
|
||||
def _receive_prompt_result(matcher: "Matcher") -> Any:
|
||||
|
||||
@@ -41,7 +41,7 @@ FrontMatter:
|
||||
from contextvars import ContextVar
|
||||
from itertools import chain
|
||||
from types import ModuleType
|
||||
from typing import Optional, TypeVar
|
||||
from typing import TypeVar
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -53,7 +53,7 @@ C = TypeVar("C", bound=BaseModel)
|
||||
|
||||
_plugins: dict[str, "Plugin"] = {}
|
||||
_managers: list["PluginManager"] = []
|
||||
_current_plugin: ContextVar[Optional["Plugin"]] = ContextVar(
|
||||
_current_plugin: ContextVar["Plugin | None"] = ContextVar(
|
||||
"_current_plugin", default=None
|
||||
)
|
||||
|
||||
@@ -71,8 +71,8 @@ def _controlled_modules() -> dict[str, str]:
|
||||
|
||||
|
||||
def _find_parent_plugin_id(
|
||||
module_name: str, controlled_modules: Optional[dict[str, str]] = None
|
||||
) -> Optional[str]:
|
||||
module_name: str, controlled_modules: dict[str, str] | None = None
|
||||
) -> str | None:
|
||||
if controlled_modules is None:
|
||||
controlled_modules = _controlled_modules()
|
||||
available = {
|
||||
@@ -85,7 +85,7 @@ def _find_parent_plugin_id(
|
||||
|
||||
|
||||
def _module_name_to_plugin_id(
|
||||
module_name: str, controlled_modules: Optional[dict[str, str]] = None
|
||||
module_name: str, controlled_modules: dict[str, str] | None = None
|
||||
) -> str:
|
||||
plugin_name = _module_name_to_plugin_name(module_name)
|
||||
if parent_plugin_id := _find_parent_plugin_id(module_name, controlled_modules):
|
||||
@@ -132,7 +132,7 @@ def _revert_plugin(plugin: "Plugin") -> None:
|
||||
parent_plugin.sub_plugins.discard(plugin)
|
||||
|
||||
|
||||
def get_plugin(plugin_id: str) -> Optional["Plugin"]:
|
||||
def get_plugin(plugin_id: str) -> "Plugin | None":
|
||||
"""获取已经导入的某个插件。
|
||||
|
||||
如果为 `load_plugins` 文件夹导入的插件,则为文件(夹)名。
|
||||
@@ -145,7 +145,7 @@ def get_plugin(plugin_id: str) -> Optional["Plugin"]:
|
||||
return _plugins.get(plugin_id)
|
||||
|
||||
|
||||
def get_plugin_by_module_name(module_name: str) -> Optional["Plugin"]:
|
||||
def get_plugin_by_module_name(module_name: str) -> "Plugin | None":
|
||||
"""通过模块名获取已经导入的某个插件。
|
||||
|
||||
如果提供的模块名为某个插件的子模块,同样会返回该插件。
|
||||
|
||||
@@ -12,7 +12,6 @@ from itertools import chain
|
||||
import json
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
from typing import Optional, Union
|
||||
|
||||
from nonebot.log import logger
|
||||
from nonebot.utils import path_to_module_name
|
||||
@@ -27,7 +26,7 @@ except ModuleNotFoundError: # pragma: py-lt-311
|
||||
import tomli as tomllib # pyright: ignore[reportMissingImports]
|
||||
|
||||
|
||||
def load_plugin(module_path: Union[str, Path]) -> Optional[Plugin]:
|
||||
def load_plugin(module_path: str | Path) -> Plugin | None:
|
||||
"""加载单个插件,可以是本地插件或是通过 `pip` 安装的插件。
|
||||
|
||||
参数:
|
||||
@@ -159,7 +158,7 @@ def load_from_toml(file_path: str, encoding: str = "utf-8") -> set[Plugin]:
|
||||
)
|
||||
|
||||
|
||||
def load_builtin_plugin(name: str) -> Optional[Plugin]:
|
||||
def load_builtin_plugin(name: str) -> Plugin | None:
|
||||
"""导入 NoneBot 内置插件。
|
||||
|
||||
参数:
|
||||
@@ -177,7 +176,7 @@ def load_builtin_plugins(*plugins: str) -> set[Plugin]:
|
||||
return load_all_plugins([f"nonebot.plugins.{p}" for p in plugins], [])
|
||||
|
||||
|
||||
def _find_manager_by_name(name: str) -> Optional[PluginManager]:
|
||||
def _find_manager_by_name(name: str) -> PluginManager | None:
|
||||
for manager in reversed(_managers):
|
||||
if (
|
||||
name in manager.controlled_modules
|
||||
@@ -217,7 +216,7 @@ def require(name: str) -> ModuleType:
|
||||
return plugin.module
|
||||
|
||||
|
||||
def inherit_supported_adapters(*names: str) -> Optional[set[str]]:
|
||||
def inherit_supported_adapters(*names: str) -> set[str] | None:
|
||||
"""获取已加载插件的适配器支持状态集合。
|
||||
|
||||
如果传入了多个插件名称,返回值会自动取交集。
|
||||
@@ -229,7 +228,7 @@ def inherit_supported_adapters(*names: str) -> Optional[set[str]]:
|
||||
RuntimeError: 插件未加载
|
||||
ValueError: 插件缺少元数据
|
||||
"""
|
||||
final_supported: Optional[set[str]] = None
|
||||
final_supported: set[str] | None = None
|
||||
|
||||
for name in names:
|
||||
plugin = get_plugin(_module_name_to_plugin_id(name))
|
||||
|
||||
@@ -18,7 +18,6 @@ from pathlib import Path
|
||||
import pkgutil
|
||||
import sys
|
||||
from types import ModuleType
|
||||
from typing import Optional
|
||||
|
||||
from nonebot.log import logger
|
||||
from nonebot.utils import escape_tag, path_to_module_name
|
||||
@@ -43,8 +42,8 @@ class PluginManager:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
plugins: Optional[Iterable[str]] = None,
|
||||
search_path: Optional[Iterable[str]] = None,
|
||||
plugins: Iterable[str] | None = None,
|
||||
search_path: Iterable[str] | None = None,
|
||||
):
|
||||
# simple plugin not in search path
|
||||
self.plugins: set[str] = set(plugins or [])
|
||||
@@ -154,7 +153,7 @@ class PluginManager:
|
||||
|
||||
return self.available_plugins
|
||||
|
||||
def load_plugin(self, name: str) -> Optional[Plugin]:
|
||||
def load_plugin(self, name: str) -> Plugin | None:
|
||||
"""加载指定插件。
|
||||
|
||||
可以使用完整插件模块名或者插件标识符加载。
|
||||
@@ -211,8 +210,8 @@ class PluginFinder(MetaPathFinder):
|
||||
def find_spec(
|
||||
self,
|
||||
fullname: str,
|
||||
path: Optional[Sequence[str]],
|
||||
target: Optional[ModuleType] = None,
|
||||
path: Sequence[str] | None,
|
||||
target: ModuleType | None = None,
|
||||
):
|
||||
if _managers:
|
||||
module_spec = PathFinder.find_spec(fullname, path, target)
|
||||
@@ -235,7 +234,7 @@ class PluginLoader(SourceFileLoader):
|
||||
self.loaded = False
|
||||
super().__init__(fullname, path)
|
||||
|
||||
def create_module(self, spec) -> Optional[ModuleType]:
|
||||
def create_module(self, spec) -> ModuleType | None:
|
||||
if self.name in sys.modules:
|
||||
self.loaded = True
|
||||
return sys.modules[self.name]
|
||||
@@ -263,7 +262,7 @@ class PluginLoader(SourceFileLoader):
|
||||
_current_plugin.reset(_plugin_token)
|
||||
|
||||
# get plugin metadata
|
||||
metadata: Optional[PluginMetadata] = getattr(module, "__plugin_meta__", None)
|
||||
metadata: PluginMetadata | None = getattr(module, "__plugin_meta__", None)
|
||||
plugin.metadata = metadata
|
||||
|
||||
return
|
||||
|
||||
@@ -10,7 +10,7 @@ FrontMatter:
|
||||
import contextlib
|
||||
from dataclasses import dataclass, field
|
||||
from types import ModuleType
|
||||
from typing import TYPE_CHECKING, Any, Optional, Type # noqa: UP035
|
||||
from typing import TYPE_CHECKING, Any, Type # noqa: UP035
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -33,13 +33,13 @@ class PluginMetadata:
|
||||
"""插件功能介绍"""
|
||||
usage: str
|
||||
"""插件使用方法"""
|
||||
type: Optional[str] = None
|
||||
type: str | None = None
|
||||
"""插件类型,用于商店分类"""
|
||||
homepage: Optional[str] = None
|
||||
homepage: str | None = None
|
||||
"""插件主页"""
|
||||
config: Optional[Type[BaseModel]] = None # noqa: UP006
|
||||
config: Type[BaseModel] | None = None # noqa: UP006
|
||||
"""插件配置项"""
|
||||
supported_adapters: Optional[set[str]] = None
|
||||
supported_adapters: set[str] | None = None
|
||||
"""插件支持的适配器模块路径
|
||||
|
||||
格式为 `<module>[:<Adapter>]`,`~` 为 `nonebot.adapters.` 的缩写。
|
||||
@@ -49,7 +49,7 @@ class PluginMetadata:
|
||||
extra: dict[Any, Any] = field(default_factory=dict)
|
||||
"""插件额外信息,可由插件编写者自由扩展定义"""
|
||||
|
||||
def get_supported_adapters(self) -> Optional[set[Type["Adapter"]]]: # noqa: UP006
|
||||
def get_supported_adapters(self) -> set[Type["Adapter"]] | None: # noqa: UP006
|
||||
"""获取当前已安装的插件支持适配器类列表"""
|
||||
if self.supported_adapters is None:
|
||||
return None
|
||||
@@ -77,11 +77,11 @@ class Plugin:
|
||||
"""导入该插件的插件管理器"""
|
||||
matcher: set[type[Matcher]] = field(default_factory=set)
|
||||
"""插件加载时定义的 `Matcher`"""
|
||||
parent_plugin: Optional["Plugin"] = None
|
||||
parent_plugin: "Plugin | None" = None
|
||||
"""父插件"""
|
||||
sub_plugins: set["Plugin"] = field(default_factory=set)
|
||||
"""子插件集合"""
|
||||
metadata: Optional[PluginMetadata] = None
|
||||
metadata: PluginMetadata | None = None
|
||||
"""插件元信息"""
|
||||
|
||||
@property
|
||||
|
||||
@@ -11,7 +11,7 @@ from datetime import datetime, timedelta
|
||||
import inspect
|
||||
import re
|
||||
from types import ModuleType
|
||||
from typing import Any, Optional, Union
|
||||
from typing import Any
|
||||
import warnings
|
||||
|
||||
from nonebot.adapters import Event
|
||||
@@ -48,7 +48,7 @@ def store_matcher(matcher: type[Matcher]) -> None:
|
||||
plugin.matcher.add(matcher)
|
||||
|
||||
|
||||
def get_matcher_plugin(depth: int = 1) -> Optional[Plugin]: # pragma: no cover
|
||||
def get_matcher_plugin(depth: int = 1) -> Plugin | None: # pragma: no cover
|
||||
"""获取事件响应器定义所在插件。
|
||||
|
||||
**Deprecated**, 请使用 {ref}`nonebot.plugin.on.get_matcher_source` 获取信息。
|
||||
@@ -63,7 +63,7 @@ def get_matcher_plugin(depth: int = 1) -> Optional[Plugin]: # pragma: no cover
|
||||
return (source := get_matcher_source(depth + 1)) and source.plugin
|
||||
|
||||
|
||||
def get_matcher_module(depth: int = 1) -> Optional[ModuleType]: # pragma: no cover
|
||||
def get_matcher_module(depth: int = 1) -> ModuleType | None: # pragma: no cover
|
||||
"""获取事件响应器定义所在模块。
|
||||
|
||||
**Deprecated**, 请使用 {ref}`nonebot.plugin.on.get_matcher_source` 获取信息。
|
||||
@@ -78,7 +78,7 @@ def get_matcher_module(depth: int = 1) -> Optional[ModuleType]: # pragma: no co
|
||||
return (source := get_matcher_source(depth + 1)) and source.module
|
||||
|
||||
|
||||
def get_matcher_source(depth: int = 0) -> Optional[MatcherSource]:
|
||||
def get_matcher_source(depth: int = 0) -> MatcherSource | None:
|
||||
"""获取事件响应器定义所在源码信息。
|
||||
|
||||
参数:
|
||||
@@ -99,7 +99,7 @@ def get_matcher_source(depth: int = 0) -> Optional[MatcherSource]:
|
||||
module_name = (module := inspect.getmodule(frame)) and module.__name__
|
||||
|
||||
# matcher defined when plugin loading
|
||||
plugin: Optional["Plugin"] = _current_plugin.get()
|
||||
plugin: Plugin | None = _current_plugin.get()
|
||||
# matcher defined when plugin running
|
||||
if plugin is None and module_name:
|
||||
plugin = get_plugin_by_module_name(module_name)
|
||||
@@ -113,15 +113,15 @@ def get_matcher_source(depth: int = 0) -> Optional[MatcherSource]:
|
||||
|
||||
def on(
|
||||
type: str = "",
|
||||
rule: Optional[Union[Rule, T_RuleChecker]] = None,
|
||||
permission: Optional[Union[Permission, T_PermissionChecker]] = None,
|
||||
rule: Rule | T_RuleChecker | None = None,
|
||||
permission: Permission | T_PermissionChecker | None = None,
|
||||
*,
|
||||
handlers: Optional[list[Union[T_Handler, Dependent[Any]]]] = None,
|
||||
handlers: list[T_Handler | Dependent[Any]] | None = None,
|
||||
temp: bool = False,
|
||||
expire_time: Optional[Union[datetime, timedelta]] = None,
|
||||
expire_time: datetime | timedelta | None = None,
|
||||
priority: int = 1,
|
||||
block: bool = False,
|
||||
state: Optional[T_State] = None,
|
||||
state: T_State | None = None,
|
||||
_depth: int = 0,
|
||||
) -> type[Matcher]:
|
||||
"""注册一个基础事件响应器,可自定义类型。
|
||||
@@ -219,8 +219,8 @@ def on_request(*args, _depth: int = 0, **kwargs) -> type[Matcher]:
|
||||
|
||||
|
||||
def on_startswith(
|
||||
msg: Union[str, tuple[str, ...]],
|
||||
rule: Optional[Union[Rule, T_RuleChecker]] = None,
|
||||
msg: str | tuple[str, ...],
|
||||
rule: Rule | T_RuleChecker | None = None,
|
||||
ignorecase: bool = False,
|
||||
_depth: int = 0,
|
||||
**kwargs,
|
||||
@@ -243,8 +243,8 @@ def on_startswith(
|
||||
|
||||
|
||||
def on_endswith(
|
||||
msg: Union[str, tuple[str, ...]],
|
||||
rule: Optional[Union[Rule, T_RuleChecker]] = None,
|
||||
msg: str | tuple[str, ...],
|
||||
rule: Rule | T_RuleChecker | None = None,
|
||||
ignorecase: bool = False,
|
||||
_depth: int = 0,
|
||||
**kwargs,
|
||||
@@ -267,8 +267,8 @@ def on_endswith(
|
||||
|
||||
|
||||
def on_fullmatch(
|
||||
msg: Union[str, tuple[str, ...]],
|
||||
rule: Optional[Union[Rule, T_RuleChecker]] = None,
|
||||
msg: str | tuple[str, ...],
|
||||
rule: Rule | T_RuleChecker | None = None,
|
||||
ignorecase: bool = False,
|
||||
_depth: int = 0,
|
||||
**kwargs,
|
||||
@@ -292,7 +292,7 @@ def on_fullmatch(
|
||||
|
||||
def on_keyword(
|
||||
keywords: set[str],
|
||||
rule: Optional[Union[Rule, T_RuleChecker]] = None,
|
||||
rule: Rule | T_RuleChecker | None = None,
|
||||
_depth: int = 0,
|
||||
**kwargs,
|
||||
) -> type[Matcher]:
|
||||
@@ -313,10 +313,10 @@ def on_keyword(
|
||||
|
||||
|
||||
def on_command(
|
||||
cmd: Union[str, tuple[str, ...]],
|
||||
rule: Optional[Union[Rule, T_RuleChecker]] = None,
|
||||
aliases: Optional[set[Union[str, tuple[str, ...]]]] = None,
|
||||
force_whitespace: Optional[Union[str, bool]] = None,
|
||||
cmd: str | tuple[str, ...],
|
||||
rule: Rule | T_RuleChecker | None = None,
|
||||
aliases: set[str | tuple[str, ...]] | None = None,
|
||||
force_whitespace: str | bool | None = None,
|
||||
_depth: int = 0,
|
||||
**kwargs,
|
||||
) -> type[Matcher]:
|
||||
@@ -348,10 +348,10 @@ def on_command(
|
||||
|
||||
|
||||
def on_shell_command(
|
||||
cmd: Union[str, tuple[str, ...]],
|
||||
rule: Optional[Union[Rule, T_RuleChecker]] = None,
|
||||
aliases: Optional[set[Union[str, tuple[str, ...]]]] = None,
|
||||
parser: Optional[ArgumentParser] = None,
|
||||
cmd: str | tuple[str, ...],
|
||||
rule: Rule | T_RuleChecker | None = None,
|
||||
aliases: set[str | tuple[str, ...]] | None = None,
|
||||
parser: ArgumentParser | None = None,
|
||||
_depth: int = 0,
|
||||
**kwargs,
|
||||
) -> type[Matcher]:
|
||||
@@ -386,8 +386,8 @@ def on_shell_command(
|
||||
|
||||
def on_regex(
|
||||
pattern: str,
|
||||
flags: Union[int, re.RegexFlag] = 0,
|
||||
rule: Optional[Union[Rule, T_RuleChecker]] = None,
|
||||
flags: int | re.RegexFlag = 0,
|
||||
rule: Rule | T_RuleChecker | None = None,
|
||||
_depth: int = 0,
|
||||
**kwargs,
|
||||
) -> type[Matcher]:
|
||||
@@ -411,8 +411,8 @@ def on_regex(
|
||||
|
||||
|
||||
def on_type(
|
||||
types: Union[type[Event], tuple[type[Event], ...]],
|
||||
rule: Optional[Union[Rule, T_RuleChecker]] = None,
|
||||
types: type[Event] | tuple[type[Event], ...],
|
||||
rule: Rule | T_RuleChecker | None = None,
|
||||
*,
|
||||
_depth: int = 0,
|
||||
**kwargs,
|
||||
@@ -443,7 +443,7 @@ class _Group:
|
||||
"""其他传递给 `on` 的参数默认值"""
|
||||
|
||||
def _get_final_kwargs(
|
||||
self, update: dict[str, Any], *, exclude: Optional[set[str]] = None
|
||||
self, update: dict[str, Any], *, exclude: set[str] | None = None
|
||||
) -> dict[str, Any]:
|
||||
"""获取最终传递给 `on` 的参数
|
||||
|
||||
@@ -477,7 +477,7 @@ class CommandGroup(_Group):
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, cmd: Union[str, tuple[str, ...]], prefix_aliases: bool = False, **kwargs
|
||||
self, cmd: str | tuple[str, ...], prefix_aliases: bool = False, **kwargs
|
||||
):
|
||||
"""命令前缀"""
|
||||
super().__init__(**kwargs)
|
||||
@@ -488,7 +488,7 @@ class CommandGroup(_Group):
|
||||
def __repr__(self) -> str:
|
||||
return f"CommandGroup(cmd={self.basecmd}, matchers={len(self.matchers)})"
|
||||
|
||||
def command(self, cmd: Union[str, tuple[str, ...]], **kwargs) -> type[Matcher]:
|
||||
def command(self, cmd: str | tuple[str, ...], **kwargs) -> type[Matcher]:
|
||||
"""注册一个新的命令。新参数将会覆盖命令组默认值
|
||||
|
||||
参数:
|
||||
@@ -515,9 +515,7 @@ class CommandGroup(_Group):
|
||||
self.matchers.append(matcher)
|
||||
return matcher
|
||||
|
||||
def shell_command(
|
||||
self, cmd: Union[str, tuple[str, ...]], **kwargs
|
||||
) -> type[Matcher]:
|
||||
def shell_command(self, cmd: str | tuple[str, ...], **kwargs) -> type[Matcher]:
|
||||
"""注册一个新的 `shell_like` 命令。新参数将会覆盖命令组默认值
|
||||
|
||||
参数:
|
||||
@@ -641,9 +639,7 @@ class MatcherGroup(_Group):
|
||||
self.matchers.append(matcher)
|
||||
return matcher
|
||||
|
||||
def on_startswith(
|
||||
self, msg: Union[str, tuple[str, ...]], **kwargs
|
||||
) -> type[Matcher]:
|
||||
def on_startswith(self, msg: str | tuple[str, ...], **kwargs) -> type[Matcher]:
|
||||
"""注册一个消息事件响应器,并且当消息的**文本部分**以指定内容开头时响应。
|
||||
|
||||
参数:
|
||||
@@ -663,7 +659,7 @@ class MatcherGroup(_Group):
|
||||
self.matchers.append(matcher)
|
||||
return matcher
|
||||
|
||||
def on_endswith(self, msg: Union[str, tuple[str, ...]], **kwargs) -> type[Matcher]:
|
||||
def on_endswith(self, msg: str | tuple[str, ...], **kwargs) -> type[Matcher]:
|
||||
"""注册一个消息事件响应器,并且当消息的**文本部分**以指定内容结尾时响应。
|
||||
|
||||
参数:
|
||||
@@ -683,7 +679,7 @@ class MatcherGroup(_Group):
|
||||
self.matchers.append(matcher)
|
||||
return matcher
|
||||
|
||||
def on_fullmatch(self, msg: Union[str, tuple[str, ...]], **kwargs) -> type[Matcher]:
|
||||
def on_fullmatch(self, msg: str | tuple[str, ...], **kwargs) -> type[Matcher]:
|
||||
"""注册一个消息事件响应器,并且当消息的**文本部分**与指定内容完全一致时响应。
|
||||
|
||||
参数:
|
||||
@@ -724,9 +720,9 @@ class MatcherGroup(_Group):
|
||||
|
||||
def on_command(
|
||||
self,
|
||||
cmd: Union[str, tuple[str, ...]],
|
||||
aliases: Optional[set[Union[str, tuple[str, ...]]]] = None,
|
||||
force_whitespace: Optional[Union[str, bool]] = None,
|
||||
cmd: str | tuple[str, ...],
|
||||
aliases: set[str | tuple[str, ...]] | None = None,
|
||||
force_whitespace: str | bool | None = None,
|
||||
**kwargs,
|
||||
) -> type[Matcher]:
|
||||
"""注册一个消息事件响应器,并且当消息以指定命令开头时响应。
|
||||
@@ -755,9 +751,9 @@ class MatcherGroup(_Group):
|
||||
|
||||
def on_shell_command(
|
||||
self,
|
||||
cmd: Union[str, tuple[str, ...]],
|
||||
aliases: Optional[set[Union[str, tuple[str, ...]]]] = None,
|
||||
parser: Optional[ArgumentParser] = None,
|
||||
cmd: str | tuple[str, ...],
|
||||
aliases: set[str | tuple[str, ...]] | None = None,
|
||||
parser: ArgumentParser | None = None,
|
||||
**kwargs,
|
||||
) -> type[Matcher]:
|
||||
"""注册一个支持 `shell_like` 解析参数的命令消息事件响应器。
|
||||
@@ -786,7 +782,7 @@ class MatcherGroup(_Group):
|
||||
return matcher
|
||||
|
||||
def on_regex(
|
||||
self, pattern: str, flags: Union[int, re.RegexFlag] = 0, **kwargs
|
||||
self, pattern: str, flags: int | re.RegexFlag = 0, **kwargs
|
||||
) -> type[Matcher]:
|
||||
"""注册一个消息事件响应器,并且当消息匹配正则表达式时响应。
|
||||
|
||||
@@ -810,7 +806,7 @@ class MatcherGroup(_Group):
|
||||
return matcher
|
||||
|
||||
def on_type(
|
||||
self, types: Union[type[Event], tuple[type[Event]]], **kwargs
|
||||
self, types: type[Event] | tuple[type[Event]], **kwargs
|
||||
) -> type[Matcher]:
|
||||
"""注册一个事件响应器,并且当事件为指定类型时响应。
|
||||
|
||||
|
||||
@@ -24,10 +24,8 @@ from typing import (
|
||||
IO,
|
||||
TYPE_CHECKING,
|
||||
NamedTuple,
|
||||
Optional,
|
||||
TypedDict,
|
||||
TypeVar,
|
||||
Union,
|
||||
cast,
|
||||
overload,
|
||||
)
|
||||
@@ -61,11 +59,11 @@ T = TypeVar("T")
|
||||
|
||||
|
||||
class CMD_RESULT(TypedDict):
|
||||
command: Optional[tuple[str, ...]]
|
||||
raw_command: Optional[str]
|
||||
command_arg: Optional[Message]
|
||||
command_start: Optional[str]
|
||||
command_whitespace: Optional[str]
|
||||
command: tuple[str, ...] | None
|
||||
raw_command: str | None
|
||||
command_arg: Message | None
|
||||
command_start: str | None
|
||||
command_whitespace: str | None
|
||||
|
||||
|
||||
class TRIE_VALUE(NamedTuple):
|
||||
@@ -179,7 +177,7 @@ class StartswithRule:
|
||||
return False
|
||||
|
||||
|
||||
def startswith(msg: Union[str, tuple[str, ...]], ignorecase: bool = False) -> Rule:
|
||||
def startswith(msg: str | tuple[str, ...], ignorecase: bool = False) -> Rule:
|
||||
"""匹配消息纯文本开头。
|
||||
|
||||
参数:
|
||||
@@ -234,7 +232,7 @@ class EndswithRule:
|
||||
return False
|
||||
|
||||
|
||||
def endswith(msg: Union[str, tuple[str, ...]], ignorecase: bool = False) -> Rule:
|
||||
def endswith(msg: str | tuple[str, ...], ignorecase: bool = False) -> Rule:
|
||||
"""匹配消息纯文本结尾。
|
||||
|
||||
参数:
|
||||
@@ -288,7 +286,7 @@ class FullmatchRule:
|
||||
return False
|
||||
|
||||
|
||||
def fullmatch(msg: Union[str, tuple[str, ...]], ignorecase: bool = False) -> Rule:
|
||||
def fullmatch(msg: str | tuple[str, ...], ignorecase: bool = False) -> Rule:
|
||||
"""完全匹配消息。
|
||||
|
||||
参数:
|
||||
@@ -360,7 +358,7 @@ class CommandRule:
|
||||
def __init__(
|
||||
self,
|
||||
cmds: list[tuple[str, ...]],
|
||||
force_whitespace: Optional[Union[str, bool]] = None,
|
||||
force_whitespace: str | bool | None = None,
|
||||
):
|
||||
self.cmds = tuple(cmds)
|
||||
self.force_whitespace = force_whitespace
|
||||
@@ -378,9 +376,9 @@ class CommandRule:
|
||||
|
||||
async def __call__(
|
||||
self,
|
||||
cmd: Optional[tuple[str, ...]] = Command(),
|
||||
cmd_arg: Optional[Message] = CommandArg(),
|
||||
cmd_whitespace: Optional[str] = CommandWhitespace(),
|
||||
cmd: tuple[str, ...] | None = Command(),
|
||||
cmd_arg: Message | None = CommandArg(),
|
||||
cmd_whitespace: str | None = CommandWhitespace(),
|
||||
) -> bool:
|
||||
if cmd not in self.cmds:
|
||||
return False
|
||||
@@ -392,8 +390,8 @@ class CommandRule:
|
||||
|
||||
|
||||
def command(
|
||||
*cmds: Union[str, tuple[str, ...]],
|
||||
force_whitespace: Optional[Union[str, bool]] = None,
|
||||
*cmds: str | tuple[str, ...],
|
||||
force_whitespace: str | bool | None = None,
|
||||
) -> Rule:
|
||||
"""匹配消息命令。
|
||||
|
||||
@@ -456,36 +454,36 @@ class ArgumentParser(ArgParser):
|
||||
@overload
|
||||
def parse_known_args(
|
||||
self,
|
||||
args: Optional[Sequence[Union[str, MessageSegment]]] = None,
|
||||
args: Sequence[str | MessageSegment] | None = None,
|
||||
namespace: None = None,
|
||||
) -> tuple[Namespace, list[Union[str, MessageSegment]]]: ...
|
||||
) -> tuple[Namespace, list[str | MessageSegment]]: ...
|
||||
|
||||
@overload
|
||||
def parse_known_args(
|
||||
self, args: Optional[Sequence[Union[str, MessageSegment]]], namespace: T
|
||||
) -> tuple[T, list[Union[str, MessageSegment]]]: ...
|
||||
self, args: Sequence[str | MessageSegment] | None, namespace: T
|
||||
) -> tuple[T, list[str | MessageSegment]]: ...
|
||||
|
||||
@overload
|
||||
def parse_known_args(
|
||||
self, *, namespace: T
|
||||
) -> tuple[T, list[Union[str, MessageSegment]]]: ...
|
||||
) -> tuple[T, list[str | MessageSegment]]: ...
|
||||
|
||||
def parse_known_args( # pyright: ignore[reportIncompatibleMethodOverride]
|
||||
self,
|
||||
args: Optional[Sequence[Union[str, MessageSegment]]] = None,
|
||||
namespace: Optional[T] = None,
|
||||
) -> tuple[Union[Namespace, T], list[Union[str, MessageSegment]]]: ...
|
||||
args: Sequence[str | MessageSegment] | None = None,
|
||||
namespace: T | None = None,
|
||||
) -> tuple[Namespace | T, list[str | MessageSegment]]: ...
|
||||
|
||||
@overload
|
||||
def parse_args(
|
||||
self,
|
||||
args: Optional[Sequence[Union[str, MessageSegment]]] = None,
|
||||
args: Sequence[str | MessageSegment] | None = None,
|
||||
namespace: None = None,
|
||||
) -> Namespace: ...
|
||||
|
||||
@overload
|
||||
def parse_args(
|
||||
self, args: Optional[Sequence[Union[str, MessageSegment]]], namespace: T
|
||||
self, args: Sequence[str | MessageSegment] | None, namespace: T
|
||||
) -> T: ...
|
||||
|
||||
@overload
|
||||
@@ -493,29 +491,29 @@ class ArgumentParser(ArgParser):
|
||||
|
||||
def parse_args(
|
||||
self,
|
||||
args: Optional[Sequence[Union[str, MessageSegment]]] = None,
|
||||
namespace: Optional[T] = None,
|
||||
) -> Union[Namespace, T]:
|
||||
args: Sequence[str | MessageSegment] | None = None,
|
||||
namespace: T | None = None,
|
||||
) -> Namespace | T:
|
||||
result, argv = self.parse_known_args(args, namespace)
|
||||
if argv:
|
||||
msg = gettext("unrecognized arguments: %s")
|
||||
self.error(msg % " ".join(map(str, argv)))
|
||||
return cast(Union[Namespace, T], result)
|
||||
return cast(Namespace | T, result)
|
||||
|
||||
def _parse_optional(
|
||||
self, arg_string: Union[str, MessageSegment]
|
||||
) -> Optional[tuple[Optional[Action], str, Optional[str]]]:
|
||||
self, arg_string: str | MessageSegment
|
||||
) -> tuple[Action | None, str, str | None] | None:
|
||||
return (
|
||||
super()._parse_optional(arg_string) if isinstance(arg_string, str) else None
|
||||
)
|
||||
|
||||
def _print_message(self, message: str, file: Optional[IO[str]] = None): # type: ignore
|
||||
def _print_message(self, message: str, file: IO[str] | None = None): # type: ignore
|
||||
if (msg := parser_message.get(None)) is not None:
|
||||
parser_message.set(msg + message)
|
||||
else:
|
||||
super()._print_message(message, file)
|
||||
|
||||
def exit(self, status: int = 0, message: Optional[str] = None):
|
||||
def exit(self, status: int = 0, message: str | None = None):
|
||||
if message:
|
||||
self._print_message(message)
|
||||
raise ParserExit(status=status, message=parser_message.get(None))
|
||||
@@ -531,7 +529,7 @@ class ShellCommandRule:
|
||||
|
||||
__slots__ = ("cmds", "parser")
|
||||
|
||||
def __init__(self, cmds: list[tuple[str, ...]], parser: Optional[ArgumentParser]):
|
||||
def __init__(self, cmds: list[tuple[str, ...]], parser: ArgumentParser | None):
|
||||
self.cmds = tuple(cmds)
|
||||
self.parser = parser
|
||||
|
||||
@@ -551,8 +549,8 @@ class ShellCommandRule:
|
||||
async def __call__(
|
||||
self,
|
||||
state: T_State,
|
||||
cmd: Optional[tuple[str, ...]] = Command(),
|
||||
msg: Optional[Message] = CommandArg(),
|
||||
cmd: tuple[str, ...] | None = Command(),
|
||||
msg: Message | None = CommandArg(),
|
||||
) -> bool:
|
||||
if cmd not in self.cmds or msg is None:
|
||||
return False
|
||||
@@ -589,7 +587,7 @@ class ShellCommandRule:
|
||||
|
||||
|
||||
def shell_command(
|
||||
*cmds: Union[str, tuple[str, ...]], parser: Optional[ArgumentParser] = None
|
||||
*cmds: str | tuple[str, ...], parser: ArgumentParser | None = None
|
||||
) -> Rule:
|
||||
"""匹配 `shell_like` 形式的消息命令。
|
||||
|
||||
@@ -695,7 +693,7 @@ class RegexRule:
|
||||
return False
|
||||
|
||||
|
||||
def regex(regex: str, flags: Union[int, re.RegexFlag] = 0) -> Rule:
|
||||
def regex(regex: str, flags: int | re.RegexFlag = 0) -> Rule:
|
||||
"""匹配符合正则表达式的消息字符串。
|
||||
|
||||
可以通过 {ref}`nonebot.params.RegexStr` 获取匹配成功的字符串,
|
||||
|
||||
@@ -15,9 +15,9 @@ FrontMatter:
|
||||
import sys
|
||||
import types
|
||||
import typing as t
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
from typing import TYPE_CHECKING, TypeAlias, TypeVar, get_args, get_origin
|
||||
import typing_extensions as t_ext
|
||||
from typing_extensions import ParamSpec, TypeAlias, get_args, get_origin, override
|
||||
from typing_extensions import ParamSpec, override
|
||||
import warnings
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -43,31 +43,15 @@ def overrides(InterfaceClass: object):
|
||||
return override
|
||||
|
||||
|
||||
if sys.version_info < (3, 10):
|
||||
|
||||
def type_has_args(type_: type[t.Any]) -> bool:
|
||||
"""判断类型是否有参数"""
|
||||
return isinstance(type_, (t._GenericAlias, types.GenericAlias)) # type: ignore
|
||||
|
||||
else:
|
||||
|
||||
def type_has_args(type_: type[t.Any]) -> bool:
|
||||
return isinstance(type_, (t._GenericAlias, types.GenericAlias, types.UnionType)) # type: ignore
|
||||
def type_has_args(type_: type[t.Any]) -> bool:
|
||||
return isinstance(type_, (t._GenericAlias, types.GenericAlias, types.UnionType)) # type: ignore
|
||||
|
||||
|
||||
if sys.version_info < (3, 10):
|
||||
|
||||
def origin_is_union(origin: t.Optional[type[t.Any]]) -> bool:
|
||||
"""判断是否是 Union 类型"""
|
||||
return origin is t.Union
|
||||
|
||||
else:
|
||||
|
||||
def origin_is_union(origin: t.Optional[type[t.Any]]) -> bool:
|
||||
return origin is t.Union or origin is types.UnionType
|
||||
def origin_is_union(origin: type[t.Any] | None) -> bool:
|
||||
return origin is t.Union or origin is types.UnionType
|
||||
|
||||
|
||||
def origin_is_literal(origin: t.Optional[type[t.Any]]) -> bool:
|
||||
def origin_is_literal(origin: type[t.Any] | None) -> bool:
|
||||
"""判断是否是 Literal 类型"""
|
||||
return origin is t.Literal or origin is t_ext.Literal
|
||||
|
||||
@@ -84,14 +68,12 @@ def all_literal_values(type_: type[t.Any]) -> list[t.Any]:
|
||||
return [x for value in _literal_values(type_) for x in all_literal_values(value)]
|
||||
|
||||
|
||||
def origin_is_annotated(origin: t.Optional[type[t.Any]]) -> bool:
|
||||
def origin_is_annotated(origin: type[t.Any] | None) -> bool:
|
||||
"""判断是否是 Annotated 类型"""
|
||||
return origin is t_ext.Annotated
|
||||
|
||||
|
||||
NONE_TYPES = {None, type(None), t.Literal[None], t_ext.Literal[None]} # noqa: PYI061
|
||||
if sys.version_info >= (3, 10):
|
||||
NONE_TYPES.add(types.NoneType)
|
||||
NONE_TYPES = {None, type(None), t.Literal[None], t_ext.Literal[None], types.NoneType} # noqa: PYI061
|
||||
|
||||
|
||||
def is_none_type(type_: type[t.Any]) -> bool:
|
||||
@@ -133,9 +115,7 @@ _STATE_FLAG = StateFlag()
|
||||
T_State: TypeAlias = t.Annotated[dict[t.Any, t.Any], _STATE_FLAG]
|
||||
"""事件处理状态 State 类型"""
|
||||
|
||||
_DependentCallable: TypeAlias = t.Union[
|
||||
t.Callable[..., T], t.Callable[..., t.Awaitable[T]]
|
||||
]
|
||||
_DependentCallable: TypeAlias = t.Callable[..., T] | t.Callable[..., t.Awaitable[T]]
|
||||
|
||||
# driver hooks
|
||||
T_BotConnectionHook: TypeAlias = _DependentCallable[t.Any]
|
||||
@@ -163,7 +143,7 @@ T_CallingAPIHook: TypeAlias = t.Callable[
|
||||
]
|
||||
"""`bot.call_api` 钩子函数"""
|
||||
T_CalledAPIHook: TypeAlias = t.Callable[
|
||||
["Bot", t.Optional[Exception], str, dict[str, t.Any], t.Any], t.Awaitable[t.Any]
|
||||
["Bot", Exception | None, str, dict[str, t.Any], t.Any], t.Awaitable[t.Any]
|
||||
]
|
||||
"""`bot.call_api` 后执行的函数,参数分别为 bot, exception, api, data, result"""
|
||||
|
||||
|
||||
@@ -8,7 +8,14 @@ FrontMatter:
|
||||
"""
|
||||
|
||||
from collections import deque
|
||||
from collections.abc import AsyncGenerator, Coroutine, Generator, Mapping, Sequence
|
||||
from collections.abc import (
|
||||
AsyncGenerator,
|
||||
Callable,
|
||||
Coroutine,
|
||||
Generator,
|
||||
Mapping,
|
||||
Sequence,
|
||||
)
|
||||
import contextlib
|
||||
from contextlib import AbstractContextManager, asynccontextmanager
|
||||
import dataclasses
|
||||
@@ -18,8 +25,15 @@ import inspect
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
from typing import Any, Callable, Generic, Optional, TypeVar, Union, overload
|
||||
from typing_extensions import ParamSpec, get_args, get_origin, override
|
||||
from typing import (
|
||||
Any,
|
||||
Generic,
|
||||
TypeVar,
|
||||
get_args,
|
||||
get_origin,
|
||||
overload,
|
||||
)
|
||||
from typing_extensions import ParamSpec, override
|
||||
|
||||
import anyio
|
||||
import anyio.to_thread
|
||||
@@ -73,7 +87,7 @@ def deep_update(
|
||||
|
||||
|
||||
def lenient_issubclass(
|
||||
cls: Any, class_or_tuple: Union[type[Any], tuple[type[Any], ...]]
|
||||
cls: Any, class_or_tuple: type[Any] | tuple[type[Any], ...]
|
||||
) -> bool:
|
||||
"""检查 cls 是否是 class_or_tuple 中的一个类型子类并忽略类型错误。"""
|
||||
try:
|
||||
@@ -83,7 +97,7 @@ def lenient_issubclass(
|
||||
|
||||
|
||||
def generic_check_issubclass(
|
||||
cls: Any, class_or_tuple: Union[type[Any], tuple[type[Any], ...]]
|
||||
cls: Any, class_or_tuple: type[Any] | tuple[type[Any], ...]
|
||||
) -> bool:
|
||||
"""检查 cls 是否是 class_or_tuple 中的一个类型子类。
|
||||
|
||||
@@ -141,7 +155,7 @@ def type_is_complex(type_: type[Any]) -> bool:
|
||||
return _type_is_complex_inner(type_) or _type_is_complex_inner(origin)
|
||||
|
||||
|
||||
def _type_is_complex_inner(type_: Optional[type[Any]]) -> bool:
|
||||
def _type_is_complex_inner(type_: type[Any] | None) -> bool:
|
||||
if lenient_issubclass(type_, (str, bytes)):
|
||||
return False
|
||||
|
||||
@@ -212,7 +226,7 @@ async def run_coro_with_catch(
|
||||
coro: Coroutine[Any, Any, T],
|
||||
exc: tuple[type[Exception], ...],
|
||||
return_on_err: None = None,
|
||||
) -> Union[T, None]: ...
|
||||
) -> T | None: ...
|
||||
|
||||
|
||||
@overload
|
||||
@@ -220,14 +234,14 @@ async def run_coro_with_catch(
|
||||
coro: Coroutine[Any, Any, T],
|
||||
exc: tuple[type[Exception], ...],
|
||||
return_on_err: R,
|
||||
) -> Union[T, R]: ...
|
||||
) -> T | R: ...
|
||||
|
||||
|
||||
async def run_coro_with_catch(
|
||||
coro: Coroutine[Any, Any, T],
|
||||
exc: tuple[type[Exception], ...],
|
||||
return_on_err: Optional[R] = None,
|
||||
) -> Optional[Union[T, R]]:
|
||||
return_on_err: R | None = None,
|
||||
) -> T | R | None:
|
||||
"""运行协程并当遇到指定异常时返回指定值。
|
||||
|
||||
参数:
|
||||
@@ -288,7 +302,7 @@ def path_to_module_name(path: Path) -> str:
|
||||
|
||||
|
||||
def resolve_dot_notation(
|
||||
obj_str: str, default_attr: str, default_prefix: Optional[str] = None
|
||||
obj_str: str, default_attr: str, default_prefix: str | None = None
|
||||
) -> Any:
|
||||
"""解析并导入点分表示法的对象"""
|
||||
modulename, _, cls = obj_str.partition(":")
|
||||
@@ -309,7 +323,7 @@ class classproperty(Generic[T]):
|
||||
def __init__(self, func: Callable[[Any], T]) -> None:
|
||||
self.func = func
|
||||
|
||||
def __get__(self, instance: Any, owner: Optional[type[Any]] = None) -> T:
|
||||
def __get__(self, instance: Any, owner: type[Any] | None = None) -> T:
|
||||
return self.func(type(instance) if owner is None else owner)
|
||||
|
||||
|
||||
@@ -339,7 +353,7 @@ def logger_wrapper(logger_name: str):
|
||||
- exception: 异常信息
|
||||
"""
|
||||
|
||||
def log(level: str, message: str, exception: Optional[Exception] = None):
|
||||
def log(level: str, message: str, exception: Exception | None = None):
|
||||
logger.opt(colors=True, exception=exception).log(
|
||||
level, f"<m>{escape_tag(logger_name)}</m> | {message}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user