🚧 process handler call

This commit is contained in:
yanyongyu 2021-11-13 19:38:01 +08:00
parent f7eadb48b5
commit 9d708a6723
15 changed files with 270 additions and 107 deletions

View File

@ -12,7 +12,7 @@ from typing import TYPE_CHECKING, Set, Type, Optional
from nonebot.log import logger from nonebot.log import logger
from nonebot.rule import TrieRule from nonebot.rule import TrieRule
from nonebot.utils import escape_tag from nonebot.utils import escape_tag
from nonebot.matcher import Matcher, matchers from nonebot.processor import Matcher, matchers
from nonebot.exception import NoLogException, StopPropagation, IgnoredException from nonebot.exception import NoLogException, StopPropagation, IgnoredException
from nonebot.typing import (T_State, T_RunPreProcessor, T_RunPostProcessor, from nonebot.typing import (T_State, T_RunPreProcessor, T_RunPostProcessor,
T_EventPreProcessor, T_EventPostProcessor) T_EventPreProcessor, T_EventPostProcessor)

View File

@ -5,10 +5,9 @@ from types import ModuleType
from typing import (TYPE_CHECKING, Any, Set, Dict, List, Type, Tuple, Union, from typing import (TYPE_CHECKING, Any, Set, Dict, List, Type, Tuple, Union,
Optional) Optional)
from nonebot.handler import Handler
from nonebot.matcher import Matcher
from .manager import _current_plugin from .manager import _current_plugin
from nonebot.permission import Permission from nonebot.permission import Permission
from nonebot.processor import Handler, Matcher
from nonebot.typing import T_State, T_Handler, T_RuleChecker, T_StateFactory from nonebot.typing import T_State, T_Handler, T_RuleChecker, T_StateFactory
from nonebot.rule import (Rule, ArgumentParser, regex, command, keyword, from nonebot.rule import (Rule, ArgumentParser, regex, command, keyword,
endswith, startswith, shell_command) endswith, startswith, shell_command)

View File

@ -1,10 +1,9 @@
import re import re
from typing import Set, List, Type, Tuple, Union, Optional from typing import Set, List, Type, Tuple, Union, Optional
from nonebot.handler import Handler
from nonebot.matcher import Matcher
from nonebot.permission import Permission from nonebot.permission import Permission
from nonebot.rule import Rule, ArgumentParser from nonebot.rule import Rule, ArgumentParser
from nonebot.processor import Handler, Matcher
from nonebot.typing import T_State, T_Handler, T_RuleChecker, T_StateFactory from nonebot.typing import T_State, T_Handler, T_RuleChecker, T_StateFactory

View File

@ -3,7 +3,7 @@ from dataclasses import field, dataclass
from typing import Set, Dict, Type, Optional from typing import Set, Dict, Type, Optional
from .export import Export from .export import Export
from nonebot.matcher import Matcher from nonebot.processor import Matcher
plugins: Dict[str, "Plugin"] = {} plugins: Dict[str, "Plugin"] = {}
""" """

View File

@ -1,7 +1,7 @@
from typing import Dict, Optional from typing import Dict, Optional
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.matcher import Matcher from nonebot.processor import Matcher
from nonebot.adapters import Bot, Event from nonebot.adapters import Bot, Event
from nonebot.message import (IgnoredException, run_preprocessor, from nonebot.message import (IgnoredException, run_preprocessor,
run_postprocessor) run_postprocessor)

View File

