python - 使用 Python click 命令调用带有可变参数的类方法

标签 python command-line-interface args variadic python-click

我有一个类,它使用先前未知数量的参数进行初始化,并且我希望使用 Python 的 click 包在 CLI 上完成该操作。我的问题是我无法初始化它并运行 click 命令:

$ python mycode.py arg1 arg2 ... argN click_command

设置定义数量的参数,例如 nargs=5,可以解决缺少命令的问题,但要求我在命令之前输入 5 个参数。对于诸如 nargs=-1 之类的可变参数,click 无法将 click_command 识别为命令。

如何输入 n 个参数,然后使用 click 运行命令?

import click

class Foo(object):
    def __init__(self, *args):
        self.args = args

    def log(self):
        print('self.args:', self.args)

pass_foo = click.make_pass_decorator(Foo)

@click.group()
@click.argument('myargs', nargs=-1)
@click.pass_context
def main(ctx, myargs):
    ctx.obj = Foo(myargs)
    print("arguments: ", myargs)

@main.command()
@pass_foo
def log(foo):
    foo.log()

main()

我希望在将 n 个参数传递给我的 Foo() 类后能够运行 click 命令,这样我就可以初始化它并运行它的 log() 方法作为 CLI 命令,但输出是:

Error: Missing command

最佳答案

我不完全确定您正在尝试做的事情是解决此问题的最佳方法。我认为将可变参数放在命令后面会更符合逻辑,并且肯定会更符合单击的工作方式。但是,你可以用这个做你想做的事:

自定义类:

class CommandAfterArgs(click.Group):

    def parse_args(self, ctx, args):
        parsed_args = super(CommandAfterArgs, self).parse_args(ctx, args)
        possible_command = ctx.params['myargs'][-1]
        if possible_command in self.commands:
            ctx.protected_args = [possible_command]
            ctx.params['myargs'] = ctx.params['myargs'][:-1]

        elif possible_command in ('-h', '--help'):
            if len(ctx.params['myargs']) > 1 and \
                    ctx.params['myargs'][-2] in self.commands:
                ctx.protected_args = [ctx.params['myargs'][-2]]
                parsed_args = ['--help']
                ctx.params['myargs'] = ctx.params['myargs'][:-2]
                ctx.args = [possible_command]

        return parsed_args

使用自定义类:

然后要使用自定义类,请将其作为 cls 参数传递给组装饰器,如下所示:

@click.group(cls=CommandAfterArgs)
@click.argument('myargs', nargs=-1)
def main(myargs):
    ...

测试代码:

import click

class Foo(object):
    def __init__(self, *args):
        self.args = args

    def log(self):
        print('self.args:', self.args)


pass_foo = click.make_pass_decorator(Foo)


@click.group(cls=CommandAfterArgs)
@click.argument('myargs', nargs=-1)
@click.pass_context
def main(ctx, myargs):
    ctx.obj = Foo(*myargs)
    print("arguments: ", myargs)


@main.command()
@pass_foo
def log(foo):
    foo.log()


if __name__ == "__main__":
    commands = (
        'arg1 arg2 log',
        'log --help',
        '--help',
    )

    import sys, time

    time.sleep(1)
    print('Click Version: {}'.format(click.__version__))
    print('Python Version: {}'.format(sys.version))
    for cmd in commands:
        try:
            time.sleep(0.1)
            print('-----------')
            print('> ' + cmd)
            time.sleep(0.1)
            main(cmd.split())

        except BaseException as exc:
            if str(exc) != '0' and \
                    not isinstance(exc, (click.ClickException, SystemExit)):
                raise

结果:

Click Version: 6.7
Python Version: 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]
-----------
> arg1 arg2 log
arguments:  ('arg1', 'arg2')
self.args: ('arg1', 'arg2')
-----------
> log --help
arguments:  ()
Usage: test.py log [OPTIONS]

Options:
  --help  Show this message and exit.
-----------
> --help
Usage: test.py [OPTIONS] [MYARGS]... COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  log

关于python - 使用 Python click 命令调用带有可变参数的类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54702048/

相关文章:

python - pg.内部错误 : SSL SYSCALL error: EOF detected

python - 如何在 tweepy 中的某个位置获取特定主题标签的推文?

python - 有效地重新排序列表/配对的数据帧

php - 如何使用 PHP-CLI 获取光标位置?

java - Dice Class,Cho-Han Bakuchi 的游戏。Java(二元运算符的错误操作数类型 '+')

java - Java中的args、argh和argv有什么区别?

python - 猴子补丁方法和引用的问题

post - 如何将参数从命令行传递到 PHP 脚本中的 $_POST?

git - 是否可以在不打开浏览器的情况下从 CLI 在 GitHub 上创建远程仓库?

go - Visual Studio Code 任务参数