diff --git a/nonebot/plugin/__init__.py b/nonebot/plugin/__init__.py index a04c6a51..b169b278 100644 --- a/nonebot/plugin/__init__.py +++ b/nonebot/plugin/__init__.py @@ -290,6 +290,7 @@ def on_request(rule: Optional[Union[Rule, T_RuleChecker]] = None, def on_startswith(msg: str, rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = None, + ignorecase: bool = False, **kwargs) -> Type[Matcher]: """ :说明: @@ -300,6 +301,7 @@ def on_startswith(msg: str, * ``msg: str``: 指定消息开头内容 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 + * ``ignorecase: bool``: 是否忽略大小写 * ``permission: Optional[Permission]``: 事件响应权限 * ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``temp: bool``: 是否为临时事件响应器(仅执行一次) @@ -312,11 +314,12 @@ def on_startswith(msg: str, - ``Type[Matcher]`` """ - return on_message(startswith(msg) & rule, **kwargs) + return on_message(startswith(msg, ignorecase) & rule, **kwargs) def on_endswith(msg: str, rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = None, + ignorecase: bool = False, **kwargs) -> Type[Matcher]: """ :说明: @@ -327,6 +330,7 @@ def on_endswith(msg: str, * ``msg: str``: 指定消息结尾内容 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 + * ``ignorecase: bool``: 是否忽略大小写 * ``permission: Optional[Permission]``: 事件响应权限 * ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 * ``temp: bool``: 是否为临时事件响应器(仅执行一次) @@ -339,7 +343,7 @@ def on_endswith(msg: str, - ``Type[Matcher]`` """ - return on_message(endswith(msg) & rule, **kwargs) + return on_message(endswith(msg, ignorecase) & rule, **kwargs) def on_keyword(keywords: Set[str], @@ -552,7 +556,7 @@ class CommandGroup: :参数: * ``cmd: Union[str, Tuple[str, ...]]``: 命令前缀 - * ``**kwargs``: 其他传递给 ``on_command`` 的参数,将会覆盖命令组默认值 + * ``**kwargs``: 其他传递给 ``on_shell_command`` 的参数,将会覆盖命令组默认值 :返回: @@ -637,6 +641,7 @@ class MatcherGroup: final_kwargs = self.base_kwargs.copy() final_kwargs.update(kwargs) final_kwargs.pop("type", None) + final_kwargs.pop("permission", None) matcher = on_metaevent(**final_kwargs) self.matchers.append(matcher) return matcher @@ -732,6 +737,7 @@ class MatcherGroup: :参数: * ``msg: str``: 指定消息开头内容 + * ``ignorecase: bool``: 是否忽略大小写 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``permission: Optional[Permission]``: 事件响应权限 * ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 @@ -761,6 +767,7 @@ class MatcherGroup: :参数: * ``msg: str``: 指定消息结尾内容 + * ``ignorecase: bool``: 是否忽略大小写 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``permission: Optional[Permission]``: 事件响应权限 * ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 diff --git a/nonebot/plugin/__init__.pyi b/nonebot/plugin/__init__.pyi index bda05b77..7b2cbe50 100644 --- a/nonebot/plugin/__init__.pyi +++ b/nonebot/plugin/__init__.pyi @@ -1,7 +1,7 @@ import re from types import ModuleType -from contextvars import ContextVar -from typing import Any, Set, List, Dict, Type, Tuple, Union, Optional +from dataclasses import dataclass +from typing import Set, List, Dict, Type, Tuple, Union, Optional, TYPE_CHECKING from nonebot.matcher import Matcher from nonebot.handler import Handler @@ -9,32 +9,28 @@ from nonebot.permission import Permission from nonebot.rule import Rule, ArgumentParser from nonebot.typing import T_State, T_StateFactory, T_Handler, T_RuleChecker +from .export import Export, export +from .manager import PluginManager + plugins: Dict[str, "Plugin"] = ... - -_export: ContextVar["Export"] = ... -_tmp_matchers: ContextVar[Set[Type[Matcher]]] = ... - - -class Export(dict): - - def __call__(self, func, **kwargs): - ... - - def __setattr__(self, name, value): - ... - - def __getattr__(self, name): - ... +PLUGIN_NAMESPACE: str = ... +@dataclass(eq=False) class Plugin(object): name: str module: ModuleType - matcher: Set[Type[Matcher]] - export: Export + + @property + def export(self) -> Export: + ... + + @property + def matcher(self) -> Set[Type[Matcher]]: + ... -def on(type: str = ..., +def on(type: str = "", rule: Optional[Union[Rule, T_RuleChecker]] = ..., permission: Optional[Permission] = ..., *, @@ -96,6 +92,7 @@ def on_request(rule: Optional[Union[Rule, T_RuleChecker]] = ..., def on_startswith( msg: str, rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = ..., + ignorecase: bool = ..., *, permission: Optional[Permission] = ..., handlers: Optional[List[Union[T_Handler, Handler]]] = ..., @@ -109,6 +106,7 @@ def on_startswith( def on_endswith(msg: str, rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = ..., + ignorecase: bool = ..., *, permission: Optional[Permission] = ..., handlers: Optional[List[Union[T_Handler, Handler]]] = ..., @@ -121,7 +119,7 @@ def on_endswith(msg: str, def on_keyword(keywords: Set[str], - rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = ..., + rule: Optional[Union[Rule, T_RuleChecker]] = ..., *, permission: Optional[Permission] = ..., handlers: Optional[List[Union[T_Handler, Handler]]] = ..., @@ -147,16 +145,24 @@ def on_command(cmd: Union[str, Tuple[str, ...]], ... -def on_shell_command(cmd: Union[str, Tuple[str, ...]], - rule: Optional[Union[Rule, T_RuleChecker]] = None, - aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = None, - parser: Optional[ArgumentParser] = None, - **kwargs) -> Type[Matcher]: +def on_shell_command( + cmd: Union[str, Tuple[str, ...]], + rule: Optional[Union[Rule, T_RuleChecker]] = ..., + aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ..., + parser: Optional[ArgumentParser] = ..., + *, + permission: Optional[Permission] = ..., + handlers: Optional[List[Union[T_Handler, Handler]]] = ..., + temp: bool = ..., + priority: int = ..., + block: bool = ..., + state: Optional[T_State] = ..., + state_factory: Optional[T_StateFactory] = ...) -> Type[Matcher]: ... def on_regex(pattern: str, - flags: Union[int, re.RegexFlag] = 0, + flags: Union[int, re.RegexFlag] = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ..., *, permission: Optional[Permission] = ..., @@ -169,67 +175,26 @@ def on_regex(pattern: str, ... -def load_plugin(module_path: str) -> Optional[Plugin]: - ... - - -def load_plugins(*plugin_dir: str) -> Set[Plugin]: - ... - - -def load_all_plugins(module_path: Set[str], - plugin_dir: Set[str]) -> Set[Plugin]: - ... - - -def load_from_json(file_path: str, encoding: str = ...) -> Set[Plugin]: - ... - - -def load_from_toml(file_path: str, encoding: str = ...) -> Set[Plugin]: - ... - - -def load_builtin_plugins(name: str = ...): - ... - - -def get_plugin(name: str) -> Optional[Plugin]: - ... - - -def get_loaded_plugins() -> Set[Plugin]: - ... - - -def export() -> Export: - ... - - -def require(name: str) -> Export: - ... - - class CommandGroup: def __init__(self, cmd: Union[str, Tuple[str, ...]], + *, rule: Optional[Union[Rule, T_RuleChecker]] = ..., permission: Optional[Permission] = ..., - *, handlers: Optional[List[Union[T_Handler, Handler]]] = ..., temp: bool = ..., priority: int = ..., block: bool = ..., - state: Optional[T_State] = ...): - self.basecmd: Tuple[str, ...] = ... - self.base_kwargs: Dict[str, Any] = ... + state: Optional[T_State] = ..., + state_factory: Optional[T_StateFactory] = ...): + ... def command(self, cmd: Union[str, Tuple[str, ...]], *, + aliases: Optional[Set[Union[str, Tuple[str, ...]]]], rule: Optional[Union[Rule, T_RuleChecker]] = ..., - aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ..., permission: Optional[Permission] = ..., handlers: Optional[List[Union[T_Handler, Handler]]] = ..., temp: bool = ..., @@ -244,7 +209,7 @@ class CommandGroup: cmd: Union[str, Tuple[str, ...]], *, rule: Optional[Union[Rule, T_RuleChecker]] = ..., - aliases: Optional[Set[Union[str, Tuple[str, ...]]]] = ..., + aliases: Optional[Set[Union[str, Tuple[str, ...]]]], parser: Optional[ArgumentParser] = ..., permission: Optional[Permission] = ..., handlers: Optional[List[Union[T_Handler, Handler]]] = ..., @@ -267,7 +232,8 @@ class MatcherGroup: temp: bool = ..., priority: int = ..., block: bool = ..., - state: Optional[T_State] = ...): + state: Optional[T_State] = ..., + state_factory: Optional[T_StateFactory] = ...): ... def on(self, @@ -286,49 +252,49 @@ class MatcherGroup: def on_metaevent( self, *, - rule: Optional[Union[Rule, T_RuleChecker]] = None, - handlers: Optional[List[Union[T_Handler, Handler]]] = None, - temp: bool = False, - priority: int = 1, - block: bool = False, - state: Optional[T_State] = None, + rule: Optional[Union[Rule, T_RuleChecker]] = ..., + handlers: Optional[List[Union[T_Handler, Handler]]] = ..., + temp: bool = ..., + priority: int = ..., + block: bool = ..., + state: Optional[T_State] = ..., state_factory: Optional[T_StateFactory] = ...) -> Type[Matcher]: ... def on_message( self, *, - rule: Optional[Union[Rule, T_RuleChecker]] = None, - permission: Optional[Permission] = None, - handlers: Optional[List[Union[T_Handler, Handler]]] = None, - temp: bool = False, - priority: int = 1, - block: bool = True, - state: Optional[T_State] = None, + rule: Optional[Union[Rule, T_RuleChecker]] = ..., + permission: Optional[Permission] = ..., + handlers: Optional[List[Union[T_Handler, Handler]]] = ..., + temp: bool = ..., + priority: int = ..., + block: bool = ..., + state: Optional[T_State] = ..., state_factory: Optional[T_StateFactory] = ...) -> Type[Matcher]: ... def on_notice( self, *, - rule: Optional[Union[Rule, T_RuleChecker]] = None, - handlers: Optional[List[Union[T_Handler, Handler]]] = None, - temp: bool = False, - priority: int = 1, - block: bool = False, - state: Optional[T_State] = None, + rule: Optional[Union[Rule, T_RuleChecker]] = ..., + handlers: Optional[List[Union[T_Handler, Handler]]] = ..., + temp: bool = ..., + priority: int = ..., + block: bool = ..., + state: Optional[T_State] = ..., state_factory: Optional[T_StateFactory] = ...) -> Type[Matcher]: ... def on_request( self, *, - rule: Optional[Union[Rule, T_RuleChecker]] = None, - handlers: Optional[List[Union[T_Handler, Handler]]] = None, - temp: bool = False, - priority: int = 1, - block: bool = False, - state: Optional[T_State] = None, + rule: Optional[Union[Rule, T_RuleChecker]] = ..., + handlers: Optional[List[Union[T_Handler, Handler]]] = ..., + temp: bool = ..., + priority: int = ..., + block: bool = ..., + state: Optional[T_State] = ..., state_factory: Optional[T_StateFactory] = ...) -> Type[Matcher]: ... @@ -336,7 +302,8 @@ class MatcherGroup: self, msg: str, *, - rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = ..., + ignorecase: bool = ..., + rule: Optional[Union[Rule, T_RuleChecker]] = ..., permission: Optional[Permission] = ..., handlers: Optional[List[Union[T_Handler, Handler]]] = ..., temp: bool = ..., @@ -350,7 +317,8 @@ class MatcherGroup: self, msg: str, *, - rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = ..., + ignorecase: bool = ..., + rule: Optional[Union[Rule, T_RuleChecker]] = ..., permission: Optional[Permission] = ..., handlers: Optional[List[Union[T_Handler, Handler]]] = ..., temp: bool = ..., @@ -364,7 +332,7 @@ class MatcherGroup: self, keywords: Set[str], *, - rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = ..., + rule: Optional[Union[Rule, T_RuleChecker]] = ..., permission: Optional[Permission] = ..., handlers: Optional[List[Union[T_Handler, Handler]]] = ..., temp: bool = ..., @@ -408,7 +376,7 @@ class MatcherGroup: def on_regex( self, pattern: str, - flags: Union[int, re.RegexFlag] = 0, + flags: Union[int, re.RegexFlag] = ..., *, rule: Optional[Union[Rule, T_RuleChecker]] = ..., permission: Optional[Permission] = ..., @@ -419,3 +387,40 @@ class MatcherGroup: state: Optional[T_State] = ..., state_factory: Optional[T_StateFactory] = ...) -> Type[Matcher]: ... + + +def load_plugin(module_path: str) -> Optional[Plugin]: + ... + + +def load_plugins(*plugin_dir: str) -> Set[Plugin]: + ... + + +def load_all_plugins(module_path: Set[str], + plugin_dir: Set[str]) -> Set[Plugin]: + ... + + +def load_from_json(file_path: str, encoding: str = ...) -> Set[Plugin]: + ... + + +def load_from_toml(file_path: str, encoding: str = ...) -> Set[Plugin]: + ... + + +def load_builtin_plugins(name: str = ...) -> Optional[Plugin]: + ... + + +def get_plugin(name: str) -> Optional[Plugin]: + ... + + +def get_loaded_plugins() -> Set[Plugin]: + ... + + +def require(name: str) -> Optional[Export]: + ... diff --git a/nonebot/rule.py b/nonebot/rule.py index 72af1601..20f037d7 100644 --- a/nonebot/rule.py +++ b/nonebot/rule.py @@ -175,7 +175,7 @@ class TrieRule: }) -def startswith(msg: str) -> Rule: +def startswith(msg: str, ignorecase: bool = False) -> Rule: """ :说明: @@ -186,16 +186,19 @@ def startswith(msg: str) -> Rule: * ``msg: str``: 消息开头字符串 """ + pattern = re.compile(f"^{re.escape(msg)}", + re.IGNORECASE if ignorecase else 0) + async def _startswith(bot: "Bot", event: "Event", state: T_State) -> bool: if event.get_type() != "message": return False text = event.get_plaintext() - return text.startswith(msg) + return bool(pattern.match(text)) return Rule(_startswith) -def endswith(msg: str) -> Rule: +def endswith(msg: str, ignorecase: bool = False) -> Rule: """ :说明: @@ -205,11 +208,14 @@ def endswith(msg: str) -> Rule: * ``msg: str``: 消息结尾字符串 """ + pattern = re.compile(f"{re.escape(msg)}$", + re.IGNORECASE if ignorecase else 0) async def _endswith(bot: "Bot", event: "Event", state: T_State) -> bool: if event.get_type() != "message": return False - return event.get_plaintext().endswith(msg) + text = event.get_plaintext() + return bool(pattern.match(text)) return Rule(_endswith)