gpt4 book ai didi

python - 使用 Python Click 保留用户提供的参数的顺序

转载 作者:行者123 更新时间:2023-12-04 08:15:11 25 4
gpt4 key购买 nike

我正在尝试将 argparse 命令行界面 (CLI) 移植到 click。此 CLI 必须维护用户提供参数的顺序。对于 argparse 版本,我使用了 this StackOverflow answer维持秩序。使用 click,我不确定如何执行此操作。

我尝试创建一个自定义回调来按顺序存储参数和值,但如果多次使用一个参数,回调会在它第一次看到匹配参数时触发。

import click
import typing

class OrderParams:
_options: typing.List[typing.Tuple[click.Parameter, typing.Any]] = []

@classmethod
def append(cls, ctx: click.Context, param: click.Parameter, value: typing.Any):
cls._options.append((param, value))

@click.command()
@click.option("--animal", required=True, multiple=True, callback=OrderParams.append)
@click.option("--thing", required=True, multiple=True, callback=OrderParams.append)
def cli(*, animal, thing):
click.echo("Got this order of parameters:")
for param, value in OrderParams._options:
print(" ", param.name, value)

if __name__ == "__main__":
cli()

当前输出:

$ python cli.py --animal cat --thing rock --animal dog
Got this order of parameters:
animal ('cat', 'dog')
thing ('rock',)

期望的输出:

$ python cli.py --animal cat --thing rock --animal dog
Got this order of parameters:
animal 'cat'
thing 'rock'
animal 'dog'

click documentation describes the behavior第一次遇到参数时调用一次回调,即使该参数被多次使用也是如此。

If an option or argument is split up on the command line into multiple places because it is repeated [...] the callback will fire based on the position of the first option.

最佳答案

这可以通过使用自定义类覆盖 click.Command 参数解析器调用来完成,例如:

自定义类:

class OrderedParamsCommand(click.Command):
_options = []

def parse_args(self, ctx, args):
# run the parser for ourselves to preserve the passed order
parser = self.make_parser(ctx)
opts, _, param_order = parser.parse_args(args=list(args))
for param in param_order:
type(self)._options.append((param, opts[param.name].pop(0)))

# return "normal" parse results
return super().parse_args(ctx, args)

使用自定义类:

然后要使用自定义命令,将其作为 cls 参数传递给 command 装饰器,例如:

@click.command(cls=OrderedParamsCommand)
@click.option("--animal", required=True, multiple=True)
@click.option("--thing", required=True, multiple=True)
def cli(*, animal, thing):
....

这是如何运作的?

之所以可行,是因为 click 是一个设计良好的 OO 框架。 @click.command() 装饰器通常实例化一个 click.Command 对象,但允许使用cls 参数。所以在我们的代码中继承click.Command是一件相对容易的事情自己的类(class)并超越所需的方法。

在这种情况下,我们超越 click.Command.parse_args() 并自己运行解析器以保留命令传入。

测试代码:

import click

class OrderedParamsCommand(click.Command):
_options = []

def parse_args(self, ctx, args):
parser = self.make_parser(ctx)
opts, _, param_order = parser.parse_args(args=list(args))
for param in param_order:
type(self)._options.append((param, opts[param.name].pop(0)))

return super().parse_args(ctx, args)


@click.command(cls=OrderedParamsCommand)
@click.option("--animal", required=True, multiple=True)
@click.option("--thing", required=True, multiple=True)
def cli(*, animal, thing):
click.echo("Got this order of parameters:")
for param, value in OrderedParamsCommand._options:
print(" ", param.name, value)


if __name__ == "__main__":
cli('--animal cat --thing rock --animal dog'.split())

结果:

Got this order of parameters:
animal cat
thing rock
animal dog

关于python - 使用 Python Click 保留用户提供的参数的顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65742330/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com