diff --git a/CHANGELOG.md b/CHANGELOG.md index 577a8625..aa23bb07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # 更新日志 +## Alconna 1.8.8 + +### 修复 + +- 修复子命令在自身名称解析失败时其结果被错误存储的问题 + ## Alconna 1.8.7 ### 改进 diff --git a/src/arclet/alconna/__init__.py b/src/arclet/alconna/__init__.py index 39a418a8..a8de3b05 100644 --- a/src/arclet/alconna/__init__.py +++ b/src/arclet/alconna/__init__.py @@ -27,6 +27,7 @@ from .config import namespace as namespace from .core import Alconna as Alconna from .duplication import Duplication as Duplication +from .exceptions import AlconnaException as AlconnaException from .exceptions import InvalidArgs as InvalidArgs from .exceptions import InvalidParam as InvalidParam from .exceptions import NullMessage as NullMessage @@ -50,7 +51,7 @@ from .typing import UnpackVar as UnpackVar from .typing import Up as Up -__version__ = "1.8.7" +__version__ = "1.8.8" # backward compatibility AnyOne = ANY diff --git a/src/arclet/alconna/_internal/_analyser.py b/src/arclet/alconna/_internal/_analyser.py index eda9c6fc..60342678 100644 --- a/src/arclet/alconna/_internal/_analyser.py +++ b/src/arclet/alconna/_internal/_analyser.py @@ -197,6 +197,7 @@ def process(self, argv: Argv[TDC]) -> Self: sub = argv.current_node = self.command name, _ = argv.next(sub.separators) if name not in sub.aliases: + argv.rollback(name) if not argv.fuzzy_match: raise InvalidParam(lang.require("subcommand", "name_error").format(source=sub.dest, target=name)) for al in sub.aliases: diff --git a/src/arclet/alconna/_internal/_handlers.py b/src/arclet/alconna/_internal/_handlers.py index dd59c6cb..d759f89b 100644 --- a/src/arclet/alconna/_internal/_handlers.py +++ b/src/arclet/alconna/_internal/_handlers.py @@ -12,7 +12,7 @@ from ..base import Option, Subcommand from ..completion import Prompt, comp_ctx from ..config import config -from ..exceptions import ArgumentMissing, FuzzyMatchSuccess, InvalidParam, PauseTriggered, SpecialOptionTriggered +from ..exceptions import AlconnaException, ArgumentMissing, FuzzyMatchSuccess, InvalidParam, PauseTriggered, SpecialOptionTriggered from ..model import HeadResult, OptionResult, Sentence from ..output import output_manager from ..typing import KWBool, MultiKeyWordVar, MultiVar, ShortcutRegWrapper @@ -286,6 +286,7 @@ def handle_option(argv: Argv, opt: Option) -> tuple[str, OptionResult]: elif name in opt.aliases: error = False if error: + argv.rollback(name) if not argv.fuzzy_match: raise InvalidParam(lang.require("option", "name_error").format(source=opt.dest, target=name)) for al in opt.aliases: @@ -365,7 +366,19 @@ def analyse_compact_params(analyser: SubAnalyser, argv: Argv): ) try: sparam.process(argv) - finally: + 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() _data.clear() return True @@ -373,6 +386,8 @@ def analyse_compact_params(analyser: SubAnalyser, argv: Argv): if argv.current_node.__class__ is Arg: raise e argv.data_reset(_data, _index) + else: + return False def handle_opt_default(defaults: dict[str, tuple[OptionResult, Action]], data: dict[str, OptionResult]): @@ -457,7 +472,19 @@ def analyse_param(analyser: SubAnalyser, argv: Argv, seps: tuple[str, ...] | Non ) try: sparam.process(argv) - finally: + 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() elif analyser.extra_allow: analyser.args_result.setdefault("$extra", []).append(_text) diff --git a/src/arclet/alconna/exceptions.py b/src/arclet/alconna/exceptions.py index 7db0dea3..7816f2a2 100644 --- a/src/arclet/alconna/exceptions.py +++ b/src/arclet/alconna/exceptions.py @@ -1,53 +1,57 @@ """Alconna 错误提示相关""" -class ParamsUnmatched(Exception): +class AlconnaException(Exception): + """Alconna 异常基类""" + + +class ParamsUnmatched(AlconnaException): """一个传入参数没有被选项或Args匹配""" -class InvalidParam(Exception): +class InvalidParam(AlconnaException): """传入参数验证失败""" -class ArgumentMissing(Exception): +class ArgumentMissing(AlconnaException): """组件内的 Args 参数未能解析到任何内容""" -class InvalidArgs(Exception): +class InvalidArgs(AlconnaException): """构造 alconna 时某个传入的参数不正确""" -class NullMessage(Exception): +class NullMessage(AlconnaException): """传入了无法解析的消息""" -class UnexpectedElement(Exception): +class UnexpectedElement(AlconnaException): """给出的消息含有不期望的元素""" -class ExecuteFailed(Exception): +class ExecuteFailed(AlconnaException): """执行失败""" -class ExceedMaxCount(Exception): +class ExceedMaxCount(AlconnaException): """注册的命令数量超过最大长度""" -class BehaveCancelled(Exception): +class BehaveCancelled(AlconnaException): """行为执行被停止""" -class OutBoundsBehave(Exception): +class OutBoundsBehave(AlconnaException): """越界行为""" -class FuzzyMatchSuccess(Exception): +class FuzzyMatchSuccess(AlconnaException): """模糊匹配成功""" -class PauseTriggered(Exception): +class PauseTriggered(AlconnaException): """解析状态保存触发""" -class SpecialOptionTriggered(Exception): +class SpecialOptionTriggered(AlconnaException): """内置选项解析触发"""