@ -1,14 +1,18 @@
import inspect import inspect
from typing import Any, Callable, Optional from itertools import chain
from typing import Any, Dict, List, Tuple, Callable, Optional, cast
from .models import Dependent from .models import Dependent
from .models import Depends as Depends from nonebot.typing import T_State
from nonebot.adapters import Bot, Event from nonebot.adapters import Bot, Event
from .utils import get_typed_signature, generic_check_issubclass from .models import Depends as DependsClass
from nonebot.utils import run_sync, is_coroutine_callable
from .utils import (generic_get_types, get_typed_signature,
generic_check_issubclass)
def get_param_sub_dependent(*, param: inspect.Parameter) -> Dependent: def get_param_sub_dependent(*, param: inspect.Parameter) -> Dependent:
depends: Depends = param.default depends: DependsClass = param.default
if depends.dependency: if depends.dependency:
dependency = depends.dependency dependency = depends.dependency
else: else:
@ -20,7 +24,7 @@ def get_param_sub_dependent(*, param: inspect.Parameter) -> Dependent:
) )
def get_parameterless_sub_dependant(*, depends: Depends) -> Dependent: def get_parameterless_sub_dependant(*, depends: DependsClass) -> Dependent:
assert callable( assert callable(
depends.dependency depends.dependency
), "A parameter-less dependency must have a callable dependency" ), "A parameter-less dependency must have a callable dependency"
@ -29,7 +33,7 @@ def get_parameterless_sub_dependant(*, depends: Depends) -> Dependent:
def get_sub_dependant( def get_sub_dependant(
*, *,
depends: Depends, depends: DependsClass,
dependency: Callable[..., Any], dependency: Callable[..., Any],
name: Optional[str] = None, name: Optional[str] = None,
) -> Dependent: ) -> Dependent:
@ -49,29 +53,124 @@ def get_dependent(*,
params = signature.parameters params = signature.parameters
dependent = Dependent(func=func, name=name, use_cache=use_cache) dependent = Dependent(func=func, name=name, use_cache=use_cache)
for param_name, param in params.items(): for param_name, param in params.items():
if isinstance(param.default, Depends): if isinstance(param.default, DependsClass):
sub_dependent = get_param_sub_dependent(param=param) sub_dependent = get_param_sub_dependent(param=param)
dependent.dependencies.append(sub_dependent) dependent.dependencies.append(sub_dependent)
continue continue
if generic_check_issubclass(param.annotation, Bot): if generic_check_issubclass(param.annotation, Bot):
if dependent.bot_param_name is not None:
raise ValueError(f"{func} has more than one Bot parameter: "
f"{dependent.bot_param_name} / {param_name}")
dependent.bot_param_name = param_name dependent.bot_param_name = param_name
continue dependent.bot_param_type = generic_get_types(param.annotation)
elif generic_check_issubclass(param.annotation, Event): elif generic_check_issubclass(param.annotation, Event):
if dependent.event_param_name is not None:
raise ValueError(f"{func} has more than one Event parameter: "
f"{dependent.event_param_name} / {param_name}")
dependent.event_param_name = param_name dependent.event_param_name = param_name
continue dependent.event_param_type = generic_get_types(param.annotation)
elif generic_check_issubclass(param.annotation, dict): elif generic_check_issubclass(param.annotation, dict):
if dependent.state_param_name is not None:
raise ValueError(f"{func} has more than one State parameter: "
f"{dependent.state_param_name} / {param_name}")
dependent.state_param_name = param_name dependent.state_param_name = param_name
continue
elif generic_check_issubclass(param.annotation, Matcher): elif generic_check_issubclass(param.annotation, Matcher):
if dependent.matcher_param_name is not None:
raise ValueError(
f"{func} has more than one Matcher parameter: "
f"{dependent.matcher_param_name} / {param_name}")
dependent.matcher_param_name = param_name dependent.matcher_param_name = param_name
continue else:
raise ValueError(
raise ValueError( f"Unknown parameter {param_name} with type {param.annotation}")
f"Unknown parameter {param_name} with type {param.annotation}")
return dependent return dependent
async def solve_dependencies(
*,
dependent: Dependent,
bot: Bot,
event: Event,
state: T_State,
matcher: "Matcher",
sub_dependents: Optional[List[Dependent]] = None,
dependency_overrides_provider: Optional[Any] = None,
dependency_cache: Optional[Dict[Tuple[Callable[..., Any]], Any]] = None,
) -> Tuple[Dict[str, Any], Dict[Tuple[Callable[..., Any]], Any]]:
values: Dict[str, Any] = {}
dependency_cache = dependency_cache or {}
# solve sub dependencies
sub_dependant: Dependent
for sub_dependant in chain(sub_dependents or tuple(),
dependent.dependencies):
sub_dependant.func = cast(Callable[..., Any], sub_dependant.func)
sub_dependant.cache_key = cast(Tuple[Callable[..., Any]],
sub_dependant.cache_key)
func = sub_dependant.func
# dependency overrides
use_sub_dependant = sub_dependant
if (dependency_overrides_provider and
hasattr(dependency_overrides_provider, "dependency_overrides")):
original_call = sub_dependant.func
func = getattr(dependency_overrides_provider,
"dependency_overrides",
{}).get(original_call, original_call)
use_sub_dependant = get_dependent(
func=func,
name=sub_dependant.name,
)
# solve sub dependency with current cache
solved_result = await solve_dependencies(
dependent=use_sub_dependant,
bot=bot,
event=event,
state=state,
matcher=matcher,
dependency_overrides_provider=dependency_overrides_provider,
dependency_cache=dependency_cache,
)
sub_values, sub_dependency_cache = solved_result
# update cache?
dependency_cache.update(sub_dependency_cache)
# run dependency function
if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache:
solved = dependency_cache[sub_dependant.cache_key]
elif is_coroutine_callable(func):
solved = await func(**sub_values)
else:
solved = await run_sync(func)(**sub_values)
# parameter dependency
if sub_dependant.name is not None:
values[sub_dependant.name] = solved
# save current dependency to cache
if sub_dependant.cache_key not in dependency_cache:
dependency_cache[sub_dependant.cache_key] = solved
# usual dependency
if dependent.bot_param_name is not None:
values[dependent.bot_param_name] = bot
if dependent.event_param_name is not None:
values[dependent.event_param_name] = event
if dependent.state_param_name is not None:
values[dependent.state_param_name] = state
if dependent.matcher_param_name is not None:
values[dependent.matcher_param_name] = matcher
return values, dependency_cache
def Depends(dependency: Optional[Callable[..., Any]] = None,
*,
use_cache: bool = True) -> Any:
return DependsClass(dependency=dependency, use_cache=use_cache)
from .handler import Handler as Handler from .handler import Handler as Handler
from .matcher import Matcher as Matcher from .matcher import Matcher as Matcher
from .matcher import matchers as matchers

View File

@ -4,12 +4,14 @@
该模块实现事件处理函数的封装以实现动态参数等功能 该模块实现事件处理函数的封装以实现动态参数等功能
""" """
from typing import TYPE_CHECKING, List, Optional
from .models import Depends import asyncio
from nonebot.utils import get_name from typing import TYPE_CHECKING, Any, Dict, List, Tuple, Callable, Optional
from .models import Depends, Dependent
from nonebot.utils import get_name, run_sync
from nonebot.typing import T_State, T_Handler from nonebot.typing import T_State, T_Handler
from . import get_dependent, get_parameterless_sub_dependant from . import get_dependent, solve_dependencies, get_parameterless_sub_dependant
if TYPE_CHECKING: if TYPE_CHECKING:
from .matcher import Matcher from .matcher import Matcher
@ -23,7 +25,8 @@ class Handler:
func: T_Handler, func: T_Handler,
*, *,
name: Optional[str] = None, name: Optional[str] = None,
dependencies: Optional[List[Depends]] = None): dependencies: Optional[List[Depends]] = None,
dependency_overrides_provider: Optional[Any] = None):
"""装饰事件处理函数以便根据动态参数运行""" """装饰事件处理函数以便根据动态参数运行"""
self.func: T_Handler = func self.func: T_Handler = func
""" """
@ -33,11 +36,57 @@ class Handler:
self.name = get_name(func) if name is None else name self.name = get_name(func) if name is None else name
self.dependencies = dependencies or [] self.dependencies = dependencies or []
self.sub_dependents: Dict[Tuple[Callable[..., Any]], Dependent] = {}
if dependencies:
for depends in dependencies:
if not depends.dependency:
raise ValueError(f"{depends} has no dependency")
if (depends.dependency,) in self.sub_dependents:
raise ValueError(f"{depends} is already in dependencies")
sub_dependant = get_parameterless_sub_dependant(depends=depends)
self.sub_dependents[(depends.dependency,)] = sub_dependant
self.dependency_overrides_provider = dependency_overrides_provider
self.dependent = get_dependent(func=func) self.dependent = get_dependent(func=func)
for depends in self.dependencies[::-1]:
self.dependent.dependencies.insert(
0, get_parameterless_sub_dependant(depends=depends))
def __call__(self, bot: Bot, event: Event, state: T_State, async def __call__(self, matcher: "Matcher", bot: Bot, event: Event,
matcher: "Matcher"): state: T_State):
... values, _ = await solve_dependencies(
dependent=self.dependent,
bot=bot,
event=event,
state=state,
matcher=matcher,
sub_dependents=[
self.sub_dependents[(dependency.dependency,)] # type: ignore
for dependency in self.dependencies
],
dependency_overrides_provider=self.dependency_overrides_provider)
if asyncio.iscoroutinefunction(self.func):
await self.func(**values)
else:
await run_sync(self.func)(**values)
def cache_dependent(self, dependency: Depends):
if not dependency.dependency:
raise ValueError(f"{dependency} has no dependency")
if (dependency.dependency,) in self.sub_dependents:
raise ValueError(f"{dependency} is already in dependencies")
sub_dependant = get_parameterless_sub_dependant(depends=dependency)
self.sub_dependents[(dependency.dependency,)] = sub_dependant
def prepend_dependency(self, dependency: Depends):
self.cache_dependent(dependency)
self.dependencies.insert(0, dependency)
def append_dependency(self, dependency: Depends):
self.cache_dependent(dependency)
self.dependencies.append(dependency)
def remove_dependency(self, dependency: Depends):
if not dependency.dependency:
raise ValueError(f"{dependency} has no dependency")
if (dependency.dependency,) in self.sub_dependents:
del self.sub_dependents[(dependency.dependency,)]
if dependency in self.dependencies:
self.dependencies.remove(dependency)

