mirror of
				https://github.com/nonebot/nonebot2.git
				synced 2025-10-29 22:16:42 +00:00 
			
		
		
		
	✨ Feature: 支持 re.Match 依赖注入 (#1950)
				
					
				
			This commit is contained in:
		| @@ -42,12 +42,6 @@ SHELL_ARGV: Literal["_argv"] = "_argv" | |||||||
|  |  | ||||||
| REGEX_MATCHED: Literal["_matched"] = "_matched" | REGEX_MATCHED: Literal["_matched"] = "_matched" | ||||||
| """正则匹配结果存储 key""" | """正则匹配结果存储 key""" | ||||||
| REGEX_STR: Literal["_matched_str"] = "_matched_str" |  | ||||||
| """正则匹配文本存储 key""" |  | ||||||
| REGEX_GROUP: Literal["_matched_groups"] = "_matched_groups" |  | ||||||
| """正则匹配 group 元组存储 key""" |  | ||||||
| REGEX_DICT: Literal["_matched_dict"] = "_matched_dict" |  | ||||||
| """正则匹配 group 字典存储 key""" |  | ||||||
| STARTSWITH_KEY: Literal["_startswith"] = "_startswith" | STARTSWITH_KEY: Literal["_startswith"] = "_startswith" | ||||||
| """响应触发前缀 key""" | """响应触发前缀 key""" | ||||||
| ENDSWITH_KEY: Literal["_endswith"] = "_endswith" | ENDSWITH_KEY: Literal["_endswith"] = "_endswith" | ||||||
|   | |||||||
| @@ -5,8 +5,7 @@ FrontMatter: | |||||||
|     description: nonebot.params 模块 |     description: nonebot.params 模块 | ||||||
| """ | """ | ||||||
|  |  | ||||||
| import warnings | from typing import Any, Dict, List, Match, Tuple, Union, Optional | ||||||
| from typing import Any, Dict, List, Tuple, Union, Optional |  | ||||||
|  |  | ||||||
| from nonebot.typing import T_State | from nonebot.typing import T_State | ||||||
| from nonebot.matcher import Matcher | from nonebot.matcher import Matcher | ||||||
| @@ -25,15 +24,12 @@ from nonebot.internal.params import MatcherParam as MatcherParam | |||||||
| from nonebot.internal.params import ExceptionParam as ExceptionParam | from nonebot.internal.params import ExceptionParam as ExceptionParam | ||||||
| from nonebot.consts import ( | from nonebot.consts import ( | ||||||
|     CMD_KEY, |     CMD_KEY, | ||||||
|     REGEX_STR, |  | ||||||
|     PREFIX_KEY, |     PREFIX_KEY, | ||||||
|     REGEX_DICT, |  | ||||||
|     SHELL_ARGS, |     SHELL_ARGS, | ||||||
|     SHELL_ARGV, |     SHELL_ARGV, | ||||||
|     CMD_ARG_KEY, |     CMD_ARG_KEY, | ||||||
|     KEYWORD_KEY, |     KEYWORD_KEY, | ||||||
|     RAW_CMD_KEY, |     RAW_CMD_KEY, | ||||||
|     REGEX_GROUP, |  | ||||||
|     ENDSWITH_KEY, |     ENDSWITH_KEY, | ||||||
|     CMD_START_KEY, |     CMD_START_KEY, | ||||||
|     FULLMATCH_KEY, |     FULLMATCH_KEY, | ||||||
| @@ -142,23 +138,17 @@ def ShellCommandArgv() -> Any: | |||||||
|     return Depends(_shell_command_argv, use_cache=False) |     return Depends(_shell_command_argv, use_cache=False) | ||||||
|  |  | ||||||
|  |  | ||||||
| def _regex_matched(state: T_State) -> str: | def _regex_matched(state: T_State) -> Match[str]: | ||||||
|     return state[REGEX_MATCHED] |     return state[REGEX_MATCHED] | ||||||
|  |  | ||||||
|  |  | ||||||
| def RegexMatched() -> str: | def RegexMatched() -> Match[str]: | ||||||
|     """正则匹配结果""" |     """正则匹配结果""" | ||||||
|     warnings.warn( |  | ||||||
|         '"RegexMatched()" will be changed to "re.Match" object, ' |  | ||||||
|         'use "RegexStr()" instead. ' |  | ||||||
|         "See https://github.com/nonebot/nonebot2/pull/1453 .", |  | ||||||
|         DeprecationWarning, |  | ||||||
|     ) |  | ||||||
|     return Depends(_regex_matched, use_cache=False) |     return Depends(_regex_matched, use_cache=False) | ||||||
|  |  | ||||||
|  |  | ||||||
| def _regex_str(state: T_State) -> str: | def _regex_str(state: T_State) -> str: | ||||||
|     return state[REGEX_STR] |     return _regex_matched(state).group() | ||||||
|  |  | ||||||
|  |  | ||||||
| def RegexStr() -> str: | def RegexStr() -> str: | ||||||
| @@ -167,7 +157,7 @@ def RegexStr() -> str: | |||||||
|  |  | ||||||
|  |  | ||||||
| def _regex_group(state: T_State) -> Tuple[Any, ...]: | def _regex_group(state: T_State) -> Tuple[Any, ...]: | ||||||
|     return state[REGEX_GROUP] |     return _regex_matched(state).groups() | ||||||
|  |  | ||||||
|  |  | ||||||
| def RegexGroup() -> Tuple[Any, ...]: | def RegexGroup() -> Tuple[Any, ...]: | ||||||
| @@ -176,7 +166,7 @@ def RegexGroup() -> Tuple[Any, ...]: | |||||||
|  |  | ||||||
|  |  | ||||||
| def _regex_dict(state: T_State) -> Dict[str, Any]: | def _regex_dict(state: T_State) -> Dict[str, Any]: | ||||||
|     return state[REGEX_DICT] |     return _regex_matched(state).groupdict() | ||||||
|  |  | ||||||
|  |  | ||||||
| def RegexDict() -> Dict[str, Any]: | def RegexDict() -> Dict[str, Any]: | ||||||
|   | |||||||
| @@ -44,15 +44,12 @@ from nonebot.adapters import Bot, Event, Message, MessageSegment | |||||||
| from nonebot.params import Command, EventToMe, CommandArg, CommandWhitespace | from nonebot.params import Command, EventToMe, CommandArg, CommandWhitespace | ||||||
| from nonebot.consts import ( | from nonebot.consts import ( | ||||||
|     CMD_KEY, |     CMD_KEY, | ||||||
|     REGEX_STR, |  | ||||||
|     PREFIX_KEY, |     PREFIX_KEY, | ||||||
|     REGEX_DICT, |  | ||||||
|     SHELL_ARGS, |     SHELL_ARGS, | ||||||
|     SHELL_ARGV, |     SHELL_ARGV, | ||||||
|     CMD_ARG_KEY, |     CMD_ARG_KEY, | ||||||
|     KEYWORD_KEY, |     KEYWORD_KEY, | ||||||
|     RAW_CMD_KEY, |     RAW_CMD_KEY, | ||||||
|     REGEX_GROUP, |  | ||||||
|     ENDSWITH_KEY, |     ENDSWITH_KEY, | ||||||
|     CMD_START_KEY, |     CMD_START_KEY, | ||||||
|     FULLMATCH_KEY, |     FULLMATCH_KEY, | ||||||
| @@ -678,10 +675,7 @@ class RegexRule: | |||||||
|         except Exception: |         except Exception: | ||||||
|             return False |             return False | ||||||
|         if matched := re.search(self.regex, str(msg), self.flags): |         if matched := re.search(self.regex, str(msg), self.flags): | ||||||
|             state[REGEX_MATCHED] = matched.group() |             state[REGEX_MATCHED] = matched | ||||||
|             state[REGEX_STR] = matched.group() |  | ||||||
|             state[REGEX_GROUP] = matched.groups() |  | ||||||
|             state[REGEX_DICT] = matched.groupdict() |  | ||||||
|             return True |             return True | ||||||
|         else: |         else: | ||||||
|             return False |             return False | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| from typing import List, Tuple | from typing import List, Match, Tuple | ||||||
|  |  | ||||||
| from nonebot.typing import T_State | from nonebot.typing import T_State | ||||||
| from nonebot.adapters import Message | from nonebot.adapters import Message | ||||||
| @@ -73,12 +73,12 @@ async def regex_group(regex_group: Tuple = RegexGroup()) -> Tuple: | |||||||
|     return regex_group |     return regex_group | ||||||
|  |  | ||||||
|  |  | ||||||
| async def regex_matched(regex_matched: str = RegexMatched()) -> str: | async def regex_matched(regex_matched: Match[str] = RegexMatched()) -> Match[str]: | ||||||
|     return regex_matched |     return regex_matched | ||||||
|  |  | ||||||
|  |  | ||||||
| async def regex_str(regex_matched: str = RegexStr()) -> str: | async def regex_str(regex_str: str = RegexStr()) -> str: | ||||||
|     return regex_matched |     return regex_str | ||||||
|  |  | ||||||
|  |  | ||||||
| async def startswith(startswith: str = Startswith()) -> str: | async def startswith(startswith: str = Startswith()) -> str: | ||||||
|   | |||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | import re | ||||||
|  |  | ||||||
| import pytest | import pytest | ||||||
| from nonebug import App | from nonebug import App | ||||||
|  |  | ||||||
| @@ -16,15 +18,12 @@ from nonebot.params import ( | |||||||
| ) | ) | ||||||
| from nonebot.consts import ( | from nonebot.consts import ( | ||||||
|     CMD_KEY, |     CMD_KEY, | ||||||
|     REGEX_STR, |  | ||||||
|     PREFIX_KEY, |     PREFIX_KEY, | ||||||
|     REGEX_DICT, |  | ||||||
|     SHELL_ARGS, |     SHELL_ARGS, | ||||||
|     SHELL_ARGV, |     SHELL_ARGV, | ||||||
|     CMD_ARG_KEY, |     CMD_ARG_KEY, | ||||||
|     KEYWORD_KEY, |     KEYWORD_KEY, | ||||||
|     RAW_CMD_KEY, |     RAW_CMD_KEY, | ||||||
|     REGEX_GROUP, |  | ||||||
|     ENDSWITH_KEY, |     ENDSWITH_KEY, | ||||||
|     CMD_START_KEY, |     CMD_START_KEY, | ||||||
|     FULLMATCH_KEY, |     FULLMATCH_KEY, | ||||||
| @@ -226,6 +225,7 @@ async def test_state(app: App): | |||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     fake_message = make_fake_message()("text") |     fake_message = make_fake_message()("text") | ||||||
|  |     fake_matched = re.match(r"\[cq:(?P<type>.*?),(?P<arg>.*?)\]", "[cq:test,arg=value]") | ||||||
|     fake_state = { |     fake_state = { | ||||||
|         PREFIX_KEY: { |         PREFIX_KEY: { | ||||||
|             CMD_KEY: ("cmd",), |             CMD_KEY: ("cmd",), | ||||||
| @@ -236,10 +236,7 @@ async def test_state(app: App): | |||||||
|         }, |         }, | ||||||
|         SHELL_ARGV: ["-h"], |         SHELL_ARGV: ["-h"], | ||||||
|         SHELL_ARGS: {"help": True}, |         SHELL_ARGS: {"help": True}, | ||||||
|         REGEX_MATCHED: "[cq:test,arg=value]", |         REGEX_MATCHED: fake_matched, | ||||||
|         REGEX_STR: "[cq:test,arg=value]", |  | ||||||
|         REGEX_GROUP: ("test", "arg=value"), |  | ||||||
|         REGEX_DICT: {"type": "test", "arg": "value"}, |  | ||||||
|         STARTSWITH_KEY: "startswith", |         STARTSWITH_KEY: "startswith", | ||||||
|         ENDSWITH_KEY: "endswith", |         ENDSWITH_KEY: "endswith", | ||||||
|         FULLMATCH_KEY: "fullmatch", |         FULLMATCH_KEY: "fullmatch", | ||||||
| @@ -312,19 +309,19 @@ async def test_state(app: App): | |||||||
|         regex_str, allow_types=[StateParam, DependParam] |         regex_str, allow_types=[StateParam, DependParam] | ||||||
|     ) as ctx: |     ) as ctx: | ||||||
|         ctx.pass_params(state=fake_state) |         ctx.pass_params(state=fake_state) | ||||||
|         ctx.should_return(fake_state[REGEX_STR]) |         ctx.should_return("[cq:test,arg=value]") | ||||||
|  |  | ||||||
|     async with app.test_dependent( |     async with app.test_dependent( | ||||||
|         regex_group, allow_types=[StateParam, DependParam] |         regex_group, allow_types=[StateParam, DependParam] | ||||||
|     ) as ctx: |     ) as ctx: | ||||||
|         ctx.pass_params(state=fake_state) |         ctx.pass_params(state=fake_state) | ||||||
|         ctx.should_return(fake_state[REGEX_GROUP]) |         ctx.should_return(("test", "arg=value")) | ||||||
|  |  | ||||||
|     async with app.test_dependent( |     async with app.test_dependent( | ||||||
|         regex_dict, allow_types=[StateParam, DependParam] |         regex_dict, allow_types=[StateParam, DependParam] | ||||||
|     ) as ctx: |     ) as ctx: | ||||||
|         ctx.pass_params(state=fake_state) |         ctx.pass_params(state=fake_state) | ||||||
|         ctx.should_return(fake_state[REGEX_DICT]) |         ctx.should_return({"type": "test", "arg": "arg=value"}) | ||||||
|  |  | ||||||
|     async with app.test_dependent( |     async with app.test_dependent( | ||||||
|         startswith, allow_types=[StateParam, DependParam] |         startswith, allow_types=[StateParam, DependParam] | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
|  | import re | ||||||
| import sys | import sys | ||||||
| from typing import Dict, Tuple, Union, Optional | from typing import Match, Tuple, Union, Optional | ||||||
|  |  | ||||||
| import pytest | import pytest | ||||||
| from nonebug import App | from nonebug import App | ||||||
| @@ -9,14 +10,11 @@ from utils import make_fake_event, make_fake_message | |||||||
| from nonebot.exception import ParserExit, SkippedException | from nonebot.exception import ParserExit, SkippedException | ||||||
| from nonebot.consts import ( | from nonebot.consts import ( | ||||||
|     CMD_KEY, |     CMD_KEY, | ||||||
|     REGEX_STR, |  | ||||||
|     PREFIX_KEY, |     PREFIX_KEY, | ||||||
|     REGEX_DICT, |  | ||||||
|     SHELL_ARGS, |     SHELL_ARGS, | ||||||
|     SHELL_ARGV, |     SHELL_ARGV, | ||||||
|     CMD_ARG_KEY, |     CMD_ARG_KEY, | ||||||
|     KEYWORD_KEY, |     KEYWORD_KEY, | ||||||
|     REGEX_GROUP, |  | ||||||
|     ENDSWITH_KEY, |     ENDSWITH_KEY, | ||||||
|     FULLMATCH_KEY, |     FULLMATCH_KEY, | ||||||
|     REGEX_MATCHED, |     REGEX_MATCHED, | ||||||
| @@ -414,21 +412,18 @@ async def test_shell_command(): | |||||||
|  |  | ||||||
| @pytest.mark.asyncio | @pytest.mark.asyncio | ||||||
| @pytest.mark.parametrize( | @pytest.mark.parametrize( | ||||||
|     "pattern, type, text, expected, matched, string, group, dict", |     "pattern, type, text, expected, matched", | ||||||
|     [ |     [ | ||||||
|         ( |         ( | ||||||
|             r"(?P<key>key\d)", |             r"(?P<key>key\d)", | ||||||
|             "message", |             "message", | ||||||
|             "_key1_", |             "_key1_", | ||||||
|             True, |             True, | ||||||
|             "key1", |             re.search(r"(?P<key>key\d)", "_key1_"), | ||||||
|             "key1", |  | ||||||
|             ("key1",), |  | ||||||
|             {"key": "key1"}, |  | ||||||
|         ), |         ), | ||||||
|         (r"foo", "message", None, False, None, None, None, None), |         (r"foo", "message", None, False, None), | ||||||
|         (r"foo", "notice", "foo", True, "foo", "foo", tuple(), {}), |         (r"foo", "notice", "foo", True, re.search(r"foo", "foo")), | ||||||
|         (r"foo", "notice", "bar", False, None, None, None, None), |         (r"foo", "notice", "bar", False, None), | ||||||
|     ], |     ], | ||||||
| ) | ) | ||||||
| async def test_regex( | async def test_regex( | ||||||
| @@ -436,10 +431,7 @@ async def test_regex( | |||||||
|     type: str, |     type: str, | ||||||
|     text: Optional[str], |     text: Optional[str], | ||||||
|     expected: bool, |     expected: bool, | ||||||
|     matched: Optional[str], |     matched: Optional[Match[str]], | ||||||
|     string: Optional[str], |  | ||||||
|     group: Optional[Tuple[str, ...]], |  | ||||||
|     dict: Optional[Dict[str, str]], |  | ||||||
| ): | ): | ||||||
|     test_regex = regex(pattern) |     test_regex = regex(pattern) | ||||||
|     dependent = list(test_regex.checkers)[0] |     dependent = list(test_regex.checkers)[0] | ||||||
| @@ -452,10 +444,13 @@ async def test_regex( | |||||||
|     event = make_fake_event(_type=type, _message=message)() |     event = make_fake_event(_type=type, _message=message)() | ||||||
|     state = {} |     state = {} | ||||||
|     assert await dependent(event=event, state=state) == expected |     assert await dependent(event=event, state=state) == expected | ||||||
|     assert state.get(REGEX_MATCHED) == matched |     result: Optional[Match[str]] = state.get(REGEX_MATCHED) | ||||||
|     assert state.get(REGEX_STR) == string |     if matched is None: | ||||||
|     assert state.get(REGEX_GROUP) == group |         assert result is None | ||||||
|     assert state.get(REGEX_DICT) == dict |     else: | ||||||
|  |         assert isinstance(result, Match) | ||||||
|  |         assert result.group() == matched.group() | ||||||
|  |         assert result.span() == matched.span() | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.asyncio | @pytest.mark.asyncio | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user