💥 remove Python 3.7 support (#1148)

This commit is contained in:
Ju4tCode 2022-08-14 19:41:00 +08:00 committed by GitHub
parent 0620bec51f
commit 4974c596ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 261 additions and 317 deletions

View File

@ -5,7 +5,7 @@ inputs:
python-version:
description: Python version
required: false
default: "3.9"
default: "3.10"
runs:
using: "composite"

View File

@ -15,7 +15,7 @@ jobs:
cancel-in-progress: true
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
python-version: ["3.8", "3.9", "3.10"]
os: [ubuntu-latest, windows-latest, macos-latest]
fail-fast: false
env:

View File

@ -21,7 +21,7 @@ _✨ 跨平台 Python 异步机器人框架 ✨_
<a href="https://pypi.python.org/pypi/nonebot2">
<img src="https://img.shields.io/pypi/v/nonebot2" alt="pypi">
</a>
<img src="https://img.shields.io/badge/python-3.7.3+-blue" alt="python">
<img src="https://img.shields.io/badge/python-3.8+-blue" alt="python">
<a href="https://codecov.io/gh/nonebot/nonebot2">
<img src="https://codecov.io/gh/nonebot/nonebot2/branch/master/graph/badge.svg?token=2P0G0VS7N4" alt="codecov"/>
</a>

View File

@ -171,8 +171,7 @@ def get_bots() -> Dict[str, Bot]:
bots = nonebot.get_bots()
```
"""
driver = get_driver()
return driver.bots
return get_driver().bots
def _resolve_dot_notation(
@ -240,7 +239,7 @@ def init(*, _env_file: Optional[str] = None, **kwargs: Any) -> None:
f"Loaded <y><b>Config</b></y>: {escape_tag(str(config.dict()))}"
)
DriverClass: Type[Driver] = _resolve_combine_expr(config.driver)
DriverClass = _resolve_combine_expr(config.driver)
_driver = DriverClass(env, config)

View File

@ -4,7 +4,7 @@ FrontMatter:
sidebar_position: 9
description: nonebot.consts 模块
"""
from typing_extensions import Literal
from typing import Literal
# used by Matcher
RECEIVE_KEY: Literal["_receive_{id}"] = "_receive_{id}"

View File

@ -7,7 +7,18 @@ FrontMatter:
import abc
import inspect
from typing import Any, Dict, List, Type, Generic, TypeVar, Callable, Optional
from typing import (
Any,
Dict,
List,
Type,
Generic,
TypeVar,
Callable,
Optional,
Awaitable,
cast,
)
from pydantic import BaseConfig
from pydantic.schema import get_annotation_from_field_info
@ -15,6 +26,7 @@ from pydantic.fields import Required, FieldInfo, Undefined, ModelField
from nonebot.log import logger
from nonebot.exception import TypeMisMatch
from nonebot.typing import _DependentCallable
from nonebot.utils import run_sync, is_coroutine_callable
from .utils import check_field_type, get_typed_signature
@ -64,7 +76,7 @@ class Dependent(Generic[R]):
def __init__(
self,
*,
call: Callable[..., Any],
call: _DependentCallable[R],
pre_checkers: Optional[List[Param]] = None,
params: Optional[List[ModelField]] = None,
parameterless: Optional[List[Param]] = None,
@ -89,29 +101,25 @@ class Dependent(Generic[R]):
values = await self.solve(**kwargs)
if is_coroutine_callable(self.call):
return await self.call(**values)
return await cast(Callable[..., Awaitable[R]], self.call)(**values)
else:
return await run_sync(self.call)(**values)
return await run_sync(cast(Callable[..., R], self.call))(**values)
def parse_param(self, name: str, param: inspect.Parameter) -> Param:
for allow_type in self.allow_types:
field_info = allow_type._check_param(self, name, param)
if field_info:
if field_info := allow_type._check_param(self, name, param):
return field_info
else:
raise ValueError(
f"Unknown parameter {name} for function {self.call} with type {param.annotation}"
)
raise ValueError(
f"Unknown parameter {name} for function {self.call} with type {param.annotation}"
)
def parse_parameterless(self, value: Any) -> Param:
for allow_type in self.allow_types:
field_info = allow_type._check_parameterless(self, value)
if field_info:
if field_info := allow_type._check_parameterless(self, value):
return field_info
else:
raise ValueError(
f"Unknown parameterless {value} for function {self.call} with type {type(value)}"
)
raise ValueError(
f"Unknown parameterless {value} for function {self.call} with type {type(value)}"
)
def prepend_parameterless(self, value: Any) -> None:
self.parameterless.insert(0, self.parse_parameterless(value))
@ -121,12 +129,12 @@ class Dependent(Generic[R]):
@classmethod
def parse(
cls: Type[T],
cls,
*,
call: Callable[..., Any],
call: _DependentCallable[R],
parameterless: Optional[List[Any]] = None,
allow_types: Optional[List[Type[Param]]] = None,
) -> T:
) -> "Dependent[R]":
signature = get_typed_signature(call)
params = signature.parameters
dependent = cls(
@ -141,10 +149,10 @@ class Dependent(Generic[R]):
if isinstance(default_value, Param):
field_info = default_value
default_value = field_info.default
else:
field_info = dependent.parse_param(param_name, param)
default_value = field_info.default
default_value = field_info.default
annotation: Any = Any
required = default_value == Required

View File

@ -28,8 +28,7 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
)
for param in signature.parameters.values()
]
typed_signature = inspect.Signature(typed_params)
return typed_signature
return inspect.Signature(typed_params)
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any:

View File

@ -1,7 +1,7 @@
import signal
import asyncio
import threading
from typing import Set, Union, Callable, Awaitable
from typing import Set, Union, Callable, Awaitable, cast
from nonebot.log import logger
from nonebot.drivers import Driver
@ -9,8 +9,7 @@ from nonebot.typing import overrides
from nonebot.config import Env, Config
from nonebot.utils import run_sync, is_coroutine_callable
STARTUP_FUNC = Callable[[], Union[None, Awaitable[None]]]
SHUTDOWN_FUNC = Callable[[], Union[None, Awaitable[None]]]
HOOK_FUNC = Union[Callable[[], None], Callable[[], Awaitable[None]]]
HANDLED_SIGNALS = (
signal.SIGINT, # Unix signal 2. Sent by Ctrl+C.
signal.SIGTERM, # Unix signal 15. Sent by `kill <pid>`.
@ -20,8 +19,8 @@ HANDLED_SIGNALS = (
class BlockDriver(Driver):
def __init__(self, env: Env, config: Config):
super().__init__(env, config)
self.startup_funcs: Set[STARTUP_FUNC] = set()
self.shutdown_funcs: Set[SHUTDOWN_FUNC] = set()
self.startup_funcs: Set[HOOK_FUNC] = set()
self.shutdown_funcs: Set[HOOK_FUNC] = set()
self.should_exit: asyncio.Event = asyncio.Event()
self.force_exit: bool = False
@ -38,7 +37,7 @@ class BlockDriver(Driver):
return logger
@overrides(Driver)
def on_startup(self, func: STARTUP_FUNC) -> STARTUP_FUNC:
def on_startup(self, func: HOOK_FUNC) -> HOOK_FUNC:
"""
注册一个启动时执行的函数
"""
@ -46,7 +45,7 @@ class BlockDriver(Driver):
return func
@overrides(Driver)
def on_shutdown(self, func: SHUTDOWN_FUNC) -> SHUTDOWN_FUNC:
def on_shutdown(self, func: HOOK_FUNC) -> HOOK_FUNC:
"""
注册一个停止时执行的函数
"""
@ -71,7 +70,9 @@ class BlockDriver(Driver):
async def startup(self):
# run startup
cors = [
startup() if is_coroutine_callable(startup) else run_sync(startup)()
cast(Callable[..., Awaitable[None]], startup)()
if is_coroutine_callable(startup)
else run_sync(startup)()
for startup in self.startup_funcs
]
if cors:
@ -94,7 +95,9 @@ class BlockDriver(Driver):
logger.info("Waiting for application shutdown.")
# run shutdown
cors = [
shutdown() if is_coroutine_callable(shutdown) else run_sync(shutdown)()
cast(Callable[..., Awaitable[None]], shutdown)()
if is_coroutine_callable(shutdown)
else run_sync(shutdown)()
for shutdown in self.shutdown_funcs
]
if cors:

View File

@ -9,7 +9,9 @@ FrontMatter:
description: nonebot.drivers.fastapi 模块
"""
import logging
import contextlib
from functools import wraps
from typing import Any, List, Tuple, Union, Callable, Optional
@ -186,14 +188,12 @@ class Driver(ReverseDriver):
setup: HTTPServerSetup,
) -> Response:
json: Any = None
try:
with contextlib.suppress(Exception):
json = await request.json()
except Exception:
pass
data: Optional[dict] = None
files: Optional[List[Tuple[str, FileTypes]]] = None
try:
with contextlib.suppress(Exception):
form = await request.form()
data = {}
files = []
@ -204,8 +204,7 @@ class Driver(ReverseDriver):
)
else:
data[key] = value
except Exception:
pass
http_request = BaseRequest(
request.method,
str(request.url),
@ -219,7 +218,9 @@ class Driver(ReverseDriver):
)
response = await setup.handle_func(http_request)
return Response(response.content, response.status_code, dict(response.headers))
return Response(
response.content, response.status_code, dict(response.headers.items())
)
async def _handle_ws(self, websocket: WebSocket, setup: WebSocketServerSetup):
request = BaseRequest(

View File

@ -1,8 +1,7 @@
import abc
import asyncio
from functools import partial
from typing_extensions import Protocol
from typing import TYPE_CHECKING, Any, Set, Union, Optional
from typing import TYPE_CHECKING, Any, Set, Union, Optional, Protocol
from nonebot.log import logger
from nonebot.config import Config
@ -72,8 +71,7 @@ class Bot(abc.ABC):
skip_calling_api: bool = False
exception: Optional[Exception] = None
coros = list(map(lambda x: x(self, api, data), self._calling_api_hook))
if coros:
if coros := [hook(self, api, data) for hook in self._calling_api_hook]:
try:
logger.debug("Running CallingAPI hooks...")
await asyncio.gather(*coros)
@ -95,10 +93,9 @@ class Bot(abc.ABC):
except Exception as e:
exception = e
coros = list(
map(lambda x: x(self, exception, api, data, result), self._called_api_hook)
)
if coros:
if coros := [
hook(self, exception, api, data, result) for hook in self._called_api_hook
]:
try:
logger.debug("Running CalledAPI hooks...")
await asyncio.gather(*coros)

View File

@ -233,13 +233,11 @@ def combine_driver(driver: Type[Driver], *mixins: Type[ForwardMixin]) -> Type[Dr
if not mixins:
return driver
class CombinedDriver(*mixins, driver, ForwardDriver): # type: ignore
@property
def type(self) -> str:
return (
driver.type.__get__(self)
+ "+"
+ "+".join(map(lambda x: x.type.__get__(self), mixins))
)
def type_(self: ForwardDriver) -> str:
return (
driver.type.__get__(self)
+ "+"
+ "+".join(map(lambda x: x.type.__get__(self), mixins))
)
return CombinedDriver
return type("CombinedDriver", (*mixins, driver, ForwardDriver), {"type": property(type_)}) # type: ignore

View File

@ -14,6 +14,7 @@ from typing import (
Callable,
NoReturn,
Optional,
overload,
)
from nonebot.log import logger
@ -551,7 +552,17 @@ class Matcher(metaclass=MatcherMeta):
"""
raise SkippedException
def get_receive(self, id: str, default: T = None) -> Union[Event, T]:
@overload
def get_receive(self, id: str) -> Union[Event, None]:
...
@overload
def get_receive(self, id: str, default: T) -> Union[Event, T]:
...
def get_receive(
self, id: str, default: Optional[T] = None
) -> Optional[Union[Event, T]]:
"""获取一个 `receive` 事件
如果没有找到对应的事件返回 `default`
@ -563,14 +574,34 @@ class Matcher(metaclass=MatcherMeta):
self.state[RECEIVE_KEY.format(id=id)] = event
self.state[LAST_RECEIVE_KEY] = event
def get_last_receive(self, default: T = None) -> Union[Event, T]:
@overload
def get_last_receive(self) -> Union[Event, None]:
...
@overload
def get_last_receive(self, default: T) -> Union[Event, T]:
...
def get_last_receive(
self, default: Optional[T] = None
) -> Optional[Union[Event, T]]:
"""获取最近一次 `receive` 事件
如果没有事件返回 `default`
"""
return self.state.get(LAST_RECEIVE_KEY, default)
def get_arg(self, key: str, default: T = None) -> Union[Message, T]:
@overload
def get_arg(self, key: str) -> Union[Message, None]:
...
@overload
def get_arg(self, key: str, default: T) -> Union[Message, T]:
...
def get_arg(
self, key: str, default: Optional[T] = None
) -> Optional[Union[Message, T]]:
"""获取一个 `got` 消息
如果没有找到对应的消息返回 `default`
@ -587,7 +618,15 @@ class Matcher(metaclass=MatcherMeta):
else:
self.state[REJECT_TARGET] = target
def get_target(self, default: T = None) -> Union[str, T]:
@overload
def get_target(self) -> Union[str, None]:
...
@overload
def get_target(self, default: T) -> Union[str, T]:
...
def get_target(self, default: Optional[T] = None) -> Optional[Union[str, T]]:
return self.state.get(REJECT_TARGET, default)
def stop_propagation(self):

View File

@ -1,8 +1,7 @@
import asyncio
import inspect
import warnings
from typing_extensions import Literal
from typing import TYPE_CHECKING, Any, Callable, Optional, cast
from typing import TYPE_CHECKING, Any, Literal, Callable, Optional, cast
from contextlib import AsyncExitStack, contextmanager, asynccontextmanager
from pydantic.fields import Required, Undefined, ModelField

View File

@ -37,14 +37,14 @@ class Permission:
]
def __init__(self, *checkers: Union[T_PermissionChecker, Dependent[bool]]) -> None:
self.checkers: Set[Dependent[bool]] = set(
self.checkers: Set[Dependent[bool]] = {
checker
if isinstance(checker, Dependent)
else Dependent[bool].parse(
call=checker, allow_types=self.HANDLER_PARAM_TYPES
)
for checker in checkers
)
}
"""存储 `PermissionChecker`"""
async def __call__(

View File

@ -37,14 +37,14 @@ class Rule:
]
def __init__(self, *checkers: Union[T_RuleChecker, Dependent[bool]]) -> None:
self.checkers: Set[Dependent[bool]] = set(
self.checkers: Set[Dependent[bool]] = {
checker
if isinstance(checker, Dependent)
else Dependent[bool].parse(
call=checker, allow_types=self.HANDLER_PARAM_TYPES
)
for checker in checkers
)
}
"""存储 `RuleChecker`"""
async def __call__(

View File

@ -8,6 +8,7 @@ FrontMatter:
"""
import asyncio
import contextlib
from datetime import datetime
from contextlib import AsyncExitStack
from typing import TYPE_CHECKING, Any, Set, Dict, Type, Optional, Coroutine
@ -120,10 +121,8 @@ async def _check_matcher(
dependency_cache: Optional[T_DependencyCache] = None,
) -> None:
if Matcher.expire_time and datetime.now() > Matcher.expire_time:
try:
with contextlib.suppress(Exception):
matchers[priority].remove(Matcher)
except Exception:
pass
return
try:
@ -138,11 +137,8 @@ async def _check_matcher(
return
if Matcher.temp:
try:
with contextlib.suppress(Exception):
matchers[priority].remove(Matcher)
except Exception:
pass
await _run_matcher(Matcher, bot, event, state, stack, dependency_cache)
@ -157,24 +153,20 @@ async def _run_matcher(
logger.info(f"Event will be handled by {Matcher}")
matcher = Matcher()
coros = list(
map(
lambda x: run_coro_with_catch(
x(
matcher=matcher,
bot=bot,
event=event,
state=state,
stack=stack,
dependency_cache=dependency_cache,
),
(SkippedException,),
if coros := [
run_coro_with_catch(
proc(
matcher=matcher,
bot=bot,
event=event,
state=state,
stack=stack,
dependency_cache=dependency_cache,
),
_run_preprocessors,
(SkippedException,),
)
)
if coros:
for proc in _run_preprocessors
]:
try:
await asyncio.gather(*coros)
except IgnoredException:
@ -184,9 +176,9 @@ async def _run_matcher(
return
except Exception as e:
logger.opt(colors=True, exception=e).error(
"<r><bg #f8bbd0>Error when running RunPreProcessors. "
"Running cancelled!</bg #f8bbd0></r>"
"<r><bg #f8bbd0>Error when running RunPreProcessors. Running cancelled!</bg #f8bbd0></r>"
)
return
exception = None
@ -200,24 +192,21 @@ async def _run_matcher(
)
exception = e
coros = list(
map(
lambda x: run_coro_with_catch(
x(
matcher=matcher,
exception=exception,
bot=bot,
event=event,
state=matcher.state,
stack=stack,
dependency_cache=dependency_cache,
),
(SkippedException,),
if coros := [
run_coro_with_catch(
proc(
matcher=matcher,
exception=exception,
bot=bot,
event=event,
state=matcher.state,
stack=stack,
dependency_cache=dependency_cache,
),
_run_postprocessors,
(SkippedException,),
)
)
if coros:
for proc in _run_postprocessors
]:
try:
await asyncio.gather(*coros)
except Exception as e:
@ -256,22 +245,19 @@ async def handle_event(bot: "Bot", event: "Event") -> None:
dependency_cache: T_DependencyCache = {}
async with AsyncExitStack() as stack:
coros = list(
map(
lambda x: run_coro_with_catch(
x(
bot=bot,
event=event,
state=state,
stack=stack,
dependency_cache=dependency_cache,
),
(SkippedException,),
if coros := [
run_coro_with_catch(
proc(
bot=bot,
event=event,
state=state,
stack=stack,
dependency_cache=dependency_cache,
),
_event_preprocessors,
(SkippedException,),
)
)
if coros:
for proc in _event_preprocessors
]:
try:
if show_log:
logger.debug("Running PreProcessors...")
@ -324,22 +310,19 @@ async def handle_event(bot: "Bot", event: "Event") -> None:
"<r><bg #f8bbd0>Error when checking Matcher.</bg #f8bbd0></r>"
)
coros = list(
map(
lambda x: run_coro_with_catch(
x(
bot=bot,
event=event,
state=state,
stack=stack,
dependency_cache=dependency_cache,
),
(SkippedException,),
if coros := [
run_coro_with_catch(
proc(
bot=bot,
event=event,
state=state,
stack=stack,
dependency_cache=dependency_cache,
),
_event_postprocessors,
(SkippedException,),
)
)
if coros:
for proc in _event_postprocessors
]:
try:
if show_log:
logger.debug("Running PostProcessors...")

View File

@ -12,9 +12,8 @@ import re
import shlex
from itertools import product
from argparse import Namespace
from typing_extensions import TypedDict
from argparse import ArgumentParser as ArgParser
from typing import Any, List, Tuple, Union, Optional, Sequence, NamedTuple
from typing import Any, List, Tuple, Union, Optional, Sequence, TypedDict, NamedTuple
from pygtrie import CharTrie
@ -83,8 +82,7 @@ class TrieRule:
message_seg: MessageSegment = message[0]
if message_seg.is_text():
segment_text = str(message_seg).lstrip()
pf = cls.prefix.longest_prefix(segment_text)
if pf:
if pf := cls.prefix.longest_prefix(segment_text):
value: TRIE_VALUE = pf.value
prefix[RAW_CMD_KEY] = pf.key
prefix[CMD_START_KEY] = value.command_start

View File

@ -11,6 +11,7 @@ FrontMatter:
sidebar_position: 11
description: nonebot.typing 模块
"""
from typing import (
TYPE_CHECKING,
Any,
@ -28,6 +29,8 @@ if TYPE_CHECKING:
from nonebot.adapters import Bot
from nonebot.permission import Permission
T = TypeVar("T")
T_Wrapped = TypeVar("T_Wrapped", bound=Callable)
@ -41,10 +44,14 @@ def overrides(InterfaceClass: object) -> Callable[[T_Wrapped], T_Wrapped]:
return overrider
# state
T_State = Dict[Any, Any]
"""事件处理状态 State 类型"""
T_BotConnectionHook = Callable[..., Awaitable[Any]]
_DependentCallable = Union[Callable[..., T], Callable[..., Awaitable[T]]]
# driver hooks
T_BotConnectionHook = _DependentCallable[Any]
"""Bot 连接建立时钩子函数
依赖参数:
@ -53,7 +60,7 @@ T_BotConnectionHook = Callable[..., Awaitable[Any]]
- BotParam: Bot 对象
- DefaultParam: 带有默认值的参数
"""
T_BotDisconnectionHook = Callable[..., Awaitable[Any]]
T_BotDisconnectionHook = _DependentCallable[Any]
"""Bot 连接断开时钩子函数
依赖参数:
@ -62,6 +69,8 @@ T_BotDisconnectionHook = Callable[..., Awaitable[Any]]
- BotParam: Bot 对象
- DefaultParam: 带有默认值的参数
"""
# api hooks
T_CallingAPIHook = Callable[["Bot", str, Dict[str, Any]], Awaitable[Any]]
"""`bot.call_api` 钩子函数"""
T_CalledAPIHook = Callable[
@ -69,7 +78,8 @@ T_CalledAPIHook = Callable[
]
"""`bot.call_api` 后执行的函数,参数分别为 bot, exception, api, data, result"""
T_EventPreProcessor = Callable[..., Union[Any, Awaitable[Any]]]
# event hooks
T_EventPreProcessor = _DependentCallable[Any]
"""事件预处理函数 EventPreProcessor 类型
依赖参数:
@ -80,7 +90,7 @@ T_EventPreProcessor = Callable[..., Union[Any, Awaitable[Any]]]
- StateParam: State 对象
- DefaultParam: 带有默认值的参数
"""
T_EventPostProcessor = Callable[..., Union[Any, Awaitable[Any]]]
T_EventPostProcessor = _DependentCallable[Any]
"""事件预处理函数 EventPostProcessor 类型
依赖参数:
@ -91,7 +101,9 @@ T_EventPostProcessor = Callable[..., Union[Any, Awaitable[Any]]]
- StateParam: State 对象
- DefaultParam: 带有默认值的参数
"""
T_RunPreProcessor = Callable[..., Union[Any, Awaitable[Any]]]
# matcher run hooks
T_RunPreProcessor = _DependentCallable[Any]
"""事件响应器运行前预处理函数 RunPreProcessor 类型
依赖参数:
@ -103,7 +115,7 @@ T_RunPreProcessor = Callable[..., Union[Any, Awaitable[Any]]]
- MatcherParam: Matcher 对象
- DefaultParam: 带有默认值的参数
"""
T_RunPostProcessor = Callable[..., Union[Any, Awaitable[Any]]]
T_RunPostProcessor = _DependentCallable[Any]
"""事件响应器运行后后处理函数 RunPostProcessor 类型
依赖参数:
@ -117,7 +129,8 @@ T_RunPostProcessor = Callable[..., Union[Any, Awaitable[Any]]]
- DefaultParam: 带有默认值的参数
"""
T_RuleChecker = Callable[..., Union[bool, Awaitable[bool]]]
# rule, permission
T_RuleChecker = _DependentCallable[bool]
"""RuleChecker 即判断是否响应事件的处理函数。
依赖参数:
@ -128,7 +141,7 @@ T_RuleChecker = Callable[..., Union[bool, Awaitable[bool]]]
- StateParam: State 对象
- DefaultParam: 带有默认值的参数
"""
T_PermissionChecker = Callable[..., Union[bool, Awaitable[bool]]]
T_PermissionChecker = _DependentCallable[bool]
"""PermissionChecker 即判断事件是否满足权限的处理函数。
依赖参数:
@ -139,9 +152,9 @@ T_PermissionChecker = Callable[..., Union[bool, Awaitable[bool]]]
- DefaultParam: 带有默认值的参数
"""
T_Handler = Callable[..., Any]
T_Handler = _DependentCallable[Any]
"""Handler 处理函数。"""
T_TypeUpdater = Callable[..., Union[str, Awaitable[str]]]
T_TypeUpdater = _DependentCallable[str]
"""TypeUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新响应的事件类型。默认会更新为 `message`。
依赖参数:
@ -153,7 +166,7 @@ T_TypeUpdater = Callable[..., Union[str, Awaitable[str]]]
- MatcherParam: Matcher 对象
- DefaultParam: 带有默认值的参数
"""
T_PermissionUpdater = Callable[..., Union["Permission", Awaitable["Permission"]]]
T_PermissionUpdater = _DependentCallable["Permission"]
"""PermissionUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新会话对象权限。默认会更新为当前事件的触发对象。
依赖参数:
@ -165,5 +178,5 @@ T_PermissionUpdater = Callable[..., Union["Permission", Awaitable["Permission"]]
- MatcherParam: Matcher 对象
- DefaultParam: 带有默认值的参数
"""
T_DependencyCache = Dict[Callable[..., Any], "Task[Any]"]
T_DependencyCache = Dict[_DependentCallable[Any], "Task[Any]"]
"""依赖缓存, 用于存储依赖函数的返回值"""

View File

@ -24,6 +24,7 @@ from typing import (
Coroutine,
AsyncGenerator,
ContextManager,
overload,
)
from pydantic.typing import is_union, is_none_type
@ -129,11 +130,28 @@ async def run_sync_ctx_manager(
await run_sync(cm.__exit__)(None, None, None)
@overload
async def run_coro_with_catch(
coro: Coroutine[Any, Any, T],
exc: Tuple[Type[Exception], ...],
return_on_err: R = None,
) -> Union[T, None]:
...
@overload
async def run_coro_with_catch(
coro: Coroutine[Any, Any, T],
exc: Tuple[Type[Exception], ...],
return_on_err: R,
) -> Union[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]]:
try:
return await coro
except exc:
@ -173,7 +191,7 @@ def logger_wrapper(logger_name: str):
def log(level: str, message: str, exception: Optional[Exception] = None):
logger.opt(colors=True, exception=exception).log(
level, f"<m>{escape_tag(logger_name)}</m> | " + message
level, f"<m>{escape_tag(logger_name)}</m> | {message}"
)
return log

View File

@ -17,7 +17,7 @@ _✨ NoneBot 本地文档插件 ✨_
<a href="https://pypi.python.org/pypi/nonebot-plugin-docs">
<img src="https://img.shields.io/pypi/v/nonebot-plugin-docs.svg" alt="pypi">
</a>
<img src="https://img.shields.io/badge/python-3.7+-blue.svg" alt="python">
<img src="https://img.shields.io/badge/python-3.8+-blue.svg" alt="python">
</p>
## 使用方式

View File

@ -12,7 +12,7 @@ include = ["nonebot_plugin_docs/dist/**/*"]
[tool.poetry.dependencies]
python = "^3.7.3"
python = "^3.8"
nonebot2 = "^2.0.0-beta.1"
[tool.poetry.dev-dependencies]

169
poetry.lock generated
View File

@ -29,14 +29,12 @@ python-versions = ">=3.6"
aiodns = {version = "*", optional = true, markers = "extra == \"speedups\""}
aiosignal = ">=1.1.2"
async-timeout = ">=4.0.0a3,<5.0"
asynctest = {version = "0.13.0", markers = "python_version < \"3.8\""}
attrs = ">=17.3.0"
Brotli = {version = "*", optional = true, markers = "extra == \"speedups\""}
cchardet = {version = "*", optional = true, markers = "extra == \"speedups\""}
charset-normalizer = ">=2.0,<3.0"
frozenlist = ">=1.1.1"
multidict = ">=4.5,<7.0"
typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
yarl = ">=1.0,<2.0"
[package.extras]
@ -64,7 +62,6 @@ python-versions = ">=3.6.2"
[package.dependencies]
idna = ">=2.8"
sniffio = ">=1.1"
typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
[package.extras]
doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"]
@ -79,9 +76,6 @@ category = "dev"
optional = false
python-versions = ">=3.7"
[package.dependencies]
typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
[package.extras]
tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"]
@ -105,17 +99,6 @@ category = "main"
optional = true
python-versions = ">=3.6"
[package.dependencies]
typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""}
[[package]]
name = "asynctest"
version = "0.13.0"
description = "Enhance the standard unittest package with features for testing asyncio libraries"
category = "main"
optional = true
python-versions = ">=3.5"
[[package]]
name = "atomicwrites"
version = "1.4.1"
@ -152,7 +135,6 @@ mypy-extensions = ">=0.4.3"
pathspec = ">=0.9.0"
platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""}
typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
[package.extras]
@ -233,7 +215,6 @@ python-versions = ">=3.7"
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
[[package]]
name = "colorama"
@ -245,7 +226,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "coverage"
version = "6.4.2"
version = "6.4.3"
description = "Code coverage measurement for Python"
category = "dev"
optional = false
@ -296,15 +277,15 @@ test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.91
[[package]]
name = "filelock"
version = "3.7.1"
version = "3.8.0"
description = "A platform independent file lock."
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"]
testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"]
docs = ["furo (>=2022.6.21)", "sphinx (>=5.1.1)", "sphinx-autodoc-typehints (>=1.19.1)"]
testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pytest-cov (>=3)", "pytest-timeout (>=2.1)"]
[[package]]
name = "frozenlist"
@ -405,7 +386,6 @@ h11 = "*"
h2 = ">=3.1.0"
priority = "*"
toml = "*"
typing_extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
wsproto = ">=0.14.0"
[package.extras]
@ -440,23 +420,6 @@ category = "main"
optional = false
python-versions = ">=3.5"
[[package]]
name = "importlib-metadata"
version = "4.12.0"
description = "Read metadata from Python packages"
category = "main"
optional = false
python-versions = ">=3.7"
[package.dependencies]
typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
zipp = ">=0.5"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
perf = ["ipython"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"]
[[package]]
name = "iniconfig"
version = "1.1.1"
@ -651,9 +614,6 @@ category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
[package.extras]
dev = ["pre-commit", "tox"]
testing = ["pytest", "pytest-benchmark"]
@ -669,7 +629,6 @@ python-versions = ">=3.7"
[package.dependencies]
cfgv = ">=2.0.0"
identify = ">=1.0.0"
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
nodeenv = ">=0.11.1"
pyyaml = ">=5.1"
toml = "*"
@ -704,7 +663,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "pycares"
version = "4.2.1"
version = "4.2.2"
description = "Python interface for c-ares"
category = "main"
optional = true
@ -771,7 +730,6 @@ python-versions = ">=3.7"
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
attrs = ">=19.2.0"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
iniconfig = "*"
packaging = "*"
pluggy = ">=0.12,<2.0"
@ -791,7 +749,6 @@ python-versions = ">=3.7"
[package.dependencies]
pytest = ">=6.1.0"
typing-extensions = {version = ">=3.7.2", markers = "python_version < \"3.8\""}
[package.extras]
testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)", "flaky (>=3.5.0)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"]
@ -873,12 +830,10 @@ aiofiles = "*"
blinker = "*"
click = "*"
hypercorn = ">=0.11.2"
importlib_metadata = {version = "*", markers = "python_version < \"3.8\""}
itsdangerous = "*"
jinja2 = "*"
markupsafe = "*"
toml = "*"
typing_extensions = {version = "*", markers = "python_version < \"3.8\""}
werkzeug = ">=2.0.0"
[package.extras]
@ -965,20 +920,12 @@ python-versions = ">=3.7"
[[package]]
name = "tomlkit"
version = "0.11.1"
version = "0.11.3"
description = "Style preserving TOML library"
category = "main"
optional = false
python-versions = ">=3.6,<4.0"
[[package]]
name = "typed-ast"
version = "1.5.4"
description = "a fork of Python 2 and 3 ast modules with type comment support"
category = "dev"
optional = false
python-versions = ">=3.6"
[[package]]
name = "typing-extensions"
version = "4.3.0"
@ -1015,7 +962,6 @@ h11 = ">=0.8"
httptools = {version = ">=0.4.0", optional = true, markers = "extra == \"standard\""}
python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""}
PyYAML = {version = ">=5.1", optional = true, markers = "extra == \"standard\""}
typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""}
watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""}
websockets = {version = ">=10.0", optional = true, markers = "extra == \"standard\""}
@ -1038,21 +984,20 @@ test = ["aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<
[[package]]
name = "virtualenv"
version = "20.16.2"
version = "20.16.3"
description = "Virtual Python Environment builder"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
distlib = ">=0.3.1,<1"
filelock = ">=3.2,<4"
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
platformdirs = ">=2,<3"
distlib = ">=0.3.5,<1"
filelock = ">=3.4.1,<4"
platformdirs = ">=2.4,<3"
[package.extras]
docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"]
testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "packaging (>=20.0)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)"]
docs = ["proselint (>=0.13)", "sphinx (>=5.1.1)", "sphinx-argparse (>=0.3.1)", "sphinx-rtd-theme (>=1)", "towncrier (>=21.9)"]
testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"]
[[package]]
name = "watchfiles"
@ -1083,7 +1028,7 @@ python-versions = ">=3.7"
[[package]]
name = "werkzeug"
version = "2.2.1"
version = "2.2.2"
description = "The comprehensive WSGI web application library."
category = "main"
optional = true
@ -1128,19 +1073,6 @@ python-versions = ">=3.7"
[package.dependencies]
idna = ">=2.0"
multidict = ">=4.0"
typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
[[package]]
name = "zipp"
version = "3.8.1"
description = "Backport of pathlib-compatible object wrapper for zip files"
category = "main"
optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]
[extras]
aiohttp = ["aiohttp"]
@ -1151,8 +1083,8 @@ websockets = ["websockets"]
[metadata]
lock-version = "1.1"
python-versions = "^3.7.3"
content-hash = "8775c8091ff054a3fb807281e0cfebde4a0409d18970a1001a7a06fad595addf"
python-versions = "^3.8"
content-hash = "3b21339de9113224b61700da359ea53ef866677d19c0bdbad7126e33ceceb856"
[metadata.files]
aiodns = [
@ -1256,10 +1188,6 @@ async-timeout = [
{file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
{file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
]
asynctest = [
{file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"},
{file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"},
]
atomicwrites = []
attrs = [
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
@ -1455,10 +1383,7 @@ execnet = [
{file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"},
]
fastapi = []
filelock = [
{file = "filelock-3.7.1-py3-none-any.whl", hash = "sha256:37def7b658813cda163b56fc564cdc75e86d338246458c4c28ae84cabefa2404"},
{file = "filelock-3.7.1.tar.gz", hash = "sha256:3a0fd85166ad9dbab54c9aec96737b744106dc5f15c0b09a6744a445299fcf04"},
]
filelock = []
frozenlist = []
h11 = [
{file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"},
@ -1529,7 +1454,6 @@ idna = [
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
]
importlib-metadata = []
iniconfig = [
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
@ -1694,39 +1618,7 @@ py = [
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
]
pycares = [
{file = "pycares-4.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d83f193563b42360528167705b1c7bb91e2a09f990b98e3d6378835b72cd5c96"},
{file = "pycares-4.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b03f69df69f0ab3bfb8dbe54444afddff6ff9389561a08aade96b4f91207a655"},
{file = "pycares-4.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3b78bdee2f2f1351d5fccc2d1b667aea2d15a55d74d52cb9fd5bea8b5e74c4dc"},
{file = "pycares-4.2.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f05223de13467bb26f9a1594a1799ce2d08ad8ea241489fecd9d8ed3bbbfc672"},
{file = "pycares-4.2.1-cp310-cp310-win32.whl", hash = "sha256:1f37f762414680063b4dfec5be809a84f74cd8e203d939aaf3ba9c807a9e7013"},
{file = "pycares-4.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:1a9506d496efeb809a1b63647cb2f3f33c67fcf62bf80a2359af692fef2c1755"},
{file = "pycares-4.2.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2fd53eb5b441c4f6f9c78d7900e05883e9998b34a14b804be4fc4c6f9fea89f3"},
{file = "pycares-4.2.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:061dd4c80fec73feb150455b159704cd51a122f20d36790033bd6375d4198579"},
{file = "pycares-4.2.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a521d7f54f3e52ded4d34c306ba05cfe9eb5aaa2e5aaf83c96564b9369495588"},
{file = "pycares-4.2.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:99e00e397d07a79c9f43e4303e67f4f97bcabd013bda0d8f2d430509b7aef8a0"},
{file = "pycares-4.2.1-cp36-cp36m-win32.whl", hash = "sha256:d9cd826d8e0c270059450709bff994bfeb072f79d82fd3f11c701690ff65d0e7"},
{file = "pycares-4.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f8e6942965465ca98e212376c4afb9aec501d8129054929744b2f4a487c8c14b"},
{file = "pycares-4.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e75cbd4d3b3d9b02bba6e170846e39893a825e7a5fb1b96728fc6d7b964f8945"},
{file = "pycares-4.2.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2e8ec4c8e07c986b70a3cc8f5b297c53b08ac755e5b9797512002a466e2de86"},
{file = "pycares-4.2.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5333b51ef4ff3e8973b4a1b57cad5ada13e15552445ee3cd74bd77407dec9d44"},
{file = "pycares-4.2.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2113529004df4894783eaa61e9abc3a680756b6f033d942f2800301ae8c71c29"},
{file = "pycares-4.2.1-cp37-cp37m-win32.whl", hash = "sha256:e7a95763cdc20cf9ec357066e656ea30b8de6b03de6175cbb50890e22aa01868"},
{file = "pycares-4.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7a901776163a04de5d67c42bd63a287cff9cb05fc041668ad1681fe3daa36445"},
{file = "pycares-4.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:66b5390a4885a578e687d3f2683689c35e1d4573f4d0ecf217431f7bb55c49a0"},
{file = "pycares-4.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15dd5cf21bc73ad539e8aabf7afe370d1df8af7bc6944cd7298f3bfef0c1a27c"},
{file = "pycares-4.2.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4ee625d7571039038bca51ae049b047cbfcfc024b302aae6cc53d5d9aa8648a8"},
{file = "pycares-4.2.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:396ee487178e9de06ca4122a35a157474db3ce0a0db6038a31c831ebb9863315"},
{file = "pycares-4.2.1-cp38-cp38-win32.whl", hash = "sha256:e4dc37f732f7110ca6368e0128cbbd0a54f5211515a061b2add64da2ddb8e5ca"},
{file = "pycares-4.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:3636fccf643c5192c34ee0183c514a2d09419e3a76ca2717cef626638027cb21"},
{file = "pycares-4.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6724573e830ea2345f4bcf0f968af64cc6d491dc2133e9c617f603445dcdfa58"},
{file = "pycares-4.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9dbfcacbde6c21380c412c13d53ea44b257dea3f7b9d80be2c873bb20e21fee"},
{file = "pycares-4.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c8a46839da642b281ac5f56d3c6336528e128b3c41eab9c5330d250f22325e9d"},
{file = "pycares-4.2.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9b05c2cec644a6c66b55bcf6c24d4dfdaf2f7205b16e5c4ceee31db104fac958"},
{file = "pycares-4.2.1-cp39-cp39-win32.whl", hash = "sha256:8bd6ed3ad3a5358a635c1acf5d0f46be9afb095772b84427ff22283d2f31db1b"},
{file = "pycares-4.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:fbd53728d798d07811898e11991e22209229c090eab265a53d12270b95d70d1a"},
{file = "pycares-4.2.1.tar.gz", hash = "sha256:735b4f75fd0f595c4e9184da18cd87737f46bc81a64ea41f4edce2b6b68d46d2"},
]
pycares = []
pycparser = [
{file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
@ -1862,32 +1754,6 @@ tomli = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
tomlkit = []
typed-ast = [
{file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"},
{file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"},
{file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"},
{file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"},
{file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"},
{file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"},
{file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"},
{file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"},
{file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"},
{file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"},
{file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"},
{file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"},
{file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"},
{file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"},
{file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"},
{file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"},
{file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"},
{file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"},
{file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"},
{file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"},
{file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"},
{file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"},
{file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"},
{file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"},
]
typing-extensions = [
{file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"},
{file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"},
@ -1978,4 +1844,3 @@ wsproto = [
{file = "wsproto-1.1.0.tar.gz", hash = "sha256:a2e56bfd5c7cd83c1369d83b5feccd6d37798b74872866e62616e0ecf111bda8"},
]
yarl = []
zipp = []

View File

@ -22,7 +22,7 @@ packages = [
include = ["nonebot/py.typed"]
[tool.poetry.dependencies]
python = "^3.7.3"
python = "^3.8"
yarl = "^1.7.2"
loguru = "^0.6.0"
pygtrie = "^2.4.1"

View File

@ -78,3 +78,27 @@ async def test_reverse_driver(app: App):
assert await ws.receive_bytes() == b"pong"
await ws.close()
@pytest.mark.asyncio
@pytest.mark.parametrize(
"nonebug_init, driver_type",
[
pytest.param(
{"driver": "nonebot.drivers.fastapi:Driver+nonebot.drivers.aiohttp:Mixin"},
"fastapi+aiohttp",
id="fastapi+aiohttp",
),
pytest.param(
{"driver": "~httpx:Driver+~websockets"},
"block_driver+httpx+websockets",
id="httpx+websockets",
),
],
indirect=["nonebug_init"],
)
async def test_combine_driver(app: App, driver_type: str):
import nonebot
driver = nonebot.get_driver()
assert driver.type == driver_type

View File

@ -8,7 +8,7 @@ slug: /
NoneBot2 是一个现代、跨平台、可扩展的 Python 聊天机器人框架,它基于 Python 的类型注解和异步特性,能够为你的需求实现提供便捷灵活的支持。
需要注意的是NoneBot2 仅支持 **Python 3.7.3 以上版本**
需要注意的是NoneBot2 仅支持 **Python 3.8 以上版本**
## 特色

View File

@ -13,7 +13,7 @@ import Asciinema from "@site/src/components/Asciinema";
# 安装 NoneBot2
:::warning 注意
请确保你的 Python 版本 >= 3.7.3
请确保你的 Python 版本 >= 3.8
:::
:::warning 注意