View File

@ -5,7 +5,6 @@
该模块实现事件响应器的创建与运行并提供一些快捷方法来帮助用户更好的与机器人进行对话 该模块实现事件响应器的创建与运行并提供一些快捷方法来帮助用户更好的与机器人进行对话
""" """
from functools import wraps
from types import ModuleType from types import ModuleType
from datetime import datetime from datetime import datetime
from contextvars import ContextVar from contextvars import ContextVar
@ -13,8 +12,10 @@ from collections import defaultdict
from typing import (TYPE_CHECKING, Any, Dict, List, Type, Union, Callable, from typing import (TYPE_CHECKING, Any, Dict, List, Type, Union, Callable,
NoReturn, Optional) NoReturn, Optional)
from .models import Depends
from .handler import Handler from .handler import Handler
from nonebot.rule import Rule from nonebot.rule import Rule
from nonebot import get_driver
from nonebot.log import logger from nonebot.log import logger
from nonebot.adapters import MessageTemplate from nonebot.adapters import MessageTemplate
from nonebot.permission import USER, Permission from nonebot.permission import USER, Permission
@ -228,8 +229,8 @@ class Matcher(metaclass=MatcherMeta):
"permission": "permission":
permission or Permission(), permission or Permission(),
"handlers": [ "handlers": [
handler handler if isinstance(handler, Handler) else Handler(
if isinstance(handler, Handler) else Handler(handler) handler, dependency_overrides_provider=get_driver())
for handler in handlers for handler in handlers
] if handlers else [], ] if handlers else [],
"temp": "temp":
@ -343,8 +344,12 @@ class Matcher(metaclass=MatcherMeta):
return func return func
@classmethod @classmethod
def append_handler(cls, handler: T_Handler) -> Handler: def append_handler(cls,
handler_ = Handler(handler) handler: T_Handler,
dependencies: Optional[List[Depends]] = None) -> Handler:
handler_ = Handler(handler,
dependencies=dependencies,
dependency_overrides_provider=get_driver())
cls.handlers.append(handler_) cls.handlers.append(handler_)
return handler_ return handler_
@ -378,22 +383,19 @@ class Matcher(metaclass=MatcherMeta):
* *
""" """
async def _receive(bot: "Bot", event: "Event") -> NoReturn:
raise PausedException
if cls.handlers:
# 已有前置handlers则接受一条新的消息否则视为接收初始消息
receive_handler = cls.append_handler(_receive)
else:
receive_handler = None
def _decorator(func: T_Handler) -> T_Handler: def _decorator(func: T_Handler) -> T_Handler:
if not cls.handlers or cls.handlers[-1] is not func:
func_handler = cls.append_handler(func) async def _receive() -> NoReturn:
if receive_handler: func_handler.remove_dependency(depend)
receive_handler.update_signature( raise PausedException
bot=func_handler.bot_type,
event=func_handler.event_type) depend = Depends(_receive)
if cls.handlers and cls.handlers[-1].func is func:
func_handler = cls.handlers[-1]
func_handler.prepend_dependency(depend)
else:
func_handler = cls.append_handler(
func, dependencies=[depend] if cls.handlers else [])
return func return func
@ -419,54 +421,42 @@ class Matcher(metaclass=MatcherMeta):
* ``args_parser: Optional[T_ArgsParser]``: 可选参数解析函数空则使用默认解析函数 * ``args_parser: Optional[T_ArgsParser]``: 可选参数解析函数空则使用默认解析函数
""" """
async def _key_getter(bot: "Bot", event: "Event", state: T_State):
state["_current_key"] = key
if key not in state:
if prompt is not None:
if isinstance(prompt, MessageTemplate):
_prompt = prompt.format(**state)
else:
_prompt = prompt
await bot.send(event=event, message=_prompt)
raise PausedException
else:
state["_skip_key"] = True
async def _key_parser(bot: "Bot", event: "Event", state: T_State):
if key in state and state.get("_skip_key"):
del state["_skip_key"]
return
parser = args_parser or cls._default_parser
if parser:
# parser = cast(T_ArgsParser["Bot", "Event"], parser)
await parser(bot, event, state)
else:
state[state["_current_key"]] = str(event.get_message())
getter_handler = cls.append_handler(_key_getter)
parser_handler = cls.append_handler(_key_parser)
def _decorator(func: T_Handler) -> T_Handler: def _decorator(func: T_Handler) -> T_Handler:
if not hasattr(cls.handlers[-1].func, "__wrapped__"):
parser = cls.handlers.pop()
func_handler = Handler(func)
@wraps(func) async def _key_getter(bot: "Bot", event: "Event", state: T_State):
async def wrapper(bot: "Bot", event: "Event", state: T_State, func_handler.remove_dependency(get_depend)
matcher: Matcher): state["_current_key"] = key
await parser(matcher, bot, event, state) if key not in state:
await func_handler(matcher, bot, event, state) if prompt is not None:
if "_current_key" in state: if isinstance(prompt, MessageTemplate):
del state["_current_key"] _prompt = prompt.format(**state)
else:
_prompt = prompt
await bot.send(event=event, message=_prompt)
raise PausedException
else:
state["_skip_key"] = True
wrapper_handler = cls.append_handler(wrapper) async def _key_parser(bot: "Bot", event: "Event", state: T_State):
if key in state and state.get("_skip_key"):
del state["_skip_key"]
return
parser = args_parser or cls._default_parser
if parser:
await parser(bot, event, state)
else:
state[state["_current_key"]] = str(event.get_message())
getter_handler.update_signature( get_depend = Depends(_key_getter)
bot=wrapper_handler.bot_type, parser_depend = Depends(_key_parser)
event=wrapper_handler.event_type)
parser_handler.update_signature( if cls.handlers and cls.handlers[-1].func is func:
bot=wrapper_handler.bot_type, func_handler = cls.handlers[-1]
event=wrapper_handler.event_type) func_handler.prepend_dependency(parser_depend)
func_handler.prepend_dependency(get_depend)
else:
func_handler = cls.append_handler(
func, dependencies=[get_depend, parser_depend])
return func return func

