💥 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: python-version:
description: Python version description: Python version
required: false required: false
default: "3.9" default: "3.10"
runs: runs:
using: "composite" using: "composite"

View File

@ -15,7 +15,7 @@ jobs:
cancel-in-progress: true cancel-in-progress: true
strategy: strategy:
matrix: 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] os: [ubuntu-latest, windows-latest, macos-latest]
fail-fast: false fail-fast: false
env: env:

View File

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

View File

@ -171,8 +171,7 @@ def get_bots() -> Dict[str, Bot]:
bots = nonebot.get_bots() bots = nonebot.get_bots()
``` ```
""" """
driver = get_driver() return get_driver().bots
return driver.bots
def _resolve_dot_notation( 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()))}" 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) _driver = DriverClass(env, config)

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
import signal import signal
import asyncio import asyncio
import threading import threading
from typing import Set, Union, Callable, Awaitable from typing import Set, Union, Callable, Awaitable, cast
from nonebot.log import logger from nonebot.log import logger
from nonebot.drivers import Driver from nonebot.drivers import Driver
@ -9,8 +9,7 @@ from nonebot.typing import overrides
from nonebot.config import Env, Config from nonebot.config import Env, Config
from nonebot.utils import run_sync, is_coroutine_callable from nonebot.utils import run_sync, is_coroutine_callable
STARTUP_FUNC = Callable[[], Union[None, Awaitable[None]]] HOOK_FUNC = Union[Callable[[], None], Callable[[], Awaitable[None]]]
SHUTDOWN_FUNC = Callable[[], Union[None, Awaitable[None]]]
HANDLED_SIGNALS = ( HANDLED_SIGNALS = (
signal.SIGINT, # Unix signal 2. Sent by Ctrl+C. signal.SIGINT, # Unix signal 2. Sent by Ctrl+C.
signal.SIGTERM, # Unix signal 15. Sent by `kill <pid>`. signal.SIGTERM, # Unix signal 15. Sent by `kill <pid>`.
@ -20,8 +19,8 @@ HANDLED_SIGNALS = (
class BlockDriver(Driver): class BlockDriver(Driver):
def __init__(self, env: Env, config: Config): def __init__(self, env: Env, config: Config):
super().__init__(env, config) super().__init__(env, config)
self.startup_funcs: Set[STARTUP_FUNC] = set() self.startup_funcs: Set[HOOK_FUNC] = set()
self.shutdown_funcs: Set[SHUTDOWN_FUNC] = set() self.shutdown_funcs: Set[HOOK_FUNC] = set()
self.should_exit: asyncio.Event = asyncio.Event() self.should_exit: asyncio.Event = asyncio.Event()
self.force_exit: bool = False self.force_exit: bool = False
@ -38,7 +37,7 @@ class BlockDriver(Driver):
return logger return logger
@overrides(Driver) @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 return func
@overrides(Driver) @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): async def startup(self):
# run startup # run startup
cors = [ 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 for startup in self.startup_funcs
] ]
if cors: if cors:
@ -94,7 +95,9 @@ class BlockDriver(Driver):
logger.info("Waiting for application shutdown.") logger.info("Waiting for application shutdown.")
# run shutdown # run shutdown
cors = [ 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 for shutdown in self.shutdown_funcs
] ]
if cors: if cors:

View File

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

View File

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

View File

@ -233,13 +233,11 @@ def combine_driver(driver: Type[Driver], *mixins: Type[ForwardMixin]) -> Type[Dr
if not mixins: if not mixins:
return driver return driver
class CombinedDriver(*mixins, driver, ForwardDriver): # type: ignore def type_(self: ForwardDriver) -> str:
@property
def type(self) -> str:
return ( return (
driver.type.__get__(self) driver.type.__get__(self)
+ "+" + "+"
+ "+".join(map(lambda x: x.type.__get__(self), mixins)) + "+".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, Callable,
NoReturn, NoReturn,
Optional, Optional,
overload,
) )
from nonebot.log import logger from nonebot.log import logger
@ -551,7 +552,17 @@ class Matcher(metaclass=MatcherMeta):
""" """
raise SkippedException 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` 事件 """获取一个 `receive` 事件
如果没有找到对应的事件返回 `default` 如果没有找到对应的事件返回 `default`
@ -563,14 +574,34 @@ class Matcher(metaclass=MatcherMeta):
self.state[RECEIVE_KEY.format(id=id)] = event self.state[RECEIVE_KEY.format(id=id)] = event
self.state[LAST_RECEIVE_KEY] = 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` 事件 """获取最近一次 `receive` 事件
如果没有事件返回 `default` 如果没有事件返回 `default`
""" """
return self.state.get(LAST_RECEIVE_KEY, 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` 消息 """获取一个 `got` 消息
如果没有找到对应的消息返回 `default` 如果没有找到对应的消息返回 `default`
@ -587,7 +618,15 @@ class Matcher(metaclass=MatcherMeta):
else: else:
self.state[REJECT_TARGET] = target 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) return self.state.get(REJECT_TARGET, default)
def stop_propagation(self): def stop_propagation(self):

