跳到主要内容

命令参数

Args 是一个特殊的类,用来包装command中的args, 即命令参数, 如

from arclet.alconna import Args, Option
opt = Option("test", Args(foo=str, num=int).default(foo="bar"))

from arclet.alconna import Args, Option
opt = Option("test", Args["foo", str, "bar"]["num", int])

Args 推荐的构造方式如下:

fast →arg = Args["test", bool, True]["aaa", str, "bbb"]argArgs('test': bool = 'True', 'aaa': str = 'bbb')arg << Args["perm", str, "de"] + ("month", int) argArgs('test': bool = 'True', 'aaa': str = 'bbb', 'perm': str = 'de', 'month': int)arg1 = Args.foo["bar", ...]arg1Args('foo': 'bar' = 'Ellipsis')restart ↻

Args.default() 用来设置 Args(**kwargs) 时的默认值, 但是不会覆盖 Args["key", type, default] 的默认值

Arg

Args 是由多个Arg组成的, 一个Arg代表一个参数, 如

from arclet.alconna import Args, Arg

arg1 = Args["foo", str, "bar"]["num", int]
arg2 = Args[Arg("foo", str, "bar")][Arg("num", int)]
arg3 = Args(Arg("foo", str, "bar"), Arg("num", int))

assert arg1 == arg2 == arg3

Arg 的构造方式如下:

Arg(
name: str,
value: TAValue | None = None,
field: Field[_T] | _T | None = None,
seps: str | Iterable[str] = " ",
notice: str | None = None,
flags: list[ArgFlag] | None = None,
)
  • name 为参数名, 用于在Args与解析结果中标识该参数
  • value 为参数值, 用于在Args中标识该参数的类型或者匹配值
  • field 为参数的Field, 用于在Args中标识该参数的默认值,默认值生成器等; 也可以直接传入默认值
  • seps 为参数的分隔符, 用于在Args中标识该参数的分隔符, 默认为' '(空格)
  • notice 为参数的提示, 用于在Args中标识该参数的提示, 默认为None
  • flags 为参数的标识符, 用于在Args中标识该参数的标识符, 默认为None

flag 目前有 3 种, 分别为 ?: ArgFlag.OPTIONAL!: ArgFlag.ANTI/: ArgFlag.HIDDEN

其中 name 保留了一些特殊形式, 用于便捷传入 noticeflags

其形式为 name(;?)flags#notice, ; 或 名字之后为 flags, # 之后为 notice:

from arclet.alconna import Arg, ArgFlag

arg1 = Arg("foo;/?#bar")
arg2 = Arg("foo", notice="bar", flags=[ArgFlag.OPTIONAL, ArgFlag.HIDDEN])

assert arg1 == arg2

value

value 可以是以下类型:

  • 存在于 nepattern.all_patterns 中的类型/字符串,用以替换为预制好的 BasePattern
  • 字符串,会转换为正则表达式
  • 列表,其中可存放 BasePattern、类型或者任意参数值,如字符串或者数字
  • UnionOptionalLiteral 等会尝试转换为 List[Type]
  • Dict[type1,type2]List[type]Set[type]
  • 一般的类型,其会尝试比较传入参数的类型是否与其相关
  • AnyOneAllParam.
  • 预制好的字典, 表示传入值依据该字典的键决定匹配结果
  • Annotated[type, Callable[..., bool], ...],表示为某一类型添加校验器
  • Callable[[P], T],表示会将传入的参数 P 经过该调用对象并将返回值 T 作为匹配结果
  • ...

内置的类型检查包括 intstrfloatbool'url''ip''email'listdicttuplesetAnybyteshexdatetime 等。

Field

Field 是如下定义的:

class Field(Generic[_T]):
"""标识参数单元字段"""
default: _T = dc_field(default=None)
alias: str | None = dc_field(default=None)
completion: Callable[[], str | list[str]] | None = dc_field(default=None)

其中 default 用于给出默认值

提示

需要注意的是, default 为 None 相当于没有默认值

如果你需要使自己的默认值为 None, 你应该使用 arclet.aclonna.Empty, 其会在解析之后自动替换

separator

在命令解析过程中, Args 会根据每个 Argseps 来进行分隔:

Command(
...,
Separator("main_sep"),
Segment(
Name("opt1"),
Separator("opt1_sep"),
Segment(
Arg("value1"),
Separator("arg1_sep"),
Arg("value2"),
Separator("arg2_sep"),
...,
Arg("valueN")
)
),
Separator("main_sep"),
Segment(
Name("opt2"),
Separator("opt2_sep"),
...
)
)

AnyOne 与 AllParam

AnyOneAllParam是特殊的两种参数类型, 作用分别为单参泛匹配与全参泛匹配

对于同个命令, /test foo bar 123 来讲

from arclet.alconna import AnyOne, AllParam, Alconna, Args

test1 = Alconna(
"/test",
Args["wild", AnyOne],
)

test2 = Alconna(
"/test",
Args["wild", AllParam],
)

test1只能将foo匹配给wild

test2 能够将foo bar 123 匹配给wild

警告

AllParam会直接截断后续的命令解析操作, 请谨慎使用

Keyword args

Alconna 提供了一个特殊的 KeyWordVar, 用于标识一个参数为关键字参数:

from arclet.alconna import Args, Alconna, KeyWordVar

alc = Alconna("test", Args["foo", KeyWordVar(int)])

这会使得该参数只能通过关键字参数的形式传入, 例如:

fast →test foo=123{'foo': 123}test 123Traceback (most recent call last):
File "<stdin>", line 1, in <module>
arclet.alconna.exceptions.ParamsUnmatched: 123 missing its key.
Do you forget to add 'foo='?
restart ↻

KeyWordVar 可以传入一个 sep 参数, 用于标识该关键字参数的分隔符, 默认为'=':

from arclet.alconna import Args, Alconna, KeyWordVar

alc = Alconna("test", Args["foo", KeyWordVar(int, sep=":")])

这样该参数就可以通过 foo:123 的形式传入了

Multi args

Alconna 提供了另一个特殊的 MultiVar, 用于标识一个参数为不定参数:

from arclet.alconna import Args, Alconna, MultiVar

alc = Alconna("test", Args["foo", MultiVar(int)])

这会使得该参数可以接受多个相同类型的参数, 例如:

fast →test 123 456 789{'foo': (123, 456, 789)}test 123{'foo': (123,)}restart ↻

MultiVar 可以传入一个 flag 参数, 用于标识该可变参数的类型, 目前支持的类型有:

  • *: 传入0个或多个参数
  • +: 传入1个或多个参数
  • 任意大于0的整数: 传入指定数量的参数
提示

MultiVarKeyWordVar 可以结合使用, 例如:

from arclet.alconna import Args, Alconna, MultiVar, KeyWordVar

alc = Alconna("test", Args["foo", MultiVar(KeyWordVar(int))])

这会使得该参数可以接受多个关键字参数, 例如:

fast →test bar=123 baz=456 qux=789{'foo': {'bar': 123, 'baz': 456, 'qux': 789 }}restart ↻

Optional args

通过 flag 参数, 我们可以将参数标记为可选参数:

from arclet.alconna import Args, Alconna, Arg, ArgFlag

alc = Alconna("test", Args["foo", int]["bar;?", str])
# or
alc = Alconna("test", Args["foo", int][Arg("bar", str, flags=[ArgFlag.Optional])])

这会使得该参数可以不传入, 例如:

fast →test 123{'foo': 123}test 123 abc{'foo': 123, 'bar': 'abc'}restart ↻

提示

该情形下也可以使用 typing.Optional 来标记参数参数:

from arclet.alconna import Args, Alconna
from typing import Optional

alc = Alconna("test", Args["foo", int]["bar", Optional[str]])

这等同于:

alc = Alconna("test", Args["foo", int]["bar", str, Empty])  # 意思为 bar 的默认值是 None
fast →test 123{'foo': 123, 'bar': None}test 123 abc{'foo': 123, 'bar': 'abc'}restart ↻

警告

optional 参数必须在 multi 参数之前,并且 optional flag 不能与 MultiVar 同时使用

Anti args