View File

@ -1,7 +1,10 @@
from typing import Any, List, Callable, Optional from typing import TYPE_CHECKING, Any, List, Tuple, Callable, Optional
from nonebot.utils import get_name from nonebot.utils import get_name
if TYPE_CHECKING:
from nonebot.adapters import Bot, Event
class Depends: class Depends:
@ -25,7 +28,9 @@ class Dependent:
func: Optional[Callable[..., Any]] = None, func: Optional[Callable[..., Any]] = None,
name: Optional[str] = None, name: Optional[str] = None,
bot_param_name: Optional[str] = None, bot_param_name: Optional[str] = None,
bot_param_type: Optional[Tuple["Bot", ...]] = None,
event_param_name: Optional[str] = None, event_param_name: Optional[str] = None,
event_param_type: Optional[Tuple["Event", ...]] = None,
state_param_name: Optional[str] = None, state_param_name: Optional[str] = None,
matcher_param_name: Optional[str] = None, matcher_param_name: Optional[str] = None,
dependencies: Optional[List["Dependent"]] = None, dependencies: Optional[List["Dependent"]] = None,
@ -33,7 +38,9 @@ class Dependent:
self.func = func self.func = func
self.name = name self.name = name
self.bot_param_name = bot_param_name self.bot_param_name = bot_param_name
self.bot_param_type = bot_param_type
self.event_param_name = event_param_name self.event_param_name = event_param_name
self.event_param_type = event_param_type
self.state_param_name = state_param_name self.state_param_name = state_param_name
self.matcher_param_name = matcher_param_name self.matcher_param_name = matcher_param_name
self.dependencies = dependencies or [] self.dependencies = dependencies or []

