🎨 update typing support

This commit is contained in:
yanyongyu 2020-12-06 02:30:19 +08:00
parent 9ab7176eaf
commit 629eed08b6
26 changed files with 247 additions and 205 deletions

View File

@ -46,6 +46,10 @@ CUSTOM_CONFIG2= # 留空则从系统环境变量读取,如不存在则为空
详细的配置项参考 [Config Reference](../api/config.md) 。 详细的配置项参考 [Config Reference](../api/config.md) 。
## 系统环境变量
如果在系统环境变量中定义了配置,则一样会被读取。
## bot.py 文件 ## bot.py 文件
配置项也可以在 NoneBot 初始化时传入。此处可以传入任意合法 Python 变量。当然也可以在初始化完成后修改或新增。 配置项也可以在 NoneBot 初始化时传入。此处可以传入任意合法 Python 变量。当然也可以在初始化完成后修改或新增。
@ -65,4 +69,4 @@ config.custom_config4 = "new config after init"
## 优先级 ## 优先级
`bot.py init` > `env file` > `system env` `bot.py init` > `system env` > `env file`

View File

@ -26,7 +26,13 @@
import importlib import importlib
import pkg_resources import pkg_resources
from nonebot.typing import Bot, Dict, Type, Union, Driver, Optional from typing import Dict, Type, Optional
from nonebot.utils import escape_tag
from nonebot.config import Env, Config
from nonebot.adapters import BaseBot as Bot
from nonebot.log import logger, default_filter
from nonebot.drivers import BaseDriver as Driver
_dist: pkg_resources.Distribution = pkg_resources.get_distribution("nonebot2") _dist: pkg_resources.Distribution = pkg_resources.get_distribution("nonebot2")
__version__ = _dist.version __version__ = _dist.version
@ -136,11 +142,6 @@ def get_bots() -> Dict[str, Bot]:
return driver.bots return driver.bots
from nonebot.utils import escape_tag
from nonebot.config import Env, Config
from nonebot.log import logger, default_filter
def init(*, _env_file: Optional[str] = None, **kwargs): def init(*, _env_file: Optional[str] = None, **kwargs):
""" """
:说明: :说明:

View File

