From c402b7599f58c994f3959a2e448aecb6bddd9c08 Mon Sep 17 00:00:00 2001 From: yanyongyu Date: Sat, 3 Apr 2021 17:32:01 +0800 Subject: [PATCH 001/196] :bug: fix missing matcher when load external plugin with dot --- nonebot/plugin/__init__.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/nonebot/plugin/__init__.py b/nonebot/plugin/__init__.py index 9e5f682009d2..a04c6a51a7d3 100644 --- a/nonebot/plugin/__init__.py +++ b/nonebot/plugin/__init__.py @@ -7,9 +7,10 @@ import re import json from types import ModuleType +from functools import reduce from dataclasses import dataclass from collections import defaultdict -from contextvars import Context, ContextVar, copy_context +from contextvars import Context, copy_context from typing import Any, Set, List, Dict, Type, Tuple, Union, Optional, TYPE_CHECKING import tomlkit @@ -49,11 +50,14 @@ class Plugin(object): - **类型**: ``ModuleType`` - **说明**: 插件模块对象 """ - export: Export - """ - - **类型**: ``Export`` - - **说明**: 插件内定义的导出内容 - """ + + @property + def export(self) -> Export: + """ + - **类型**: ``Export`` + - **说明**: 插件内定义的导出内容 + """ + return getattr(self.module, "__export__", Export()) @property def matcher(self) -> Set[Type[Matcher]]: @@ -61,13 +65,15 @@ def matcher(self) -> Set[Type[Matcher]]: - **类型**: ``Set[Type[Matcher]]`` - **说明**: 插件内定义的 ``Matcher`` """ - return _plugin_matchers[self.name] + return reduce( + lambda x, y: x | _plugin_matchers[y], + filter(lambda x: x.startswith(self.name), _plugin_matchers.keys()), + set()) def _store_matcher(matcher: Type[Matcher]): if matcher.module: - plugin_name = matcher.module.split(".", maxsplit=1)[0] - _plugin_matchers[plugin_name].add(matcher) + _plugin_matchers[matcher.module].add(matcher) def on(type: str = "", @@ -928,8 +934,7 @@ def _load_plugin(manager: PluginManager, plugin_name: str) -> Optional[Plugin]: try: module = manager.load_plugin(plugin_name) - plugin = Plugin(plugin_name, module, - getattr(module, "__export__", Export())) + plugin = Plugin(plugin_name, module) plugins[plugin_name] = plugin logger.opt( colors=True).info(f'Succeeded to import "{plugin_name}"') From 0d467d9275bbf19638a77e16c59a76c321c21b1b Mon Sep 17 00:00:00 2001 From: yanyongyu Date: Sun, 4 Apr 2021 12:19:03 +0800 Subject: [PATCH 002/196] :sparkles: add startswith endswith ignorecase option #312 --- nonebot/plugin/__init__.py | 13 ++- nonebot/plugin/__init__.pyi | 211 ++++++++++++++++++------------------ nonebot/rule.py | 14 ++- 3 files changed, 128 insertions(+), 110 deletions(-) diff --git a/nonebot/plugin/__init__.py b/nonebot/plugin/__init__.py index a04c6a51a7d3..b169b278ec59 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 @@ def shell_command(self, cmd: Union[str, Tuple[str, ...]], :参数: * ``cmd: Union[str, Tuple[str, ...]]``: 命令前缀 - * ``**kwargs``: 其他传递给 ``on_command`` 的参数,将会覆盖命令组默认值 + * ``**kwargs``: 其他传递给 ``on_shell_command`` 的参数,将会覆盖命令组默认值 :返回: @@ -637,6 +641,7 @@ def on_metaevent(self, **kwargs) -> Type[Matcher]: 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 @@ def on_startswith(self, msg: str, **kwargs) -> Type[Matcher]: :参数: * ``msg: str``: 指定消息开头内容 + * ``ignorecase: bool``: 是否忽略大小写 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``permission: Optional[Permission]``: 事件响应权限 * ``handlers: Optional[List[Union[T_Handler, Handler]]]``: 事件处理函数列表 @@ -761,6 +767,7 @@ def on_endswith(self, msg: str, **kwargs) -> Type[Matcher]: :参数: * ``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 bda05b77556a..7b2cbe507134 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 -plugins: Dict[str, "Plugin"] = ... - -_export: ContextVar["Export"] = ... -_tmp_matchers: ContextVar[Set[Type[Matcher]]] = ... +from .export import Export, export +from .manager import PluginManager +plugins: Dict[str, "Plugin"] = ... +PLUGIN_NAMESPACE: str = ... -class Export(dict): - def __call__(self, func, **kwargs): - ... +@dataclass(eq=False) +class Plugin(object): + name: str + module: ModuleType - def __setattr__(self, name, value): + @property + def export(self) -> Export: ... - def __getattr__(self, name): + @property + def matcher(self) -> Set[Type[Matcher]]: ... -class Plugin(object): - name: str - module: ModuleType - matcher: Set[Type[Matcher]] - export: Export - - -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 72af16012bf4..20f037d7b390 100644 --- a/nonebot/rule.py +++ b/nonebot/rule.py @@ -175,7 +175,7 @@ def get_value(cls, bot: "Bot", event: "Event", }) -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) From d1a438a2875d4d0e0e9c701b709f836b37debb4f Mon Sep 17 00:00:00 2001 From: yanyongyu Date: Sun, 4 Apr 2021 12:28:10 +0800 Subject: [PATCH 003/196] :alembic: support tuple prefix in startswith --- nonebot/plugin/__init__.py | 18 ++++++++++-------- nonebot/plugin/__init__.pyi | 8 ++++---- nonebot/rule.py | 21 +++++++++++++++------ 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/nonebot/plugin/__init__.py b/nonebot/plugin/__init__.py index b169b278ec59..a8e1a2db0d0f 100644 --- a/nonebot/plugin/__init__.py +++ b/nonebot/plugin/__init__.py @@ -288,7 +288,7 @@ def on_request(rule: Optional[Union[Rule, T_RuleChecker]] = None, return matcher -def on_startswith(msg: str, +def on_startswith(msg: Union[str, Tuple[str, ...]], rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = None, ignorecase: bool = False, **kwargs) -> Type[Matcher]: @@ -299,7 +299,7 @@ def on_startswith(msg: str, :参数: - * ``msg: str``: 指定消息开头内容 + * ``msg: Union[str, Tuple[str, ...]]``: 指定消息开头内容 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``ignorecase: bool``: 是否忽略大小写 * ``permission: Optional[Permission]``: 事件响应权限 @@ -317,7 +317,7 @@ def on_startswith(msg: str, return on_message(startswith(msg, ignorecase) & rule, **kwargs) -def on_endswith(msg: str, +def on_endswith(msg: Union[str, Tuple[str, ...]], rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = None, ignorecase: bool = False, **kwargs) -> Type[Matcher]: @@ -328,7 +328,7 @@ def on_endswith(msg: str, :参数: - * ``msg: str``: 指定消息结尾内容 + * ``msg: Union[str, Tuple[str, ...]]``: 指定消息结尾内容 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``ignorecase: bool``: 是否忽略大小写 * ``permission: Optional[Permission]``: 事件响应权限 @@ -728,7 +728,8 @@ def on_request(self, **kwargs) -> Type[Matcher]: self.matchers.append(matcher) return matcher - def on_startswith(self, msg: str, **kwargs) -> Type[Matcher]: + def on_startswith(self, msg: Union[str, Tuple[str, ...]], + **kwargs) -> Type[Matcher]: """ :说明: @@ -736,7 +737,7 @@ def on_startswith(self, msg: str, **kwargs) -> Type[Matcher]: :参数: - * ``msg: str``: 指定消息开头内容 + * ``msg: Union[str, Tuple[str, ...]]``: 指定消息开头内容 * ``ignorecase: bool``: 是否忽略大小写 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``permission: Optional[Permission]``: 事件响应权限 @@ -758,7 +759,8 @@ def on_startswith(self, msg: str, **kwargs) -> Type[Matcher]: self.matchers.append(matcher) return matcher - def on_endswith(self, msg: str, **kwargs) -> Type[Matcher]: + def on_endswith(self, msg: Union[str, Tuple[str, ...]], + **kwargs) -> Type[Matcher]: """ :说明: @@ -766,7 +768,7 @@ def on_endswith(self, msg: str, **kwargs) -> Type[Matcher]: :参数: - * ``msg: str``: 指定消息结尾内容 + * ``msg: Union[str, Tuple[str, ...]]``: 指定消息结尾内容 * ``ignorecase: bool``: 是否忽略大小写 * ``rule: Optional[Union[Rule, T_RuleChecker]]``: 事件响应规则 * ``permission: Optional[Permission]``: 事件响应权限 diff --git a/nonebot/plugin/__init__.pyi b/nonebot/plugin/__init__.pyi index 7b2cbe507134..d9b24f403598 100644 --- a/nonebot/plugin/__init__.pyi +++ b/nonebot/plugin/__init__.pyi @@ -90,7 +90,7 @@ def on_request(rule: Optional[Union[Rule, T_RuleChecker]] = ..., def on_startswith( - msg: str, + msg: Union[str, Tuple[str, ...]], rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = ..., ignorecase: bool = ..., *, @@ -104,7 +104,7 @@ def on_startswith( ... -def on_endswith(msg: str, +def on_endswith(msg: Union[str, Tuple[str, ...]], rule: Optional[Optional[Union[Rule, T_RuleChecker]]] = ..., ignorecase: bool = ..., *, @@ -300,7 +300,7 @@ class MatcherGroup: def on_startswith( self, - msg: str, + msg: Union[str, Tuple[str, ...]], *, ignorecase: bool = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ..., @@ -315,7 +315,7 @@ class MatcherGroup: def on_endswith( self, - msg: str, + msg: Union[str, Tuple[str, ...]], *, ignorecase: bool = ..., rule: Optional[Union[Rule, T_RuleChecker]] = ..., diff --git a/nonebot/rule.py b/nonebot/rule.py index 20f037d7b390..bbc9f34fe558 100644 --- a/nonebot/rule.py +++ b/nonebot/rule.py @@ -175,7 +175,8 @@ def get_value(cls, bot: "Bot", event: "Event", }) -def startswith(msg: str, ignorecase: bool = False) -> Rule: +def startswith(msg: Union[str, Tuple[str, ...]], + ignorecase: bool = False) -> Rule: """ :说明: @@ -185,9 +186,12 @@ def startswith(msg: str, ignorecase: bool = False) -> Rule: * ``msg: str``: 消息开头字符串 """ + if isinstance(msg, str): + msg = (msg,) - pattern = re.compile(f"^{re.escape(msg)}", - re.IGNORECASE if ignorecase else 0) + pattern = re.compile( + f"^(?:{'|'.join(re.escape(prefix) for prefix in msg)})", + re.IGNORECASE if ignorecase else 0) async def _startswith(bot: "Bot", event: "Event", state: T_State) -> bool: if event.get_type() != "message": @@ -198,7 +202,8 @@ async def _startswith(bot: "Bot", event: "Event", state: T_State) -> bool: return Rule(_startswith) -def endswith(msg: str, ignorecase: bool = False) -> Rule: +def endswith(msg: Union[str, Tuple[str, ...]], + ignorecase: bool = False) -> Rule: """ :说明: @@ -208,8 +213,12 @@ def endswith(msg: str, ignorecase: bool = False) -> Rule: * ``msg: str``: 消息结尾字符串 """ - pattern = re.compile(f"{re.escape(msg)}$", - re.IGNORECASE if ignorecase else 0) + if isinstance(msg, str): + msg = (msg,) + + pattern = re.compile( + f"(?:{'|'.join(re.escape(prefix) for prefix in msg)})$", + re.IGNORECASE if ignorecase else 0) async def _endswith(bot: "Bot", event: "Event", state: T_State) -> bool: if event.get_type() != "message": From 20e1bf962486a538300cb64757cc9e7033a5d71d Mon Sep 17 00:00:00 2001 From: StarHeartHunt Date: Mon, 5 Apr 2021 13:32:36 +0800 Subject: [PATCH 004/196] :memo: improve store display effect --- docs/.vuepress/components/Adapter.vue | 26 ++++++++++------------- docs/.vuepress/components/Bot.vue | 21 ++++++++---------- docs/.vuepress/components/Plugin.vue | 23 +++++++++----------- docs/.vuepress/components/PublishCard.vue | 2 +- docs/.vuepress/components/Store.vue | 2 +- 5 files changed, 32 insertions(+), 42 deletions(-) diff --git a/docs/.vuepress/components/Adapter.vue b/docs/.vuepress/components/Adapter.vue index 7cb4d3cc30fc..ffc4cfdbfa70 100644 --- a/docs/.vuepress/components/Adapter.vue +++ b/docs/.vuepress/components/Adapter.vue @@ -1,7 +1,7 @@ diff --git a/docs/.vuepress/components/Bot.vue b/docs/.vuepress/components/Bot.vue index 954a3ebd4083..60f6d76fe2ed 100644 --- a/docs/.vuepress/components/Bot.vue +++ b/docs/.vuepress/components/Bot.vue @@ -1,7 +1,7 @@ diff --git a/docs/.vuepress/components/Plugin.vue b/docs/.vuepress/components/Plugin.vue index 5e0131586b51..9d8677a74425 100644 --- a/docs/.vuepress/components/Plugin.vue +++ b/docs/.vuepress/components/Plugin.vue @@ -1,7 +1,7 @@ diff --git a/docs/.vuepress/components/PublishCard.vue b/docs/.vuepress/components/PublishCard.vue index 98e15bca5dbb..45440278ee77 100644 --- a/docs/.vuepress/components/PublishCard.vue +++ b/docs/.vuepress/components/PublishCard.vue @@ -28,7 +28,7 @@ {{ text }} fa-copy - Copied! + 复制成功! diff --git a/docs/.vuepress/components/Store.vue b/docs/.vuepress/components/Store.vue index be73fe653b0d..e1ca53116108 100644 --- a/docs/.vuepress/components/Store.vue +++ b/docs/.vuepress/components/Store.vue @@ -10,7 +10,7 @@ }} - + From 1c6711355e83a9f71e1d360fee02d79c2d7db542 Mon Sep 17 00:00:00 2001 From: StarHeartHunt Date: Mon, 5 Apr 2021 13:44:19 +0800 Subject: [PATCH 005/196] :art: format files --- docs/.vuepress/components/Adapter.vue | 83 +++++++++++----------- docs/.vuepress/components/Bot.vue | 84 +++++++++++------------ docs/.vuepress/components/Messenger.vue | 30 ++++---- docs/.vuepress/components/Plugin.vue | 84 +++++++++++------------ docs/.vuepress/components/PublishCard.vue | 28 ++++---- docs/.vuepress/components/Store.vue | 24 +++---- docs/advanced/permission.md | 1 - docs/advanced/scheduler.md | 2 +- docs/guide/creating-a-project.md | 4 +- docs/guide/ding-guide.md | 8 +-- 10 files changed, 174 insertions(+), 174 deletions(-) diff --git a/docs/.vuepress/components/Adapter.vue b/docs/.vuepress/components/Adapter.vue index ffc4cfdbfa70..c6a3f089cb16 100644 --- a/docs/.vuepress/components/Adapter.vue +++ b/docs/.vuepress/components/Adapter.vue @@ -82,8 +82,8 @@ color="blue darken-1" text @click=" - dialog = false; - publishAdapter(); + dialog = false + publishAdapter() " > 发布 @@ -93,13 +93,14 @@ - - + + - - - + + + diff --git a/docs/.vuepress/components/Bot.vue b/docs/.vuepress/components/Bot.vue index 60f6d76fe2ed..7f85fbb46ff7 100644 --- a/docs/.vuepress/components/Bot.vue +++ b/docs/.vuepress/components/Bot.vue @@ -68,8 +68,8 @@ color="blue darken-1" text @click=" - dialog = false; - publishBot(); + dialog = false + publishBot() " > 发布 @@ -79,14 +79,14 @@ - - - + + + - - - + + + diff --git a/docs/.vuepress/components/Messenger.vue b/docs/.vuepress/components/Messenger.vue index 030e21880ec6..7ff310d3f2aa 100644 --- a/docs/.vuepress/components/Messenger.vue +++ b/docs/.vuepress/components/Messenger.vue @@ -128,32 +128,32 @@