View File

@ -1,8 +1,7 @@
import asyncio import asyncio
import inspect import inspect
import warnings import warnings
from typing_extensions import Literal from typing import TYPE_CHECKING, Any, Literal, Callable, Optional, cast
from typing import TYPE_CHECKING, Any, Callable, Optional, cast
from contextlib import AsyncExitStack, contextmanager, asynccontextmanager from contextlib import AsyncExitStack, contextmanager, asynccontextmanager
from pydantic.fields import Required, Undefined, ModelField 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: def __init__(self, *checkers: Union[T_PermissionChecker, Dependent[bool]]) -> None:
self.checkers: Set[Dependent[bool]] = set( self.checkers: Set[Dependent[bool]] = {
checker checker
if isinstance(checker, Dependent) if isinstance(checker, Dependent)
else Dependent[bool].parse( else Dependent[bool].parse(
call=checker, allow_types=self.HANDLER_PARAM_TYPES call=checker, allow_types=self.HANDLER_PARAM_TYPES
) )
for checker in checkers for checker in checkers
) }
"""存储 `PermissionChecker`""" """存储 `PermissionChecker`"""
async def __call__( async def __call__(

View File

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

View File

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

View File

@ -12,9 +12,8 @@ import re
import shlex import shlex
from itertools import product from itertools import product
from argparse import Namespace from argparse import Namespace
from typing_extensions import TypedDict
from argparse import ArgumentParser as ArgParser 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 from pygtrie import CharTrie
@ -83,8 +82,7 @@ class TrieRule:
message_seg: MessageSegment = message[0] message_seg: MessageSegment = message[0]
if message_seg.is_text(): if message_seg.is_text():
segment_text = str(message_seg).lstrip() segment_text = str(message_seg).lstrip()
pf = cls.prefix.longest_prefix(segment_text) if pf := cls.prefix.longest_prefix(segment_text):
if pf:
value: TRIE_VALUE = pf.value value: TRIE_VALUE = pf.value
prefix[RAW_CMD_KEY] = pf.key prefix[RAW_CMD_KEY] = pf.key
prefix[CMD_START_KEY] = value.command_start prefix[CMD_START_KEY] = value.command_start

View File

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

View File

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

View File

@ -12,7 +12,7 @@ include = ["nonebot_plugin_docs/dist/**/*"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.7.3" python = "^3.8"
nonebot2 = "^2.0.0-beta.1" nonebot2 = "^2.0.0-beta.1"
[tool.poetry.dev-dependencies] [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\""} aiodns = {version = "*", optional = true, markers = "extra == \"speedups\""}
aiosignal = ">=1.1.2" aiosignal = ">=1.1.2"
async-timeout = ">=4.0.0a3,<5.0" async-timeout = ">=4.0.0a3,<5.0"
asynctest = {version = "0.13.0", markers = "python_version < \"3.8\""}
attrs = ">=17.3.0" attrs = ">=17.3.0"
Brotli = {version = "*", optional = true, markers = "extra == \"speedups\""} Brotli = {version = "*", optional = true, markers = "extra == \"speedups\""}
cchardet = {version = "*", optional = true, markers = "extra == \"speedups\""} cchardet = {version = "*", optional = true, markers = "extra == \"speedups\""}
charset-normalizer = ">=2.0,<3.0" charset-normalizer = ">=2.0,<3.0"
frozenlist = ">=1.1.1" frozenlist = ">=1.1.1"
multidict = ">=4.5,<7.0" multidict = ">=4.5,<7.0"
typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
yarl = ">=1.0,<2.0" yarl = ">=1.0,<2.0"
[package.extras] [package.extras]
@ -64,7 +62,6 @@ python-versions = ">=3.6.2"
[package.dependencies] [package.dependencies]
idna = ">=2.8" idna = ">=2.8"
sniffio = ">=1.1" sniffio = ">=1.1"
typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
[package.extras] [package.extras]
doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"]
@ -79,9 +76,6 @@ category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
[package.dependencies]
typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
[package.extras] [package.extras]
tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"]
@ -105,17 +99,6 @@ category = "main"
optional = true optional = true
python-versions = ">=3.6" 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]] [[package]]
name = "atomicwrites" name = "atomicwrites"
version = "1.4.1" version = "1.4.1"
@ -152,7 +135,6 @@ mypy-extensions = ">=0.4.3"
pathspec = ">=0.9.0" pathspec = ">=0.9.0"
platformdirs = ">=2" platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} 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\""} typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
[package.extras] [package.extras]
@ -233,7 +215,6 @@ python-versions = ">=3.7"
[package.dependencies] [package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""} colorama = {version = "*", markers = "platform_system == \"Windows\""}
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
[[package]] [[package]]
name = "colorama" name = "colorama"
@ -245,7 +226,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]] [[package]]
name = "coverage" name = "coverage"
version = "6.4.2" version = "6.4.3"
description = "Code coverage measurement for Python" description = "Code coverage measurement for Python"
category = "dev" category = "dev"
optional = false 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]] [[package]]
name = "filelock" name = "filelock"
version = "3.7.1" version = "3.8.0"
description = "A platform independent file lock." description = "A platform independent file lock."
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
[package.extras] [package.extras]
docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] docs = ["furo (>=2022.6.21)", "sphinx (>=5.1.1)", "sphinx-autodoc-typehints (>=1.19.1)"]
testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pytest-cov (>=3)", "pytest-timeout (>=2.1)"]
[[package]] [[package]]
name = "frozenlist" name = "frozenlist"
@ -405,7 +386,6 @@ h11 = "*"
h2 = ">=3.1.0" h2 = ">=3.1.0"
priority = "*" priority = "*"
toml = "*" toml = "*"
typing_extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
wsproto = ">=0.14.0" wsproto = ">=0.14.0"
[package.extras] [package.extras]
@ -440,23 +420,6 @@ category = "main"
optional = false optional = false
python-versions = ">=3.5" 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]] [[package]]
name = "iniconfig" name = "iniconfig"
version = "1.1.1" version = "1.1.1"
@ -651,9 +614,6 @@ category = "dev"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
[package.dependencies]
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
[package.extras] [package.extras]
dev = ["pre-commit", "tox"] dev = ["pre-commit", "tox"]
testing = ["pytest", "pytest-benchmark"] testing = ["pytest", "pytest-benchmark"]
@ -669,7 +629,6 @@ python-versions = ">=3.7"
[package.dependencies] [package.dependencies]
cfgv = ">=2.0.0" cfgv = ">=2.0.0"
identify = ">=1.0.0" identify = ">=1.0.0"
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
nodeenv = ">=0.11.1" nodeenv = ">=0.11.1"
pyyaml = ">=5.1" pyyaml = ">=5.1"
toml = "*" toml = "*"
@ -704,7 +663,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]] [[package]]
name = "pycares" name = "pycares"
version = "4.2.1" version = "4.2.2"
description = "Python interface for c-ares" description = "Python interface for c-ares"
category = "main" category = "main"
optional = true optional = true
@ -771,7 +730,6 @@ python-versions = ">=3.7"
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
attrs = ">=19.2.0" attrs = ">=19.2.0"
colorama = {version = "*", markers = "sys_platform == \"win32\""} colorama = {version = "*", markers = "sys_platform == \"win32\""}
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
iniconfig = "*" iniconfig = "*"
packaging = "*" packaging = "*"
pluggy = ">=0.12,<2.0" pluggy = ">=0.12,<2.0"
@ -791,7 +749,6 @@ python-versions = ">=3.7"
[package.dependencies] [package.dependencies]
pytest = ">=6.1.0" pytest = ">=6.1.0"
typing-extensions = {version = ">=3.7.2", markers = "python_version < \"3.8\""}
[package.extras] [package.extras]
testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)", "flaky (>=3.5.0)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] 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 = "*" blinker = "*"
click = "*" click = "*"
hypercorn = ">=0.11.2" hypercorn = ">=0.11.2"
importlib_metadata = {version = "*", markers = "python_version < \"3.8\""}
itsdangerous = "*" itsdangerous = "*"
jinja2 = "*" jinja2 = "*"
markupsafe = "*" markupsafe = "*"
toml = "*" toml = "*"
typing_extensions = {version = "*", markers = "python_version < \"3.8\""}
werkzeug = ">=2.0.0" werkzeug = ">=2.0.0"
[package.extras] [package.extras]
@ -965,20 +920,12 @@ python-versions = ">=3.7"
[[package]] [[package]]
name = "tomlkit" name = "tomlkit"
version = "0.11.1" version = "0.11.3"
description = "Style preserving TOML library" description = "Style preserving TOML library"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.6,<4.0" 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]] [[package]]
name = "typing-extensions" name = "typing-extensions"
version = "4.3.0" version = "4.3.0"
@ -1015,7 +962,6 @@ h11 = ">=0.8"
httptools = {version = ">=0.4.0", optional = true, markers = "extra == \"standard\""} httptools = {version = ">=0.4.0", optional = true, markers = "extra == \"standard\""}
python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""}
PyYAML = {version = ">=5.1", 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\""} 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\""} watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""}
websockets = {version = ">=10.0", 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]] [[package]]
name = "virtualenv" name = "virtualenv"
version = "20.16.2" version = "20.16.3"
description = "Virtual Python Environment builder" description = "Virtual Python Environment builder"
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
[package.dependencies] [package.dependencies]
distlib = ">=0.3.1,<1" distlib = ">=0.3.5,<1"
filelock = ">=3.2,<4" filelock = ">=3.4.1,<4"
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} platformdirs = ">=2.4,<3"
platformdirs = ">=2,<3"
[package.extras] [package.extras]
docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"] docs = ["proselint (>=0.13)", "sphinx (>=5.1.1)", "sphinx-argparse (>=0.3.1)", "sphinx-rtd-theme (>=1)", "towncrier (>=21.9)"]
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)"] 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]] [[package]]
name = "watchfiles" name = "watchfiles"
@ -1083,7 +1028,7 @@ python-versions = ">=3.7"
[[package]] [[package]]
name = "werkzeug" name = "werkzeug"
version = "2.2.1" version = "2.2.2"
description = "The comprehensive WSGI web application library." description = "The comprehensive WSGI web application library."
category = "main" category = "main"
optional = true optional = true
@ -1128,19 +1073,6 @@ python-versions = ">=3.7"
[package.dependencies] [package.dependencies]
idna = ">=2.0" idna = ">=2.0"
multidict = ">=4.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] [extras]
aiohttp = ["aiohttp"] aiohttp = ["aiohttp"]
@ -1151,8 +1083,8 @@ websockets = ["websockets"]
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.7.3" python-versions = "^3.8"
content-hash = "8775c8091ff054a3fb807281e0cfebde4a0409d18970a1001a7a06fad595addf" content-hash = "3b21339de9113224b61700da359ea53ef866677d19c0bdbad7126e33ceceb856"
[metadata.files] [metadata.files]
aiodns = [ aiodns = [
@ -1256,10 +1188,6 @@ async-timeout = [
{file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
{file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, {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 = [] atomicwrites = []
attrs = [ attrs = [
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, {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"}, {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"},
] ]
fastapi = [] fastapi = []
filelock = [ filelock = []
{file = "filelock-3.7.1-py3-none-any.whl", hash = "sha256:37def7b658813cda163b56fc564cdc75e86d338246458c4c28ae84cabefa2404"},
{file = "filelock-3.7.1.tar.gz", hash = "sha256:3a0fd85166ad9dbab54c9aec96737b744106dc5f15c0b09a6744a445299fcf04"},
]
frozenlist = [] frozenlist = []
h11 = [ h11 = [
{file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, {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-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
] ]
importlib-metadata = []
iniconfig = [ iniconfig = [
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, {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-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
] ]
pycares = [ 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"},
]
pycparser = [ pycparser = [
{file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
@ -1862,32 +1754,6 @@ tomli = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
] ]
tomlkit = [] 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 = [ typing-extensions = [
{file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"},
{file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, {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"}, {file = "wsproto-1.1.0.tar.gz", hash = "sha256:a2e56bfd5c7cd83c1369d83b5feccd6d37798b74872866e62616e0ecf111bda8"},
] ]
yarl = [] yarl = []
zipp = []

View File

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

View File

@ -78,3 +78,27 @@ async def test_reverse_driver(app: App):
assert await ws.receive_bytes() == b"pong" assert await ws.receive_bytes() == b"pong"
await ws.close() 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 聊天机器人框架,它基于 Python 的类型注解和异步特性,能够为你的需求实现提供便捷灵活的支持。
需要注意的是NoneBot2 仅支持 **Python 3.7.3 以上版本** 需要注意的是NoneBot2 仅支持 **Python 3.8 以上版本**
## 特色 ## 特色

View File

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