@ -8,12 +8,14 @@
import abc import abc
from functools import reduce, partial from functools import reduce, partial
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Any, Dict, Union, TypeVar, Optional, Callable, Iterable, Awaitable, Generic, TYPE_CHECKING
from pydantic import BaseModel from pydantic import BaseModel
from nonebot.config import Config from nonebot.config import Config
from nonebot.typing import Driver, Message, WebSocket
from nonebot.typing import Any, Dict, Union, Optional, Callable, Iterable, Awaitable, TypeVar, Generic if TYPE_CHECKING:
from nonebot.drivers import BaseDriver as Driver, BaseWebSocket as WebSocket
class BaseBot(abc.ABC): class BaseBot(abc.ABC):
@ -23,12 +25,12 @@ class BaseBot(abc.ABC):
@abc.abstractmethod @abc.abstractmethod
def __init__(self, def __init__(self,
driver: Driver, driver: "Driver",
connection_type: str, connection_type: str,
config: Config, config: Config,
self_id: str, self_id: str,
*, *,
websocket: Optional[WebSocket] = None): websocket: Optional["WebSocket"] = None):
""" """
:参数: :参数:
@ -60,7 +62,7 @@ class BaseBot(abc.ABC):
@classmethod @classmethod
@abc.abstractmethod @abc.abstractmethod
async def check_permission(cls, driver: Driver, connection_type: str, async def check_permission(cls, driver: "Driver", connection_type: str,
headers: dict, body: Optional[dict]) -> str: headers: dict, body: Optional[dict]) -> str:
""" """
:说明: :说明:
@ -252,7 +254,7 @@ class BaseEvent(abc.ABC, Generic[T]):
@property @property
@abc.abstractmethod @abc.abstractmethod
def message(self) -> Optional[Message]: def message(self) -> Optional["BaseMessage"]:
"""消息内容""" """消息内容"""
raise NotImplementedError raise NotImplementedError
@ -373,7 +375,9 @@ class BaseMessage(list, abc.ABC):
@staticmethod @staticmethod
@abc.abstractmethod @abc.abstractmethod
def _construct(msg: Union[str, dict, list]) -> Iterable[BaseMessageSegment]: def _construct(
msg: Union[str, dict, list,
BaseModel]) -> Iterable[BaseMessageSegment]:
raise NotImplementedError raise NotImplementedError
def __add__( def __add__(

View File

@ -3,22 +3,25 @@ import sys
import hmac import hmac
import json import json
import asyncio import asyncio
from typing import Any, Dict, Union, Optional, TYPE_CHECKING
import httpx import httpx
from nonebot.log import logger from nonebot.log import logger
from nonebot.config import Config from nonebot.config import Config
from nonebot.typing import overrides
from nonebot.adapters import BaseBot from nonebot.adapters import BaseBot
from nonebot.message import handle_event from nonebot.message import handle_event
from nonebot.exception import RequestDenied from nonebot.exception import RequestDenied
from nonebot.typing import Any, Dict, Union, Optional
from nonebot.typing import overrides, Driver, WebSocket
from .event import Event from .event import Event
from .message import Message, MessageSegment from .message import Message, MessageSegment
from .exception import NetworkError, ApiNotAvailable, ActionFailed from .exception import NetworkError, ApiNotAvailable, ActionFailed
from .utils import log from .utils import log
if TYPE_CHECKING:
from nonebot.drivers import BaseDriver as Driver, BaseWebSocket as WebSocket
def get_auth_bearer(access_token: Optional[str] = None) -> Optional[str]: def get_auth_bearer(access_token: Optional[str] = None) -> Optional[str]:
if not access_token: if not access_token:
@ -212,12 +215,12 @@ class Bot(BaseBot):
""" """
def __init__(self, def __init__(self,
driver: Driver, driver: "Driver",
connection_type: str, connection_type: str,
config: Config, config: Config,
self_id: str, self_id: str,
*, *,
websocket: Optional[WebSocket] = None): websocket: Optional["WebSocket"] = None):
super().__init__(driver, super().__init__(driver,
connection_type, connection_type,
@ -235,7 +238,7 @@ class Bot(BaseBot):
@classmethod @classmethod
@overrides(BaseBot) @overrides(BaseBot)
async def check_permission(cls, driver: Driver, connection_type: str, async def check_permission(cls, driver: "Driver", connection_type: str,
headers: dict, body: Optional[dict]) -> str: headers: dict, body: Optional[dict]) -> str:
""" """
:说明: :说明:

View File

@ -1,8 +1,9 @@
import asyncio import asyncio
from typing import Any, Dict, List, Union, Optional
from nonebot.config import Config from nonebot.config import Config
from nonebot.adapters import BaseBot from nonebot.adapters import BaseBot
from nonebot.typing import Any, Dict, List, Union, Driver, Optional, WebSocket from nonebot.drivers import BaseDriver as Driver, BaseWebSocket as WebSocket
from .event import Event from .event import Event
from .message import Message, MessageSegment from .message import Message, MessageSegment

View File

@ -1,5 +1,7 @@
from typing import Optional
from nonebot.typing import overrides
from nonebot.adapters import BaseEvent from nonebot.adapters import BaseEvent
from nonebot.typing import Optional, overrides
from .message import Message from .message import Message

View File

@ -1,4 +1,5 @@
from nonebot.typing import Optional from typing import Optional
from nonebot.exception import (AdapterException, ActionFailed as from nonebot.exception import (AdapterException, ActionFailed as
BaseActionFailed, NetworkError as BaseActionFailed, NetworkError as
BaseNetworkError, ApiNotAvailable as BaseNetworkError, ApiNotAvailable as

View File

@ -1,6 +1,7 @@
import re import re
from typing import Any, Dict, Union, Tuple, Iterable, Optional
from nonebot.typing import Any, Dict, Union, Tuple, Iterable, Optional, overrides from nonebot.typing import overrides
from nonebot.adapters import BaseMessage, BaseMessageSegment from nonebot.adapters import BaseMessage, BaseMessageSegment
from .utils import log, escape, unescape, _b2s from .utils import log, escape, unescape, _b2s

View File

@ -1,4 +1,5 @@
from nonebot.typing import Optional from typing import Optional
from nonebot.utils import logger_wrapper from nonebot.utils import logger_wrapper
log = logger_wrapper("CQHTTP") log = logger_wrapper("CQHTTP")

View File

@ -1,6 +1,7 @@
import hmac import hmac
import base64 import base64
from datetime import datetime from datetime import datetime
from typing import Any, Union, Optional, TYPE_CHECKING
import httpx import httpx
from nonebot.log import logger from nonebot.log import logger
@ -8,7 +9,6 @@ from nonebot.config import Config
from nonebot.adapters import BaseBot from nonebot.adapters import BaseBot
from nonebot.message import handle_event from nonebot.message import handle_event
from nonebot.exception import RequestDenied from nonebot.exception import RequestDenied
from nonebot.typing import Any, Union, Driver, Optional
from .utils import log from .utils import log
from .event import Event from .event import Event
@ -16,13 +16,16 @@ from .model import MessageModel
from .message import Message, MessageSegment from .message import Message, MessageSegment
from .exception import NetworkError, ApiNotAvailable, ActionFailed, SessionExpired from .exception import NetworkError, ApiNotAvailable, ActionFailed, SessionExpired
if TYPE_CHECKING:
from nonebot.drivers import BaseDriver as Driver
class Bot(BaseBot): class Bot(BaseBot):
""" """
钉钉 协议 Bot 适配继承属性参考 `BaseBot <./#class-basebot>`_ 。 钉钉 协议 Bot 适配继承属性参考 `BaseBot <./#class-basebot>`_ 。
""" """
def __init__(self, driver: Driver, connection_type: str, config: Config, def __init__(self, driver: "Driver", connection_type: str, config: Config,
self_id: str, **kwargs): self_id: str, **kwargs):
super().__init__(driver, connection_type, config, self_id, **kwargs) super().__init__(driver, connection_type, config, self_id, **kwargs)
@ -35,7 +38,7 @@ class Bot(BaseBot):
return "ding" return "ding"
@classmethod @classmethod
async def check_permission(cls, driver: Driver, connection_type: str, async def check_permission(cls, driver: "Driver", connection_type: str,
headers: dict, body: Optional[dict]) -> str: headers: dict, body: Optional[dict]) -> str:
""" """
:说明: :说明:

View File

@ -1,5 +1,6 @@
from typing import Union, Optional
from nonebot.adapters import BaseEvent from nonebot.adapters import BaseEvent
from nonebot.typing import Union, Optional
from .message import Message from .message import Message
from .model import MessageModel, ConversationType, TextMessage from .model import MessageModel, ConversationType, TextMessage

View File

@ -1,4 +1,5 @@
from nonebot.typing import Optional from typing import Optional
from nonebot.exception import (AdapterException, ActionFailed as from nonebot.exception import (AdapterException, ActionFailed as
BaseActionFailed, ApiNotAvailable as BaseActionFailed, ApiNotAvailable as
BaseApiNotAvailable, NetworkError as BaseApiNotAvailable, NetworkError as

View File

@ -1,5 +1,7 @@
from nonebot.typing import Any, Dict, Union, Iterable from typing import Any, Dict, Union, Iterable
from nonebot.adapters import BaseMessage, BaseMessageSegment from nonebot.adapters import BaseMessage, BaseMessageSegment
from .utils import log from .utils import log
from .model import TextMessage from .model import TextMessage

View File

@ -1,5 +1,6 @@
from typing import List, Optional
from enum import Enum from enum import Enum
from typing import List, Optional
from pydantic import BaseModel from pydantic import BaseModel

View File

@ -18,12 +18,11 @@ import os
from pathlib import Path from pathlib import Path
from datetime import timedelta from datetime import timedelta
from ipaddress import IPv4Address from ipaddress import IPv4Address
from typing import Any, Set, Dict, Union, Mapping, Optional
from pydantic import BaseSettings, IPvAnyAddress from pydantic import BaseSettings, IPvAnyAddress
from pydantic.env_settings import SettingsError, env_file_sentinel, read_env_file from pydantic.env_settings import SettingsError, env_file_sentinel, read_env_file
from nonebot.typing import Any, Set, Dict, Union, Mapping, Optional
class BaseConfig(BaseSettings): class BaseConfig(BaseSettings):
@ -56,7 +55,7 @@ class BaseConfig(BaseSettings):
for field in self.__fields__.values(): for field in self.__fields__.values():
env_val: Optional[str] = None env_val: Optional[str] = None
for env_name in field.field_info.extra['env_names']: for env_name in field.field_info.extra["env_names"]:
env_val = env_vars.get(env_name) env_val = env_vars.get(env_name)
if env_name in env_file_vars: if env_name in env_file_vars:
del env_file_vars[env_name] del env_file_vars[env_name]

View File

@ -6,10 +6,13 @@
""" """
import abc import abc
from typing import Dict, Type, Optional, Callable, TYPE_CHECKING
from nonebot.log import logger from nonebot.log import logger
from nonebot.config import Env, Config from nonebot.config import Env, Config
from nonebot.typing import Bot, Dict, Type, Union, Optional, Callable
if TYPE_CHECKING:
from nonebot.adapters import BaseBot as Bot
class BaseDriver(abc.ABC): class BaseDriver(abc.ABC):
@ -17,7 +20,7 @@ class BaseDriver(abc.ABC):
Driver 基类将后端框架封装以满足适配器使用 Driver 基类将后端框架封装以满足适配器使用
""" """
_adapters: Dict[str, Type[Bot]] = {} _adapters: Dict[str, Type["Bot"]] = {}
""" """
:类型: ``Dict[str, Type[Bot]]`` :类型: ``Dict[str, Type[Bot]]``
:说明: 已注册的适配器列表 :说明: 已注册的适配器列表
@ -41,14 +44,14 @@ class BaseDriver(abc.ABC):
:类型: ``Config`` :类型: ``Config``
:说明: 配置对象 :说明: 配置对象
""" """
self._clients: Dict[str, Bot] = {} self._clients: Dict[str, "Bot"] = {}
""" """
:类型: ``Dict[str, Bot]`` :类型: ``Dict[str, Bot]``
:说明: 已连接的 Bot :说明: 已连接的 Bot
""" """
@classmethod @classmethod
def register_adapter(cls, name: str, adapter: Type[Bot]): def register_adapter(cls, name: str, adapter: Type["Bot"]):
""" """
:说明: :说明:
@ -88,7 +91,7 @@ class BaseDriver(abc.ABC):
raise NotImplementedError raise NotImplementedError
@property @property
def bots(self) -> Dict[str, Bot]: def bots(self) -> Dict[str, "Bot"]:
""" """
:类型: ``Dict[str, Bot]`` :类型: ``Dict[str, Bot]``
:说明: 获取当前所有已连接的 Bot :说明: 获取当前所有已连接的 Bot

View File

@ -8,34 +8,22 @@ FastAPI 驱动适配
https://fastapi.tiangolo.com/ https://fastapi.tiangolo.com/
""" """
import hmac
import json import json
import asyncio import asyncio
import logging import logging
from typing import Optional, Callable
import uvicorn import uvicorn
from fastapi.responses import Response from fastapi.responses import Response
from fastapi import Body, status, Header, Request, FastAPI, Depends, HTTPException from fastapi import Body, status, Request, FastAPI, HTTPException
from starlette.websockets import WebSocketDisconnect, WebSocket as FastAPIWebSocket from starlette.websockets import WebSocketDisconnect, WebSocket as FastAPIWebSocket
from nonebot.log import logger from nonebot.log import logger
from nonebot.typing import overrides
from nonebot.config import Env, Config from nonebot.config import Env, Config
from nonebot.utils import DataclassEncoder from nonebot.utils import DataclassEncoder
from nonebot.exception import RequestDenied from nonebot.exception import RequestDenied
from nonebot.drivers import BaseDriver, BaseWebSocket from nonebot.drivers import BaseDriver, BaseWebSocket
from nonebot.typing import Optional, Callable, overrides
def get_auth_bearer(access_token: Optional[str] = Header(
None, alias="Authorization")):
if not access_token:
return None
scheme, _, param = access_token.partition(" ")
if scheme.lower() not in ["bearer", "token"]:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="Not authenticated",
headers={"WWW-Authenticate": "Bearer"})
return param
class Driver(BaseDriver): class Driver(BaseDriver):

View File

@ -5,20 +5,25 @@
该模块实现事件响应器的创建与运行并提供一些快捷方法来帮助用户更好的与机器人进行 对话 该模块实现事件响应器的创建与运行并提供一些快捷方法来帮助用户更好的与机器人进行 对话
""" """
from nonebot.log import logger
import typing import typing
import inspect import inspect
from functools import wraps from functools import wraps
from datetime import datetime from datetime import datetime
from contextvars import ContextVar from contextvars import ContextVar
from collections import defaultdict from collections import defaultdict
from typing import Type, List, Dict, Union, Callable, Optional, NoReturn, TYPE_CHECKING
from nonebot.rule import Rule from nonebot.rule import Rule
from nonebot.log import logger
from nonebot.permission import Permission, USER from nonebot.permission import Permission, USER
from nonebot.typing import Type, List, Dict, Union, Callable, Optional, NoReturn from nonebot.typing import State, Handler, ArgsParser
from nonebot.typing import Bot, Event, Handler, Message, ArgsParser, MessageSegment
from nonebot.exception import PausedException, RejectedException, FinishedException from nonebot.exception import PausedException, RejectedException, FinishedException
if TYPE_CHECKING:
from nonebot.adapters import (BaseBot as Bot, BaseEvent as Event,
BaseMessage as Message, BaseMessageSegment as
MessageSegment)
matchers: Dict[int, List[Type["Matcher"]]] = defaultdict(list) matchers: Dict[int, List[Type["Matcher"]]] = defaultdict(list)
""" """
:类型: ``Dict[int, List[Type[Matcher]]]`` :类型: ``Dict[int, List[Type[Matcher]]]``
@ -88,9 +93,9 @@ class Matcher(metaclass=MatcherMeta):
:说明: 事件响应器过期时间点 :说明: 事件响应器过期时间点
""" """
_default_state: dict = {} _default_state: State = {}
""" """
:类型: ``dict`` :类型: ``State``
:说明: 事件响应器默认状态 :说明: 事件响应器默认状态
""" """
@ -123,7 +128,7 @@ class Matcher(metaclass=MatcherMeta):
block: bool = False, block: bool = False,
*, *,
module: Optional[str] = None, module: Optional[str] = None,
default_state: Optional[dict] = None, default_state: Optional[State] = None,
expire_time: Optional[datetime] = None) -> Type["Matcher"]: expire_time: Optional[datetime] = None) -> Type["Matcher"]:
""" """
:说明: :说明:
@ -140,7 +145,7 @@ class Matcher(metaclass=MatcherMeta):
* ``priority: int``: 响应优先级 * ``priority: int``: 响应优先级
* ``block: bool``: 是否阻止事件向更低优先级的响应器传播 * ``block: bool``: 是否阻止事件向更低优先级的响应器传播
* ``module: Optional[str]``: 事件响应器所在模块名称 * ``module: Optional[str]``: 事件响应器所在模块名称
* ``default_state: Optional[dict]``: 默认状态 ``state`` * ``default_state: Optional[State]``: 默认状态 ``state``
* ``expire_time: Optional[datetime]``: 事件响应器最终有效时间点过时即被删除 * ``expire_time: Optional[datetime]``: 事件响应器最终有效时间点过时即被删除
:返回: :返回:
@ -167,7 +172,7 @@ class Matcher(metaclass=MatcherMeta):
return NewMatcher return NewMatcher
@classmethod @classmethod
async def check_perm(cls, bot: Bot, event: Event) -> bool: async def check_perm(cls, bot: "Bot", event: "Event") -> bool:
""" """
:说明: :说明:
@ -185,7 +190,7 @@ class Matcher(metaclass=MatcherMeta):
return await cls.permission(bot, event) return await cls.permission(bot, event)
@classmethod @classmethod
async def check_rule(cls, bot: Bot, event: Event, state: dict) -> bool: async def check_rule(cls, bot: "Bot", event: "Event", state: State) -> bool:
""" """
:说明: :说明:
@ -195,7 +200,7 @@ class Matcher(metaclass=MatcherMeta):
* ``bot: Bot``: Bot 对象 * ``bot: Bot``: Bot 对象
* ``event: Event``: 上报事件 * ``event: Event``: 上报事件
* ``state: dict``: 当前状态 * ``state: State``: 当前状态
:返回: :返回:
@ -248,7 +253,8 @@ class Matcher(metaclass=MatcherMeta):
* *
""" """
async def _receive(bot: Bot, event: Event, state: dict) -> NoReturn: async def _receive(bot: "Bot", event: "Event",
state: State) -> NoReturn:
raise PausedException raise PausedException
if cls.handlers: if cls.handlers:
@ -267,7 +273,7 @@ class Matcher(metaclass=MatcherMeta):
def got( def got(
cls, cls,
key: str, key: str,
prompt: Optional[Union[str, Message, MessageSegment]] = None, prompt: Optional[Union[str, "Message", "MessageSegment"]] = None,
args_parser: Optional[ArgsParser] = None args_parser: Optional[ArgsParser] = None
) -> Callable[[Handler], Handler]: ) -> Callable[[Handler], Handler]:
""" """
@ -282,7 +288,7 @@ class Matcher(metaclass=MatcherMeta):
* ``args_parser: Optional[ArgsParser]``: 可选参数解析函数空则使用默认解析函数 * ``args_parser: Optional[ArgsParser]``: 可选参数解析函数空则使用默认解析函数
""" """
async def _key_getter(bot: Bot, event: Event, state: dict): async def _key_getter(bot: "Bot", event: "Event", state: State):
state["_current_key"] = key state["_current_key"] = key
if key not in state: if key not in state:
if prompt: if prompt:
@ -292,7 +298,7 @@ class Matcher(metaclass=MatcherMeta):
else: else:
state["_skip_key"] = True state["_skip_key"] = True
async def _key_parser(bot: Bot, event: Event, state: dict): async def _key_parser(bot: "Bot", event: "Event", state: State):
if key in state and state.get("_skip_key"): if key in state and state.get("_skip_key"):
del state["_skip_key"] del state["_skip_key"]
return return
@ -310,7 +316,7 @@ class Matcher(metaclass=MatcherMeta):
parser = cls.handlers.pop() parser = cls.handlers.pop()
@wraps(func) @wraps(func)
async def wrapper(bot: Bot, event: Event, state: dict): async def wrapper(bot: "Bot", event: "Event", state: State):
await parser(bot, event, state) await parser(bot, event, state)
await func(bot, event, state) await func(bot, event, state)
if "_current_key" in state: if "_current_key" in state:
@ -323,7 +329,8 @@ class Matcher(metaclass=MatcherMeta):
return _decorator return _decorator
@classmethod @classmethod
async def send(cls, message: Union[str, Message, MessageSegment], **kwargs): async def send(cls, message: Union[str, "Message", "MessageSegment"],
**kwargs):
""" """
:说明: :说明:
@ -340,8 +347,8 @@ class Matcher(metaclass=MatcherMeta):
@classmethod @classmethod
async def finish(cls, async def finish(cls,
message: Optional[Union[str, Message, message: Optional[Union[str, "Message",
MessageSegment]] = None, "MessageSegment"]] = None,
**kwargs) -> NoReturn: **kwargs) -> NoReturn:
""" """
:说明: :说明:
@ -361,8 +368,8 @@ class Matcher(metaclass=MatcherMeta):
@classmethod @classmethod
async def pause(cls, async def pause(cls,
prompt: Optional[Union[str, Message, prompt: Optional[Union[str, "Message",
MessageSegment]] = None, "MessageSegment"]] = None,
**kwargs) -> NoReturn: **kwargs) -> NoReturn:
""" """
:说明: :说明:
@ -382,8 +389,8 @@ class Matcher(metaclass=MatcherMeta):
@classmethod @classmethod
async def reject(cls, async def reject(cls,
prompt: Optional[Union[str, Message, prompt: Optional[Union[str, "Message",
MessageSegment]] = None, "MessageSegment"]] = None,
**kwargs) -> NoReturn: **kwargs) -> NoReturn:
""" """
:说明: :说明:
@ -402,7 +409,7 @@ class Matcher(metaclass=MatcherMeta):
raise RejectedException raise RejectedException
# 运行handlers # 运行handlers
async def run(self, bot: Bot, event: Event, state: dict): async def run(self, bot: "Bot", event: "Event", state: State):
b_t = current_bot.set(bot) b_t = current_bot.set(bot)
e_t = current_event.set(event) e_t = current_event.set(event)
try: try:

View File

@ -7,14 +7,17 @@ NoneBot 内部处理并按优先级分发事件给所有事件响应器,提供
import asyncio import asyncio
from datetime import datetime from datetime import datetime
from typing import Set, Type, Optional, Iterable, TYPE_CHECKING
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 matchers, Matcher from nonebot.matcher import matchers, Matcher
from nonebot.typing import Set, Type, Optional, Iterable, Bot, Event
from nonebot.exception import IgnoredException, StopPropagation from nonebot.exception import IgnoredException, StopPropagation
from nonebot.typing import EventPreProcessor, RunPreProcessor, EventPostProcessor, RunPostProcessor from nonebot.typing import State, EventPreProcessor, RunPreProcessor, EventPostProcessor, RunPostProcessor
if TYPE_CHECKING:
from nonebot.adapters import BaseBot as Bot, BaseEvent as Event
_event_preprocessors: Set[EventPreProcessor] = set() _event_preprocessors: Set[EventPreProcessor] = set()
_event_postprocessors: Set[EventPostProcessor] = set() _event_postprocessors: Set[EventPostProcessor] = set()
@ -34,7 +37,7 @@ def event_preprocessor(func: EventPreProcessor) -> EventPreProcessor:
* ``bot: Bot``: Bot 对象 * ``bot: Bot``: Bot 对象
* ``event: Event``: Event 对象 * ``event: Event``: Event 对象
* ``state: dict``: 当前 State * ``state: State``: 当前 State
""" """
_event_preprocessors.add(func) _event_preprocessors.add(func)
return func return func
@ -52,7 +55,7 @@ def event_postprocessor(func: EventPostProcessor) -> EventPostProcessor:
* ``bot: Bot``: Bot 对象 * ``bot: Bot``: Bot 对象
* ``event: Event``: Event 对象 * ``event: Event``: Event 对象
* ``state: dict``: 当前事件运行前 State * ``state: State``: 当前事件运行前 State
""" """
_event_postprocessors.add(func) _event_postprocessors.add(func)
return func return func
@ -71,7 +74,7 @@ def run_preprocessor(func: RunPreProcessor) -> RunPreProcessor:
* ``matcher: Matcher``: 当前要运行的事件响应器 * ``matcher: Matcher``: 当前要运行的事件响应器
* ``bot: Bot``: Bot 对象 * ``bot: Bot``: Bot 对象
* ``event: Event``: Event 对象 * ``event: Event``: Event 对象
* ``state: dict``: 当前 State * ``state: State``: 当前 State
""" """
_run_preprocessors.add(func) _run_preprocessors.add(func)
return func return func
@ -91,18 +94,18 @@ def run_postprocessor(func: RunPostProcessor) -> RunPostProcessor:
* ``exception: Optional[Exception]``: 事件响应器运行错误如果存在 * ``exception: Optional[Exception]``: 事件响应器运行错误如果存在
* ``bot: Bot``: Bot 对象 * ``bot: Bot``: Bot 对象
* ``event: Event``: Event 对象 * ``event: Event``: Event 对象
* ``state: dict``: 当前 State * ``state: State``: 当前 State
""" """
_run_postprocessors.add(func) _run_postprocessors.add(func)
return func return func
async def _check_matcher(priority: int, bot: Bot, event: Event, async def _check_matcher(priority: int, bot: "Bot", event: "Event",
state: dict) -> Iterable[Type[Matcher]]: state: State) -> Iterable[Type[Matcher]]:
current_matchers = matchers[priority].copy() current_matchers = matchers[priority].copy()
async def _check(Matcher: Type[Matcher], bot: Bot, event: Event, async def _check(Matcher: Type[Matcher], bot: "Bot", event: "Event",
state: dict) -> Optional[Type[Matcher]]: state: State) -> Optional[Type[Matcher]]:
try: try:
if (not Matcher.expire_time or datetime.now() <= Matcher.expire_time if (not Matcher.expire_time or datetime.now() <= Matcher.expire_time
) and await Matcher.check_perm( ) and await Matcher.check_perm(
@ -136,8 +139,8 @@ async def _check_matcher(priority: int, bot: Bot, event: Event,
return filter(lambda x: x, results) return filter(lambda x: x, results)
async def _run_matcher(Matcher: Type[Matcher], bot: Bot, event: Event, async def _run_matcher(Matcher: Type[Matcher], bot: "Bot", event: "Event",
state: dict) -> None: state: State) -> None:
logger.info(f"Event will be handled by {Matcher}") logger.info(f"Event will be handled by {Matcher}")
matcher = Matcher() matcher = Matcher()
@ -186,7 +189,7 @@ async def _run_matcher(Matcher: Type[Matcher], bot: Bot, event: Event,
return return
async def handle_event(bot: Bot, event: Event): async def handle_event(bot: "Bot", event: "Event"):
""" """
:说明: :说明:

View File

@ -10,16 +10,21 @@
""" """
import asyncio import asyncio
from typing import Union, Optional, Callable, NoReturn, Awaitable, TYPE_CHECKING
from nonebot.utils import run_sync from nonebot.utils import run_sync
from nonebot.typing import Bot, Event, Union, NoReturn, Optional, Callable, Awaitable, PermissionChecker from nonebot.typing import PermissionChecker
if TYPE_CHECKING:
from nonebot.adapters import BaseBot as Bot, BaseEvent as Event
class Permission: class Permission:
__slots__ = ("checkers",) __slots__ = ("checkers",)
def __init__(self, *checkers: Callable[[Bot, Event], def __init__(
Awaitable[bool]]) -> None: self, *checkers: Callable[["Bot", "Event"],
Awaitable[bool]]) -> None:
""" """
:参数: :参数:
@ -36,7 +41,7 @@ class Permission:
* ``Set[Callable[[Bot, Event], Awaitable[bool]]]`` * ``Set[Callable[[Bot, Event], Awaitable[bool]]]``
""" """
async def __call__(self, bot: Bot, event: Event) -> bool: async def __call__(self, bot: "Bot", event: "Event") -> bool:
""" """
:说明: :说明:
@ -75,19 +80,19 @@ class Permission:
return Permission(*checkers) return Permission(*checkers)
async def _message(bot: Bot, event: Event) -> bool: async def _message(bot: "Bot", event: "Event") -> bool:
return event.type == "message" return event.type == "message"
async def _notice(bot: Bot, event: Event) -> bool: async def _notice(bot: "Bot", event: "Event") -> bool:
return event.type == "notice" return event.type == "notice"
async def _request(bot: Bot, event: Event) -> bool: async def _request(bot: "Bot", event: "Event") -> bool:
return event.type == "request" return event.type == "request"
async def _metaevent(bot: Bot, event: Event) -> bool: async def _metaevent(bot: "Bot", event: "Event") -> bool:
return event.type == "meta_event" return event.type == "meta_event"
@ -121,28 +126,28 @@ def USER(*user: int, perm: Permission = Permission()):
* ``perm: Permission``: 需要同时满足的权限 * ``perm: Permission``: 需要同时满足的权限
""" """
async def _user(bot: Bot, event: Event) -> bool: async def _user(bot: "Bot", event: "Event") -> bool:
return event.type == "message" and event.user_id in user and await perm( return event.type == "message" and event.user_id in user and await perm(
bot, event) bot, event)
return Permission(_user) return Permission(_user)
async def _private(bot: Bot, event: Event) -> bool: async def _private(bot: "Bot", event: "Event") -> bool:
return event.type == "message" and event.detail_type == "private" return event.type == "message" and event.detail_type == "private"
async def _private_friend(bot: Bot, event: Event) -> bool: async def _private_friend(bot: "Bot", event: "Event") -> bool:
return (event.type == "message" and event.detail_type == "private" and return (event.type == "message" and event.detail_type == "private" and
event.sub_type == "friend") event.sub_type == "friend")
async def _private_group(bot: Bot, event: Event) -> bool: async def _private_group(bot: "Bot", event: "Event") -> bool:
return (event.type == "message" and event.detail_type == "private" and return (event.type == "message" and event.detail_type == "private" and
event.sub_type == "group") event.sub_type == "group")
async def _private_other(bot: Bot, event: Event) -> bool: async def _private_other(bot: "Bot", event: "Event") -> bool:
return (event.type == "message" and event.detail_type == "private" and return (event.type == "message" and event.detail_type == "private" and
event.sub_type == "other") event.sub_type == "other")
@ -165,21 +170,21 @@ PRIVATE_OTHER = Permission(_private_other)
""" """
async def _group(bot: Bot, event: Event) -> bool: async def _group(bot: "Bot", event: "Event") -> bool:
return event.type == "message" and event.detail_type == "group" return event.type == "message" and event.detail_type == "group"
async def _group_member(bot: Bot, event: Event) -> bool: async def _group_member(bot: "Bot", event: "Event") -> bool:
return (event.type == "message" and event.detail_type == "group" and return (event.type == "message" and event.detail_type == "group" and
event.sender.get("role") == "member") event.sender.get("role") == "member")
async def _group_admin(bot: Bot, event: Event) -> bool: async def _group_admin(bot: "Bot", event: "Event") -> bool:
return (event.type == "message" and event.detail_type == "group" and return (event.type == "message" and event.detail_type == "group" and
event.sender.get("role") == "admin") event.sender.get("role") == "admin")
async def _group_owner(bot: Bot, event: Event) -> bool: async def _group_owner(bot: "Bot", event: "Event") -> bool:
return (event.type == "message" and event.detail_type == "group" and return (event.type == "message" and event.detail_type == "group" and
event.sender.get("role") == "owner") event.sender.get("role") == "owner")
@ -206,7 +211,7 @@ GROUP_OWNER = Permission(_group_owner)
""" """
async def _superuser(bot: Bot, event: Event) -> bool: async def _superuser(bot: "Bot", event: "Event") -> bool:
return event.type == "message" and event.user_id in bot.config.superusers return event.type == "message" and event.user_id in bot.config.superusers

View File

@ -9,17 +9,17 @@ import re
import sys import sys
import pkgutil import pkgutil
import importlib import importlib
from datetime import datetime from types import ModuleType
from dataclasses import dataclass from dataclasses import dataclass
from importlib._bootstrap import _load from importlib._bootstrap import _load
from contextvars import Context, ContextVar, copy_context from contextvars import Context, ContextVar, copy_context
from typing import Any, Set, List, Dict, Type, Tuple, Union, Optional
from nonebot.log import logger from nonebot.log import logger
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from nonebot.permission import Permission from nonebot.permission import Permission
from nonebot.typing import Handler, RuleChecker from nonebot.typing import State, Handler, RuleChecker
from nonebot.rule import Rule, startswith, endswith, keyword, command, regex from nonebot.rule import Rule, startswith, endswith, keyword, command, regex
from nonebot.typing import Any, Set, List, Dict, Type, Tuple, Union, Optional, ArgsParser, ModuleType
plugins: Dict[str, "Plugin"] = {} plugins: Dict[str, "Plugin"] = {}
""" """
@ -108,7 +108,7 @@ def on(type: str = "",
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = False, block: bool = False,
state: Optional[dict] = None) -> Type[Matcher]: state: Optional[State] = None) -> Type[Matcher]:
""" """
:说明: :说明:
@ -123,7 +123,7 @@ def on(type: str = "",
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -147,7 +147,7 @@ def on_metaevent(rule: Optional[Union[Rule, RuleChecker]] = None,
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = False, block: bool = False,
state: Optional[dict] = None) -> Type[Matcher]: state: Optional[State] = None) -> Type[Matcher]:
""" """
:说明: :说明:
@ -160,7 +160,7 @@ def on_metaevent(rule: Optional[Union[Rule, RuleChecker]] = None,
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -185,7 +185,7 @@ def on_message(rule: Optional[Union[Rule, RuleChecker]] = None,
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = True, block: bool = True,
state: Optional[dict] = None) -> Type[Matcher]: state: Optional[State] = None) -> Type[Matcher]:
""" """
:说明: :说明:
@ -199,7 +199,7 @@ def on_message(rule: Optional[Union[Rule, RuleChecker]] = None,
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -223,7 +223,7 @@ def on_notice(rule: Optional[Union[Rule, RuleChecker]] = None,
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = False, block: bool = False,
state: Optional[dict] = None) -> Type[Matcher]: state: Optional[State] = None) -> Type[Matcher]:
""" """
:说明: :说明:
@ -236,7 +236,7 @@ def on_notice(rule: Optional[Union[Rule, RuleChecker]] = None,
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -260,7 +260,7 @@ def on_request(rule: Optional[Union[Rule, RuleChecker]] = None,
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = False, block: bool = False,
state: Optional[dict] = None) -> Type[Matcher]: state: Optional[State] = None) -> Type[Matcher]:
""" """
:说明: :说明:
@ -273,7 +273,7 @@ def on_request(rule: Optional[Union[Rule, RuleChecker]] = None,
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -308,7 +308,7 @@ def on_startswith(msg: str,
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -334,7 +334,7 @@ def on_endswith(msg: str,
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -360,7 +360,7 @@ def on_keyword(keywords: Set[str],
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -390,14 +390,14 @@ def on_command(cmd: Union[str, Tuple[str, ...]],
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
- ``Type[Matcher]`` - ``Type[Matcher]``
""" """
async def _strip_cmd(bot, event, state: dict): async def _strip_cmd(bot, event, state: State):
message = event.message message = event.message
event.message = message.__class__( event.message = message.__class__(
str(message)[len(state["_prefix"]["raw_command"]):].strip()) str(message)[len(state["_prefix"]["raw_command"]):].strip())
@ -430,7 +430,7 @@ def on_regex(pattern: str,
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -521,7 +521,7 @@ class MatcherGroup:
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -547,7 +547,7 @@ class MatcherGroup:
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -575,7 +575,7 @@ class MatcherGroup:
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -602,7 +602,7 @@ class MatcherGroup:
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -629,7 +629,7 @@ class MatcherGroup:
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -661,7 +661,7 @@ class MatcherGroup:
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -687,7 +687,7 @@ class MatcherGroup:
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -713,7 +713,7 @@ class MatcherGroup:
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
@ -743,14 +743,14 @@ class MatcherGroup:
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:
- ``Type[Matcher]`` - ``Type[Matcher]``
""" """
async def _strip_cmd(bot, event, state: dict): async def _strip_cmd(bot, event, state: State):
message = event.message message = event.message
event.message = message.__class__( event.message = message.__class__(
str(message)[len(state["_prefix"]["raw_command"]):].strip()) str(message)[len(state["_prefix"]["raw_command"]):].strip())
@ -785,7 +785,7 @@ class MatcherGroup:
* ``temp: bool``: 是否为临时事件响应器仅执行一次 * ``temp: bool``: 是否为临时事件响应器仅执行一次
* ``priority: int``: 事件响应器优先级 * ``priority: int``: 事件响应器优先级
* ``block: bool``: 是否阻止事件向更低优先级传递 * ``block: bool``: 是否阻止事件向更低优先级传递
* ``state: Optional[dict]``: 默认的 state * ``state: Optional[State]``: 默认的 state
:返回: :返回:

View File

@ -1,8 +1,12 @@
import re import re
from types import ModuleType
from contextvars import ContextVar from contextvars import ContextVar
from typing import Any, Set, List, Dict, Type, Tuple, Union, Optional
from nonebot.typing import Rule, Matcher, Handler, Permission, RuleChecker from nonebot.rule import Rule
from nonebot.typing import Set, List, Dict, Type, Tuple, Union, Optional, ModuleType from nonebot.matcher import Matcher
from nonebot.permission import Permission
from nonebot.typing import State, Handler, RuleChecker
plugins: Dict[str, "Plugin"] = ... plugins: Dict[str, "Plugin"] = ...
@ -37,7 +41,7 @@ def on(type: str = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
@ -47,7 +51,7 @@ def on_metaevent(rule: Optional[Union[Rule, RuleChecker]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
@ -58,7 +62,7 @@ def on_message(rule: Optional[Union[Rule, RuleChecker]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
@ -68,7 +72,7 @@ def on_notice(rule: Optional[Union[Rule, RuleChecker]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
@ -78,7 +82,7 @@ def on_request(rule: Optional[Union[Rule, RuleChecker]] = ...,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
@ -90,7 +94,7 @@ def on_startswith(msg: str,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
@ -102,7 +106,7 @@ def on_endswith(msg: str,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
@ -114,7 +118,7 @@ def on_keyword(keywords: Set[str],
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
@ -127,7 +131,7 @@ def on_command(cmd: Union[str, Tuple[str, ...]],
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
@ -140,7 +144,7 @@ def on_regex(pattern: str,
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
@ -183,8 +187,9 @@ class CommandGroup:
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...): state: Optional[State] = ...):
... self.basecmd: Tuple[str, ...] = ...
self.base_kwargs: Dict[str, Any] = ...
def command(self, def command(self,
cmd: Union[str, Tuple[str, ...]], cmd: Union[str, Tuple[str, ...]],
@ -196,7 +201,7 @@ class CommandGroup:
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
@ -211,7 +216,7 @@ class MatcherGroup:
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...): state: Optional[State] = ...):
... ...
def on(self, def on(self,
@ -223,7 +228,7 @@ class MatcherGroup:
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
def on_metaevent(self, def on_metaevent(self,
@ -233,7 +238,7 @@ class MatcherGroup:
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = False, block: bool = False,
state: Optional[dict] = None) -> Type[Matcher]: state: Optional[State] = None) -> Type[Matcher]:
... ...
def on_message(self, def on_message(self,
@ -244,7 +249,7 @@ class MatcherGroup:
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = True, block: bool = True,
state: Optional[dict] = None) -> Type[Matcher]: state: Optional[State] = None) -> Type[Matcher]:
... ...
def on_notice(self, def on_notice(self,
@ -254,7 +259,7 @@ class MatcherGroup:
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = False, block: bool = False,
state: Optional[dict] = None) -> Type[Matcher]: state: Optional[State] = None) -> Type[Matcher]:
... ...
def on_request(self, def on_request(self,
@ -264,7 +269,7 @@ class MatcherGroup:
temp: bool = False, temp: bool = False,
priority: int = 1, priority: int = 1,
block: bool = False, block: bool = False,
state: Optional[dict] = None) -> Type[Matcher]: state: Optional[State] = None) -> Type[Matcher]:
... ...
def on_startswith(self, def on_startswith(self,
@ -276,7 +281,7 @@ class MatcherGroup:
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
def on_endswith(self, def on_endswith(self,
@ -288,7 +293,7 @@ class MatcherGroup:
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
def on_keyword(self, def on_keyword(self,
@ -300,7 +305,7 @@ class MatcherGroup:
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
def on_command(self, def on_command(self,
@ -313,7 +318,7 @@ class MatcherGroup:
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...
def on_regex(self, def on_regex(self,
@ -326,5 +331,5 @@ class MatcherGroup:
temp: bool = ..., temp: bool = ...,
priority: int = ..., priority: int = ...,
block: bool = ..., block: bool = ...,
state: Optional[dict] = ...) -> Type[Matcher]: state: Optional[State] = ...) -> Type[Matcher]:
... ...

View File

@ -1,15 +1,16 @@
from functools import reduce from functools import reduce
from nonebot.rule import to_me from nonebot.rule import to_me
from nonebot.typing import State
from nonebot.plugin import on_command from nonebot.plugin import on_command
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot.typing import Bot, Event, MessageSegment from nonebot.adapters import BaseBot as Bot, BaseEvent as Event, BaseMessageSegment as MessageSegment
say = on_command("say", to_me(), permission=SUPERUSER) say = on_command("say", to_me(), permission=SUPERUSER)
@say.handle() @say.handle()
async def say_unescape(bot: Bot, event: Event, state: dict): async def say_unescape(bot: Bot, event: Event, state: State):
Message = event.message.__class__ Message = event.message.__class__
def _unescape(message: Message, segment: MessageSegment): def _unescape(message: Message, segment: MessageSegment):
@ -25,7 +26,7 @@ echo = on_command("echo", to_me())
@echo.handle() @echo.handle()
async def echo_escape(bot: Bot, event: Event, state: dict): async def echo_escape(bot: Bot, event: Event, state: State):
# Message = event.message.__class__ # Message = event.message.__class__
# MessageSegment = event.message[0].__class__ # MessageSegment = event.message[0].__class__

View File

@ -12,13 +12,17 @@
import re import re
import asyncio import asyncio
from itertools import product from itertools import product
from typing import Any, Dict, Union, Tuple, Optional, Callable, NoReturn, Awaitable, TYPE_CHECKING
from pygtrie import CharTrie from pygtrie import CharTrie
from nonebot import get_driver from nonebot import get_driver
from nonebot.log import logger from nonebot.log import logger
from nonebot.utils import run_sync from nonebot.utils import run_sync
from nonebot.typing import Bot, Any, Dict, Event, Union, Tuple, NoReturn, Optional, Callable, Awaitable, RuleChecker from nonebot.typing import State, RuleChecker
if TYPE_CHECKING:
from nonebot.adapters import BaseBot as Bot, BaseEvent as Event
class Rule: class Rule:
@ -39,12 +43,12 @@ class Rule:
__slots__ = ("checkers",) __slots__ = ("checkers",)
def __init__( def __init__(
self, *checkers: Callable[[Bot, Event, dict], self, *checkers: Callable[["Bot", "Event", State],
Awaitable[bool]]) -> None: Awaitable[bool]]) -> None:
""" """
:参数: :参数:
* ``*checkers: Callable[[Bot, Event, dict], Awaitable[bool]]``: **异步** RuleChecker * ``*checkers: Callable[[Bot, Event, State], Awaitable[bool]]``: **异步** RuleChecker
""" """
self.checkers = set(checkers) self.checkers = set(checkers)
@ -55,10 +59,10 @@ class Rule:
:类型: :类型:
* ``Set[Callable[[Bot, Event, dict], Awaitable[bool]]]`` * ``Set[Callable[[Bot, Event, State], Awaitable[bool]]]``
""" """
async def __call__(self, bot: Bot, event: Event, state: dict) -> bool: async def __call__(self, bot: "Bot", event: "Event", state: State) -> bool:
""" """
:说明: :说明:
@ -68,7 +72,7 @@ class Rule:
* ``bot: Bot``: Bot 对象 * ``bot: Bot``: Bot 对象
* ``event: Event``: Event 对象 * ``event: Event``: Event 对象
* ``state: dict``: 当前 State * ``state: State``: 当前 State
:返回: :返回:
@ -113,8 +117,8 @@ class TrieRule:
cls.suffix[suffix[::-1]] = value cls.suffix[suffix[::-1]] = value
@classmethod @classmethod
def get_value(cls, bot: Bot, event: Event, def get_value(cls, bot: "Bot", event: "Event",
state: dict) -> Tuple[Dict[str, Any], Dict[str, Any]]: state: State) -> Tuple[Dict[str, Any], Dict[str, Any]]:
if event.type != "message": if event.type != "message":
state["_prefix"] = {"raw_command": None, "command": None} state["_prefix"] = {"raw_command": None, "command": None}
state["_suffix"] = {"raw_command": None, "command": None} state["_suffix"] = {"raw_command": None, "command": None}
@ -176,7 +180,7 @@ def startswith(msg: str) -> Rule:
* ``msg: str``: 消息开头字符串 * ``msg: str``: 消息开头字符串
""" """
async def _startswith(bot: Bot, event: Event, state: dict) -> bool: async def _startswith(bot: "Bot", event: "Event", state: State) -> bool:
return event.plain_text.startswith(msg) return event.plain_text.startswith(msg)
return Rule(_startswith) return Rule(_startswith)
@ -193,7 +197,7 @@ def endswith(msg: str) -> Rule:
* ``msg: str``: 消息结尾字符串 * ``msg: str``: 消息结尾字符串
""" """
async def _endswith(bot: Bot, event: Event, state: dict) -> bool: async def _endswith(bot: "Bot", event: "Event", state: State) -> bool:
return event.plain_text.endswith(msg) return event.plain_text.endswith(msg)
return Rule(_endswith) return Rule(_endswith)
@ -210,7 +214,7 @@ def keyword(*keywords: str) -> Rule:
* ``*keywords: str``: 关键词 * ``*keywords: str``: 关键词
""" """
async def _keyword(bot: Bot, event: Event, state: dict) -> bool: async def _keyword(bot: "Bot", event: "Event", state: State) -> bool:
return bool(event.plain_text and return bool(event.plain_text and
any(keyword in event.plain_text for keyword in keywords)) any(keyword in event.plain_text for keyword in keywords))
@ -256,7 +260,7 @@ def command(*cmds: Union[str, Tuple[str, ...]]) -> Rule:
for start, sep in product(command_start, command_sep): for start, sep in product(command_start, command_sep):
TrieRule.add_prefix(f"{start}{sep.join(command)}", command) TrieRule.add_prefix(f"{start}{sep.join(command)}", command)
async def _command(bot: Bot, event: Event, state: dict) -> bool: async def _command(bot: "Bot", event: "Event", state: State) -> bool:
return state["_prefix"]["command"] in commands return state["_prefix"]["command"] in commands
return Rule(_command) return Rule(_command)
@ -282,7 +286,7 @@ def regex(regex: str, flags: Union[int, re.RegexFlag] = 0) -> Rule:
pattern = re.compile(regex, flags) pattern = re.compile(regex, flags)
async def _regex(bot: Bot, event: Event, state: dict) -> bool: async def _regex(bot: "Bot", event: "Event", state: State) -> bool:
matched = pattern.search(str(event.message)) matched = pattern.search(str(event.message))
if matched: if matched:
state["_matched"] = matched.group() state["_matched"] = matched.group()
@ -305,7 +309,7 @@ def to_me() -> Rule:
* *
""" """
async def _to_me(bot: Bot, event: Event, state: dict) -> bool: async def _to_me(bot: "Bot", event: "Event", state: State) -> bool:
return bool(event.to_me) return bool(event.to_me)
return Rule(_to_me) return Rule(_to_me)

View File

@ -29,7 +29,7 @@ if TYPE_CHECKING:
from nonebot.drivers import BaseDriver, BaseWebSocket from nonebot.drivers import BaseDriver, BaseWebSocket
from nonebot.permission import Permission as PermissionClass from nonebot.permission import Permission as PermissionClass
from nonebot.adapters import BaseBot, BaseEvent, BaseMessage, BaseMessageSegment from nonebot.adapters import BaseBot, BaseEvent, BaseMessage, BaseMessageSegment
from nonebot.matcher import Matcher as MatcherClass, MatcherGroup as MatcherGroupClass from nonebot.matcher import Matcher as MatcherClass
def overrides(InterfaceClass: object): def overrides(InterfaceClass: object):
@ -92,34 +92,42 @@ MessageSegment = TypeVar("MessageSegment", bound="BaseMessageSegment")
所有 MessageSegment 的基类 所有 MessageSegment 的基类
""" """
EventPreProcessor = Callable[[Bot, Event, dict], Awaitable[None]] State = Dict[Any, Any]
""" """
:类型: ``Callable[[Bot, Event, dict], Awaitable[None]]`` :类型: ``Dict[Any, Any]``
:说明:
事件处理状态 State 类型
"""
EventPreProcessor = Callable[[Bot, Event, State], Awaitable[None]]
"""
:类型: ``Callable[[Bot, Event, State], Awaitable[None]]``
:说明: :说明:
事件预处理函数 EventPreProcessor 类型 事件预处理函数 EventPreProcessor 类型
""" """
EventPostProcessor = Callable[[Bot, Event, dict], Awaitable[None]] EventPostProcessor = Callable[[Bot, Event, State], Awaitable[None]]
""" """
:类型: ``Callable[[Bot, Event, dict], Awaitable[None]]`` :类型: ``Callable[[Bot, Event, State], Awaitable[None]]``
:说明: :说明:
事件预处理函数 EventPostProcessor 类型 事件预处理函数 EventPostProcessor 类型
""" """
RunPreProcessor = Callable[["Matcher", Bot, Event, dict], Awaitable[None]] RunPreProcessor = Callable[["Matcher", Bot, Event, State], Awaitable[None]]
""" """
:类型: ``Callable[[Matcher, Bot, Event, dict], Awaitable[None]]`` :类型: ``Callable[[Matcher, Bot, Event, State], Awaitable[None]]``
:说明: :说明:
事件响应器运行前预处理函数 RunPreProcessor 类型 事件响应器运行前预处理函数 RunPreProcessor 类型
""" """
RunPostProcessor = Callable[["Matcher", Optional[Exception], Bot, Event, dict], RunPostProcessor = Callable[["Matcher", Optional[Exception], Bot, Event, State],
Awaitable[None]] Awaitable[None]]
""" """
:类型: ``Callable[[Matcher, Optional[Exception], Bot, Event, dict], Awaitable[None]]`` :类型: ``Callable[[Matcher, Optional[Exception], Bot, Event, State], Awaitable[None]]``
:说明: :说明:
@ -134,14 +142,6 @@ Matcher = TypeVar("Matcher", bound="MatcherClass")
Matcher 即响应事件的处理类通过 Rule 判断是否响应事件运行 Handler Matcher 即响应事件的处理类通过 Rule 判断是否响应事件运行 Handler
""" """
MatcherGroup = TypeVar("MatcherGroup", bound="MatcherGroupClass")
"""
:类型: ``MatcherGroup``
:说明:
MatcherGroup Matcher 的集合可以共享 Handler
"""
Rule = TypeVar("Rule", bound="RuleClass") Rule = TypeVar("Rule", bound="RuleClass")
""" """
:类型: ``Rule`` :类型: ``Rule``
@ -150,9 +150,9 @@ Rule = TypeVar("Rule", bound="RuleClass")
Rule 即判断是否响应事件的处理类内部存储 RuleChecker 返回全为 True 则响应事件 Rule 即判断是否响应事件的处理类内部存储 RuleChecker 返回全为 True 则响应事件
""" """
RuleChecker = Callable[[Bot, Event, dict], Union[bool, Awaitable[bool]]] RuleChecker = Callable[[Bot, Event, State], Union[bool, Awaitable[bool]]]
""" """
:类型: ``Callable[[Bot, Event, dict], Union[bool, Awaitable[bool]]]`` :类型: ``Callable[[Bot, Event, State], Union[bool, Awaitable[bool]]]``
:说明: :说明:
@ -174,17 +174,17 @@ PermissionChecker = Callable[[Bot, Event], Union[bool, Awaitable[bool]]]
RuleChecker 即判断是否响应消息的处理函数 RuleChecker 即判断是否响应消息的处理函数
""" """
Handler = Callable[[Bot, Event, dict], Awaitable[None]] Handler = Callable[[Bot, Event, State], Awaitable[None]]
""" """
:类型: ``Callable[[Bot, Event, dict], Awaitable[None]]`` :类型: ``Callable[[Bot, Event, State], Awaitable[None]]``
:说明: :说明:
Handler 即事件的处理函数 Handler 即事件的处理函数
""" """
ArgsParser = Callable[[Bot, Event, dict], Awaitable[None]] ArgsParser = Callable[[Bot, Event, State], Awaitable[None]]
""" """
:类型: ``Callable[[Bot, Event, dict], Awaitable[None]]`` :类型: ``Callable[[Bot, Event, State], Awaitable[None]]``
:说明: :说明:

View File

@ -3,9 +3,10 @@ import json
import asyncio import asyncio
import dataclasses import dataclasses
from functools import wraps, partial from functools import wraps, partial
from typing import Any, Optional, Callable, Awaitable
from nonebot.log import logger from nonebot.log import logger
from nonebot.typing import Any, Optional, Callable, Awaitable, overrides from nonebot.typing import overrides
def escape_tag(s: str) -> str: def escape_tag(s: str) -> str: