为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

潇湘沐 2021-11-09 16:58:13
我有一个使用以前未知数量的参数初始化的类,我希望它使用 Python 的click包在 CLI 上完成。我的问题是我无法初始化它并运行click命令:$ python mycode.py arg1 arg2 ... argN click_command设置定义数量的参数,如nargs=5,解决了缺少命令的问题,但我有义务在我的命令之前输入 5 个参数。对于像nargs=-1, 之类的可变参数,click不能识别click_command为命令。如何输入 n 个参数,然后使用click?import clickclass 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_contextdef main(ctx, myargs):    ctx.obj = Foo(myargs)    print("arguments: ", myargs)@main.command()@pass_foodef log(foo):    foo.log()main()我希望能够click在将 n-many args 传递给我的Foo()类后运行命令,因此我可以初始化它并将其log()方法作为 CLI 命令运行,但输出是:错误:缺少命令
查看完整描述

1 回答

?
一只萌萌小番薯

TA贡献1795条经验 获得超7个赞

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


自定义类:

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


查看完整回答
反对 回复 2021-11-09
  • 1 回答
  • 0 关注
  • 256 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信