From 2a8d8c39e25d6bf3a4f717413e54cc6f38dc0d52 Mon Sep 17 00:00:00 2001 From: RF-Tar-Railt Date: Sun, 22 Sep 2024 21:04:20 +0800 Subject: [PATCH] :bug: fix duplicate subcommand --- src/arclet/alconna/_internal/_analyser.py | 5 +- src/arclet/alconna/_internal/_handlers.py | 68 ++++++++++++----------- tests/core_test.py | 2 +- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/arclet/alconna/_internal/_analyser.py b/src/arclet/alconna/_internal/_analyser.py index 44920860..977772d7 100644 --- a/src/arclet/alconna/_internal/_analyser.py +++ b/src/arclet/alconna/_internal/_analyser.py @@ -222,7 +222,8 @@ def analyse(self, argv: Argv[TDC]) -> Self: ArgumentMissing: 参数缺失 """ while analyse_param(self, argv, self.command.separators): - pass + self.sentences.clear() + argv.current_node = None if self.default_main_only and not self.args_result: self.args_result = analyse_args(argv, self.self_args) if not self.args_result and self.need_main_args: @@ -406,7 +407,7 @@ def process(self, argv: Argv[TDC]) -> Arparma[TDC]: def analyse(self, argv: Argv[TDC]) -> Arparma[TDC] | None: try: while analyse_param(self, argv) and argv.current_index != argv.ndata: - pass + argv.current_node = None except FuzzyMatchSuccess as e: output_manager.send(self.command.name, lambda: str(e)) return self.export(argv, True) diff --git a/src/arclet/alconna/_internal/_handlers.py b/src/arclet/alconna/_internal/_handlers.py index 247ddcf5..34138e56 100644 --- a/src/arclet/alconna/_internal/_handlers.py +++ b/src/arclet/alconna/_internal/_handlers.py @@ -442,14 +442,10 @@ def analyse_param(analyser: SubAnalyser, argv: Argv, seps: tuple[str, ...] | Non return True else: _param = None - if not _param and analyser.command.nargs and not analyser.args_result: - analyser.args_result = analyse_args(argv, analyser.self_args) - if analyser.args_result: - argv.current_node = None - return True if _param.__class__ is Sentence: - analyser.sentences.append(argv.next()[0]) - return True + if _param.name not in analyser.sentences: # type: ignore + analyser.sentences.append(argv.next()[0]) + return True if _param.__class__ is Option: oparam: Option = _param # type: ignore if oparam.requires and analyser.sentences != oparam.requires: @@ -457,7 +453,9 @@ def analyse_param(analyser: SubAnalyser, argv: Argv, seps: tuple[str, ...] | Non lang.require("option", "require_error").format(source=oparam.name, target=" ".join(analyser.sentences)) ) analyse_option(analyser, argv, oparam) - elif _param.__class__ is list: + analyser.sentences.clear() + return True + if _param.__class__ is list: exc: Exception | None = None lparam: list[Option] = _param # type: ignore for opt in lparam: @@ -479,38 +477,46 @@ def analyse_param(analyser: SubAnalyser, argv: Argv, seps: tuple[str, ...] | Non argv.data_reset(_data, _index) if exc: raise exc # type: ignore # noqa - elif _param is not None: + analyser.sentences.clear() + return True + if _param is not None: sparam: SubAnalyser = _param # type: ignore - if sparam.command.requires and analyser.sentences != sparam.command.requires: - raise InvalidParam( - lang.require("subcommand", "require_error").format( - source=sparam.command.name, target=" ".join(analyser.sentences) + if sparam.command.dest not in analyser.subcommands_result: + if sparam.command.requires and analyser.sentences != sparam.command.requires: + raise InvalidParam( + lang.require("subcommand", "require_error").format( + source=sparam.command.name, target=" ".join(analyser.sentences) + ) ) - ) - try: - sparam.process(argv) - except (FuzzyMatchSuccess, PauseTriggered, SpecialOptionTriggered): - sparam.result() - raise - except InvalidParam: - if argv.current_node is sparam.command: + try: + sparam.process(argv) + except (FuzzyMatchSuccess, PauseTriggered, SpecialOptionTriggered): sparam.result() + raise + except InvalidParam: + if argv.current_node is sparam.command: + sparam.result() + else: + analyser.subcommands_result[sparam.command.dest] = sparam.result() + raise + except AlconnaException: + analyser.subcommands_result[sparam.command.dest] = sparam.result() + raise else: analyser.subcommands_result[sparam.command.dest] = sparam.result() - raise - except AlconnaException: - analyser.subcommands_result[sparam.command.dest] = sparam.result() - raise - else: - analyser.subcommands_result[sparam.command.dest] = sparam.result() - elif analyser.extra_allow: + analyser.sentences.clear() + return True + if _param is None and analyser.command.nargs and not analyser.args_result: + analyser.args_result = analyse_args(argv, analyser.self_args) + if analyser.args_result: + argv.current_node = None + return True + if analyser.extra_allow: analyser.args_result.setdefault("$extra", []).append(_text) argv.next(seps, move=True) + return True else: return False - analyser.sentences.clear() - argv.current_node = None - return True def _header_handle0(header: "Header[set[str], TPattern]", argv: Argv): diff --git a/tests/core_test.py b/tests/core_test.py index 286d6506..616346c6 100644 --- a/tests/core_test.py +++ b/tests/core_test.py @@ -868,7 +868,7 @@ def test_action(): Option("--q", action=count, requires=["foo", "bar"]), ) res = alc24_2.parse( - "core24_2 -A --a -vvv -x -x --xyzxyz " "-Fabc -Fdef --flag xyz --i 4 --i 5 " "foo bar --q foo bar --qq" + "core24_2 -A --a -vvv -x -x --xyzxyz -Fabc -Fdef --flag xyz --i 4 --i 5 foo bar --q foo bar --qq" ) assert res.query[int]("i.foo") == 5 assert res.query[List[int]]("a.value") == [1, 1]