View File

@ -1,7 +1,7 @@
import inspect import inspect
from typing import Any, Dict, Type, Tuple, Union, Callable from typing import Any, Dict, Type, Tuple, Union, Callable
from pydantic.typing import (ForwardRef, GenericAlias, get_args, get_origin, from pydantic.typing import (ForwardRef, get_args, get_origin,
evaluate_forwardref) evaluate_forwardref)
@ -41,3 +41,9 @@ def generic_check_issubclass(
return False return False
return True return True
raise raise
def generic_get_types(cls: Any) -> Tuple[Type[Any], ...]:
if get_origin(cls) is Union:
return get_args(cls)
return (cls,)

View File

@ -22,7 +22,7 @@ from typing import (TYPE_CHECKING, Any, Dict, Union, TypeVar, Callable,
NoReturn, Optional, Awaitable) NoReturn, Optional, Awaitable)
if TYPE_CHECKING: if TYPE_CHECKING:
from nonebot.matcher import Matcher from nonebot.processor import Matcher
from nonebot.adapters import Bot, Event from nonebot.adapters import Bot, Event
from nonebot.permission import Permission from nonebot.permission import Permission

View File

@ -4,11 +4,15 @@ import asyncio
import inspect import inspect
import dataclasses import dataclasses
from functools import wraps, partial from functools import wraps, partial
from typing import Any, Callable, Optional, Awaitable from typing_extensions import ParamSpec
from typing import Any, TypeVar, Callable, Optional, Awaitable
from nonebot.log import logger from nonebot.log import logger
from nonebot.typing import overrides from nonebot.typing import overrides
P = ParamSpec("P")
R = TypeVar("R")
def escape_tag(s: str) -> str: def escape_tag(s: str) -> str:
""" """
@ -27,7 +31,16 @@ def escape_tag(s: str) -> str:
return re.sub(r"</?((?:[fb]g\s)?[^<>\s]*)>", r"\\\g<0>", s) return re.sub(r"</?((?:[fb]g\s)?[^<>\s]*)>", r"\\\g<0>", s)
def run_sync(func: Callable[..., Any]) -> Callable[..., Awaitable[Any]]: def is_coroutine_callable(func: Callable[..., Any]) -> bool:
if inspect.isroutine(func):
return inspect.iscoroutinefunction(func)
if inspect.isclass(func):
return False
func_ = getattr(func, "__call__", None)
return inspect.iscoroutinefunction(func_)
def run_sync(func: Callable[P, R]) -> Callable[P, Awaitable[R]]:
""" """
:说明: :说明:
@ -35,15 +48,15 @@ def run_sync(func: Callable[..., Any]) -> Callable[..., Awaitable[Any]]:
:参数: :参数:
* ``func: Callable[..., Any]``: 被装饰的同步函数 * ``func: Callable[P, R]``: 被装饰的同步函数
:返回: :返回:
- ``Callable[..., Awaitable[Any]]`` - ``Callable[P, Awaitable[R]]``
""" """
@wraps(func) @wraps(func)
async def _wrapper(*args: Any, **kwargs: Any) -> Any: async def _wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
loop = asyncio.get_running_loop() loop = asyncio.get_running_loop()
pfunc = partial(func, *args, **kwargs) pfunc = partial(func, *args, **kwargs)
result = await loop.run_in_executor(None, pfunc) result = await loop.run_in_executor(None, pfunc)

