diff --git a/CHANGELOG.md b/CHANGELOG.md index 9975bdc5..8878562a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # 更新日志 +## Alconna 1.8.11 + +### 改进 + +- 快捷指令处理数据时会尝试把带分隔符的字符串用引号包裹 + +### 修复 + +- 修复 `Bracket Header` 的正则表达式丢失问题 + ## Alconna 1.8.10 ### 改进 diff --git a/pdm.lock b/pdm.lock index 21c923e0..ce2cc163 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev", "full"] strategy = ["cross_platform", "inherit_metadata"] lock_version = "4.4.1" -content_hash = "sha256:b65ba5e8efa9c12d2f66e509b9cb0bb0af44839c0930007bc92f2dcf2e44b484" +content_hash = "sha256:614ef678748b728ba3295731b75fc5c9d3c4db87c5f9f905520265374bb96660" [[package]] name = "arclet-alconna-tools" @@ -212,7 +212,7 @@ files = [ [[package]] name = "nepattern" -version = "0.7.0" +version = "0.7.1" requires_python = ">=3.8" summary = "a complex pattern, support typing" groups = ["default", "full"] @@ -221,8 +221,8 @@ dependencies = [ "typing-extensions>=4.5.0", ] files = [ - {file = "nepattern-0.7.0-py3-none-any.whl", hash = "sha256:6cd51145af78a7476486c9f3f3817e8c93a9f4d10e45d8cdcaed62776a9f9a3e"}, - {file = "nepattern-0.7.0.tar.gz", hash = "sha256:75c3b5b93c3ea8aaff585c282d45c1e4db0ebb92e68eecbcaddd3cb33d16dcee"}, + {file = "nepattern-0.7.1-py3-none-any.whl", hash = "sha256:e5190a79d398dce72f972ffafc413653414cca12a1dac56d38fcf070d2f034bc"}, + {file = "nepattern-0.7.1.tar.gz", hash = "sha256:14bae0dfa93241f3c2d8371cfc5e51072a186a295a7d35fbd7a60b08e83b2605"}, ] [[package]] diff --git a/src/arclet/alconna/__init__.py b/src/arclet/alconna/__init__.py index 2e4d14f4..7a2b4279 100644 --- a/src/arclet/alconna/__init__.py +++ b/src/arclet/alconna/__init__.py @@ -51,7 +51,7 @@ from .typing import UnpackVar as UnpackVar from .typing import Up as Up -__version__ = "1.8.10" +__version__ = "1.8.11" # backward compatibility AnyOne = ANY diff --git a/src/arclet/alconna/_internal/_argv.py b/src/arclet/alconna/_internal/_argv.py index ce246f53..64264f7e 100644 --- a/src/arclet/alconna/_internal/_argv.py +++ b/src/arclet/alconna/_internal/_argv.py @@ -225,6 +225,8 @@ def rollback(self, data: str | Any, replace: bool = False): return if self._sep: _current_data = self.raw_data[self.current_index] + if self._sep[0] in data and data[0] not in ("'", '"'): + data = f"\'{data}\'" self.raw_data[self.current_index] = f"{data}{self._sep[0]}{_current_data}" return if self.current_index >= 1: diff --git a/src/arclet/alconna/_internal/_handlers.py b/src/arclet/alconna/_internal/_handlers.py index 1cdc06a1..ac22dc7d 100644 --- a/src/arclet/alconna/_internal/_handlers.py +++ b/src/arclet/alconna/_internal/_handlers.py @@ -707,7 +707,13 @@ def _handle_shortcut_data(argv: Argv, data: list): argv.raw_data[i + offset] = unescape(unit.replace(f"{{*{mat[1]}}}", "".join(map(str, extend)))) data.clear() break - return [unit for i, unit in enumerate(data) if i not in record] + + def recover_quote(_unit: str): + if any(_unit.count(sep) for sep in argv.separators) and not (_unit[0] in ('"', "'") and _unit[0] == _unit[-1]): + return f'"{_unit}"' + return _unit + + return [recover_quote(unit) for i, unit in enumerate(data) if i not in record] INDEX_REG_SLOT = re.compile(r"\{(\d+)\}") diff --git a/src/arclet/alconna/_internal/_header.py b/src/arclet/alconna/_internal/_header.py index f2bab50b..b9514472 100644 --- a/src/arclet/alconna/_internal/_header.py +++ b/src/arclet/alconna/_internal/_header.py @@ -20,6 +20,19 @@ def prefixed(pat: BasePattern): return new_pat +regex_patterns = { + "str": r".+", + "int": r"\-?\d+", + "float": r"\-?\d+\.?\d*", + "number": r"\-?\d+(?:\.\d*)?", + "bool": "(?i:True|False)", + "list": r"\[.+?\]", + "tuple": r"\(.+?\)", + "set": r"\{.+?\}", + "dict": r"\{.+?\}", +} + + def handle_bracket(name: str, mapping: dict): """处理字符串中的括号对并转为正则表达式""" pattern_map = all_patterns() @@ -37,10 +50,11 @@ def handle_bracket(name: str, mapping: dict): parts[i] = f"(?P<{res[0]}>.+)" elif not res[0]: pat = pattern_map.get(res[1], res[1]) - parts[i] = str(pat.pattern if isinstance(pat, BasePattern) else pat) + parts[i] = regex_patterns.get(res[1], str(pat.pattern if isinstance(pat, BasePattern) else pat)) elif res[1] in pattern_map: mapping[res[0]] = pattern_map[res[1]] - parts[i] = f"(?P<{res[0]}>{pattern_map[res[1]].pattern})" + pat = regex_patterns.get(res[1], str(pattern_map[res[1]].pattern)) + parts[i] = f"(?P<{res[0]}>{pat})" else: parts[i] = f"(?P<{res[0]}>{res[1]})" return unescape("".join(parts)), True diff --git a/tests/core_test.py b/tests/core_test.py index 2f910774..0ba25696 100644 --- a/tests/core_test.py +++ b/tests/core_test.py @@ -534,6 +534,11 @@ def wrapper(slot, content): assert alc16_9.parse("test123").bar == "123" assert not alc16_9.parse("test").matched + alc16_10 = Alconna("core16_10", Args["bar", str]["baz", int]) + alc16_10.shortcut("/qux", {"command": "core16_10"}) + + assert alc16_10.parse('/qux "abc def.zip" 123').bar == "abc def.zip" + def test_help(): from arclet.alconna import output_manager