通过 flag 参数, 我们可以将参数标记为反向参数:

from arclet.alconna import Args, Alconna, Arg, ArgFlag

alc = Alconna("test", Args["foo", int]["bar;!", int])
# or
alc = Alconna("test", Args["foo", int][Arg("bar", int, flags=[ArgFlag.Anti])])

这使得该参数可以传入任何不符合该参数类型的参数, 例如:

fast →test 123 abc{'foo': 123, 'bar': 'abc'}test 123 456Traceback (most recent call last):
File "<stdin>", line 1, in <module>
arclet.alconna.exceptions.ParamsUnmatched: 参数 456 不正确
restart ↻

Const args

value 参数中传入一个 const 值, 可以将该参数标记为常量参数:

from arclet.alconna import Args, Alconna

alc = Alconna("test", Args["foo", int]["bar", 123])
# or
from typing import Literal
alc = Alconna("test", Args["foo", int]["bar", Literal[123]])

这会使得该参数只能传入指定的值, 例如:

fast →test 123 123{'foo': 123, 'bar': 123}test 123 456Traceback (most recent call last):
File "<stdin>", line 1, in <module>
arclet.alconna.exceptions.ParamsUnmatched: 参数 456 不正确
restart ↻

Union args

value 参数中传入一个 typing.Union 值, 可以将该参数标记为联合参数:

from arclet.alconna import Args, Alconna
from typing import Union

alc = Alconna("test", Args["foo", Union[int, bool]])

这会使得该参数可以传入多种类型的参数, 例如:

fast →test 123{'foo': 123}test true{'foo': True}restart ↻

备注

此处可以直接使用 [int, bool] 作为 value 参数

不仅如此,直接使用 [...] 可以传入常量参数作为 "choice" 参数:

alc = Alconna("test", Args["foo", [1, 2, 3]])

这使得该参数只能传入 1, 2, 3 中的一个, 例如:

fast →test 1{'foo': 1}test 4Traceback (most recent call last):
File "<stdin>", line 1, in <module>
arclet.alconna.exceptions.ParamsUnmatched: 参数 4 不正确
restart ↻

[...] 中可以同时传入类型和常量:

alc = Alconna("test", Args["foo", [bool, 1, 2, 3]])

更特别的是,此处还可以传入 "foo|bar" 这样的字符串:

alc = Alconna("test", Args["foo", ["abc|def"]])  # 会尝试在 patterns 里寻找 abc 或 def
# or
alc = Alconna("test", Args["foo", ["re:abc|def"]]) # 转为正则表达式

Switch args

value 参数中传入一个字典, 可以将该参数标记为开关参数:

from arclet.alconna import Args, Alconna

alc = Alconna("test", Args["foo", {"bar": 123, "baz": 456}])

这就类似于:

switch (foo) {
case "bar": return 123;
case "baz": return 456;
default: throw new Error("参数不正确");
}

使得该参数只能传入指定的值, 例如:

fast →test bar{'foo': 123}test baz{'foo': 456}test abcTraceback (most recent call last):
File "<stdin>", line 1, in <module>
arclet.alconna.exceptions.ParamsUnmatched: 参数 abc 不正确
restart ↻

特别的,如果字典中有一个 ... 键,那么该参数可以传入任何值:

alc = Alconna("test", Args["foo", {"bar": 123, "baz": 456, ...: 789}])

这就类似于:

switch (foo) {
case "bar": return 123;
case "baz": return 456;
default: return 789;
}

Callable args

value 参数中传入一个可调用对象, 可以将该参数标记为可调用参数:

from arclet.alconna import Args, Alconna

def func(value) -> int | None:
if isinstance(value, int):
return value * 2
elif isinstance(value, str):
if value == "abc":
return 123
elif value == "def":
return 456

alc = Alconna("test", Args["foo", func])

这会使得该参数只能传入可以通过 func 处理的值, 例如:

fast →test 123{'foo': 246}test abc{'foo': 123}test def{'foo': 456}test ghiTraceback (most recent call last):
File "<stdin>", line 1, in <module>
arclet.alconna.exceptions.ParamsUnmatched: 参数 ghi 不正确
restart ↻