Feature: 支持 re.Match 依赖注入 (#1950)

This commit is contained in:
Ju4tCode 2023-04-27 21:58:56 +08:00 committed by GitHub
parent 6691f6ef70
commit 93b79ddcb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 33 additions and 63 deletions

View File

@ -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"

View File

@ -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]:

View File

@ -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

View File

@ -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:

View File

@ -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]

View File

@ -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