2
poetry.lock generated
View File

@ -1099,7 +1099,7 @@ quart = ["Quart"]
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.7.3" python-versions = "^3.7.3"
content-hash = "51f4f0ce5ced234a65cae790c4f57486e42d7120972657a3f51e733cb4e7c639" content-hash = "81edd95f4289e55d7cfe632664c930846bde723cb8fa0359fa1e18474853f454"
[metadata.files] [metadata.files]
aiocache = [ aiocache = [

View File

@ -28,6 +28,7 @@ pygtrie = "^2.4.1"
tomlkit = "^0.7.0" tomlkit = "^0.7.0"
fastapi = "^0.70.0" fastapi = "^0.70.0"
websockets = ">=9.1" websockets = ">=9.1"
typing-extensions = "^3.10.0"
Quart = { version = "^0.15.0", optional = true } Quart = { version = "^0.15.0", optional = true }
httpx = { version = ">=0.20.0, <1.0.0", extras = ["http2"] } httpx = { version = ">=0.20.0, <1.0.0", extras = ["http2"] }
pydantic = { version = "~1.8.0", extras = ["dotenv"] } pydantic = { version = "~1.8.0", extras = ["dotenv"] }

View File

@ -1,7 +1,7 @@
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.matcher import Matcher from nonebot.processor import Matcher
from nonebot.adapters import Bot, Event from nonebot.adapters import Bot, Event
from nonebot.message import event_preprocessor, run_preprocessor from nonebot.message import run_preprocessor, event_preprocessor
@event_preprocessor @event_preprocessor