diff --git a/CHANGELOG.md b/CHANGELOG.md index 86eb7294..df7226be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,64 @@ # 更新日志 +## Alconna 1.8.0 + +**此版本为长期支持版本 (LTS),同时为 v1.x 与 v2.0 之间的过渡版本** + +### 破坏性改动 + +> 用户侧 + +- `Args.__init__` 不再接受 `**kwargs` 参数 +- `Alconna.parse` 不再接受 `duplication` 参数;请直接使用 `Duplication(Arparma)` +- `fuzzy_threshold` 参数移至 `Namespace` + +> 开发侧 + +- `NEPattern` 依赖升级至 0.6.x +- 移除兼容名称 `Arpamar` 与 `DataCollectionContainer` + +### 新增 + +- `Alconna.parse` 新增 `ctx: dict[str, Any]` 参数,用于传入上下文. + 1. 用户可以通过 `$argv.overrides` 参数来覆盖 Argv 的属性 +- `Arparma` 新增 `context` 参数,与 `Alconna.parse` 的 `ctx` 参数对应 + 1. 当触发快捷指令后,用户可以通过 `$shortcut.trigger`, `$shortcut.args`, `$shortcut.rest` 来获取快捷指令的信息 +- 新增 `ContextVal` 表达式,可以依据用户传入的指定键从 `ctx` 中获取值 + 1. `ContextVal` 默认格式为 `$(KEY)`, 其中 `KEY` 为 `ctx` 中的键 + 2. 使用 `ContextVal(style="bracket")` 可以将 `ContextVal` 的格式改为 `{KEY}` + 3. 指定键支持 eval 表达式,如 `$(session.user.id)`, `$(session.user.name[1:])` + 4. `ContextVal` 支持只允许指定的键,如 `ContextVal("session", "event")` + + ```python + from dataclasses import dataclass + from arclet.alconna import Alconna, Args, ContextVal + + alc = Alconna("test", Args["foo", ContextVal(style="bracket")]) + + @dataclass + class User: + id: str + + @dataclass + class Session: + user: User + + arp = alc.parse( + "test {session.user.id}", + {"session": Session(user=User(id="123"))} + ) + assert arp.query[str]("foo") == "123" + ``` + +### 改进 + +- `Subcommand` 可以设置别名了 +- `Alconna` 的前缀可以在最尾端塞分隔符 + +### 修复 + +- 修复类型提示错误 + ## Alconna 1.7.44 ### 修复 @@ -359,7 +418,7 @@ ## Alconna 1.7.0 -**此版本为长期支持版本 (LTS), 也是 2.0 版本前的最后一个主要版本** +**此版本为长期支持版本 (LTS)** ### 破坏性改动 diff --git a/example/pip.py b/example/pip.py index 92837310..285ecc57 100644 --- a/example/pip.py +++ b/example/pip.py @@ -1,7 +1,7 @@ from pathlib import Path from typing import Tuple -from nepattern import URL, create_local_patterns +from nepattern import URL from arclet.alconna import Alconna, Args, MultiVar, Option, Subcommand, count, store_true diff --git a/pyproject.toml b/pyproject.toml index 73a05681..71a5508a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ authors = [ dependencies = [ "typing-extensions>=4.5.0", "nepattern<1.0.0,>=0.6.4", - "tarina>=0.4.1", + "tarina>=0.4.4", ] dynamic = ["version"] requires-python = ">=3.8" diff --git a/src/arclet/alconna/__init__.py b/src/arclet/alconna/__init__.py index c3a4c222..b96d3d9c 100644 --- a/src/arclet/alconna/__init__.py +++ b/src/arclet/alconna/__init__.py @@ -51,8 +51,7 @@ from .typing import UnpackVar as UnpackVar from .typing import Up as Up -__version__ = "1.7.44" +__version__ = "1.8.0" # backward compatibility -Arpamar = Arparma -DataCollectionContainer = Argv +AnyOne = ANY diff --git a/src/arclet/alconna/_internal/_argv.py b/src/arclet/alconna/_internal/_argv.py index 6915942e..c0345959 100644 --- a/src/arclet/alconna/_internal/_argv.py +++ b/src/arclet/alconna/_internal/_argv.py @@ -56,7 +56,7 @@ class Argv(Generic[TDC]): """命令的token""" origin: TDC = field(init=False) """原始命令""" - context: dict[str, Any] = field(init=False) + context: dict[str, Any] = field(init=False, default_factory=dict) _sep: tuple[str, ...] | None = field(init=False) _cache: ClassVar[dict[type, dict[str, Any]]] = {} @@ -269,7 +269,6 @@ def enter(self, ctx: dict[str, Any] | None = None) -> Self: def exit(self) -> dict[str, Any]: """退出上下文""" - try: - return self.context - finally: - self.context = {} + _ = self.context + self.context = {} + return _ diff --git a/src/arclet/alconna/_internal/_header.py b/src/arclet/alconna/_internal/_header.py index 7190b3da..a437611f 100644 --- a/src/arclet/alconna/_internal/_header.py +++ b/src/arclet/alconna/_internal/_header.py @@ -2,7 +2,7 @@ import re from inspect import isclass -from typing import Any, Callable +from typing import TYPE_CHECKING, Any, Callable from nepattern import BasePattern, MatchMode, UnionPattern, all_patterns, parser from nepattern.util import TPattern @@ -212,8 +212,9 @@ def match2(self, pf: Any, cmd: Any, p_str: bool, c_str: bool, pbfn: Callable[... pbfn(cmd[len(mat[0]):], replace=True) return (pf, cmd), (val._value, mat[0]), True, mat.groupdict() - def match(self, pf: Any, cmd: Any, p_str: bool, c_str: bool, pbfn: Callable[..., Any], comp: bool) -> Any: - ... + if TYPE_CHECKING: + def match(self, pf: Any, cmd: Any, p_str: bool, c_str: bool, pbfn: Callable[..., Any], comp: bool) -> Any: + ... class Header: diff --git a/src/arclet/alconna/base.py b/src/arclet/alconna/base.py index 9be270c1..979aeece 100644 --- a/src/arclet/alconna/base.py +++ b/src/arclet/alconna/base.py @@ -100,7 +100,7 @@ def __init__( _name = _aliases[0] aliases.extend(_aliases[1:]) if not _name: - raise InvalidArgs(lang.require("common", "name_empty")) + raise InvalidArgs(lang.require("common", "name_empty")) aliases.insert(0, _name) self.name = _name self.aliases = frozenset(aliases) @@ -196,7 +196,7 @@ def __init__( compact (bool, optional): 是否允许名称与后随参数之间无分隔符 priority (int, optional): 命令选项优先级 """ - + self.priority = priority self.compact = compact if default is not Empty: diff --git a/src/arclet/alconna/core.py b/src/arclet/alconna/core.py index 72130f92..99850576 100644 --- a/src/arclet/alconna/core.py +++ b/src/arclet/alconna/core.py @@ -230,8 +230,8 @@ def shortcut(self, key: str, args: ShortcutArgs | None = None) -> str: @overload def shortcut( - self, - key: str, + self, + key: str, *, command: str | None = None, arguments: list[Any] | None = None, diff --git a/src/arclet/alconna/output.py b/src/arclet/alconna/output.py index aefa4c8e..cdac8682 100644 --- a/src/arclet/alconna/output.py +++ b/src/arclet/alconna/output.py @@ -29,7 +29,7 @@ class OutputManager: """缓存的输出行为""" outputs: dict[str, Sender] = field(default_factory=dict) """输出行为""" - send_action: Callable[[str], Any] = field(default=lambda x: print(x)) + send_action: Callable[[str], Any] = field(default=print) # type: ignore """默认的发送行为""" _out_cache: dict[str, dict[str, Any]] = field(default_factory=dict, hash=False, init=False)