单击中没有名称的命令 [英] A command without name, in Click

查看:75
本文介绍了单击中没有名称的命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想拥有这样的用法的命令行工具:

I want to have a command line tool with a usage like this:

$ program <arg>            does something, no command name required
$ program cut <arg>
$ program eat <arg>

点击代码如下所示:

@click.group()
def main() :
    pass

@main.command()
@click.argument('arg')
def noname(arg) :
    # does stuff

@main.command()
@click.argument('arg')
def cut(arg) :
    # cuts stuff

@main.command()
@click.argument('arg')
def eat(arg) :
    # eats stuff

我的问题是,使用此代码,总会有一个必需的命令名称,即:我需要运行$ program noname arg.但是我希望能够运行$ program arg.

My problem is that with this code, there is always a required command name, ie: I need to run $ program noname arg. But I want to be able to run $ program arg.

推荐答案

由于 default 命令引入的歧义,您的方案面临一些挑战.无论如何,这是使用click可以实现的一种方法.如测试结果所示,所生成的帮助不太理想,但可能还可以.

Your scheme has some challenges because of the ambiguity introduce with the default command. Regardless, here is one way that can be achieved with click. As shown in the test results, the generated help with be less than ideal, but likely OK.

import click

class DefaultCommandGroup(click.Group):
    """allow a default command for a group"""

    def command(self, *args, **kwargs):
        default_command = kwargs.pop('default_command', False)
        if default_command and not args:
            kwargs['name'] = kwargs.get('name', '<>')
        decorator = super(
            DefaultCommandGroup, self).command(*args, **kwargs)

        if default_command:
            def new_decorator(f):
                cmd = decorator(f)
                self.default_command = cmd.name
                return cmd

            return new_decorator

        return decorator

    def resolve_command(self, ctx, args):
        try:
            # test if the command parses
            return super(
                DefaultCommandGroup, self).resolve_command(ctx, args)
        except click.UsageError:
            # command did not parse, assume it is the default command
            args.insert(0, self.default_command)
            return super(
                DefaultCommandGroup, self).resolve_command(ctx, args)

使用自定义类

要使用自定义类,请将cls参数传递给click.group()装饰器.然后将default_command=True用作默认命令.

Using the Custom Class

To use the custom class, pass the cls parameter to the click.group() decorator. Then pass default_command=True for the command which will be the default.

@click.group(cls=DefaultCommandGroup)
def a_group():
    """My Amazing Group"""

@a_group.command(default_command=True)
def a_command():
    """a command under the group"""

这是如何工作的?

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

How does this work?

This works because click is a well designed OO framework. The @click.group() decorator usually instantiates a click.Group object but allows this behavior to be over ridden with the cls parameter. So it is a relatively easy matter to inherit from click.Group in our own class and over ride desired methods.

在这种情况下,我们越过了click.Group.command(),以便在添加命令时可以找到默认命令.此外,我们覆盖了click.Group.resolve_command(),以便在第一个解析不成功时可以插入默认命令名称.

In this case we over ride click.Group.command() so that when a command is added we find the default command. In addition we override click.Group.resolve_command() so that we can insert the default command name if the first resolution is unsuccessful.

@click.group(cls=DefaultCommandGroup)
def main():
    pass

@main.command(default_command=True)
@click.argument('arg')
def noname(arg):
    """ does stuff """
    click.echo('default: {}'.format(arg))

@main.command()
@click.argument('arg')
def cut(arg):
    """ cuts stuff """
    click.echo('cut: {}'.format(arg))

@main.command()
@click.argument('arg')
def eat(arg):
    """ eats stuff """
    click.echo('eat: {}'.format(arg))


if __name__ == "__main__":
    commands = (
        'an_arg',
        'cut cut_arg',
        'eat eat_arg',
        '--help',
        'cut --help',
        'eat --help',
        '',
    )

    import sys, time

    time.sleep(1)
    print('Click Version: {}'.format(click.__version__))
    print('Python Version: {}'.format(sys.version))
    for command in commands:
        try:
            time.sleep(0.1)
            print('-----------')
            print('> ' + command)
            time.sleep(0.1)
            main(command.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)]
-----------
> an_arg
default: an_arg
-----------
> cut cut_arg
cut: cut_arg
-----------
> eat eat_arg
eat: eat_arg
-----------
> --help
Usage: test.py [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  <>   does stuff
  cut  cuts stuff
  eat  eats stuff
-----------
> cut --help
Usage: test.py cut [OPTIONS] ARG

  cuts stuff

Options:
  --help  Show this message and exit.
-----------
> eat --help
Usage: test.py eat [OPTIONS] ARG

  eats stuff

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

Options:
  --help  Show this message and exit.

Commands:
  <>   does stuff
  cut  cuts stuff
  eat  eats stuff

这篇关于单击中没有名称的命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