Python click application required parameters have precedence over sub command help option

安稳与你 提交于 2021-02-04 21:19:28

问题


I'm building a click 7.x application with Python 3.6 and am having some issues getting help to work for sub commands. I have a global option that is required and this option is being reported as missing when I run help on any sub command.

For example, given the following dummy script cli.py:

import click


@click.group()
@click.option('--directory', required=True)
def cli(directory):
    """
    this is a tool that has an add and remove command
    """
    click.echo(directory)


@cli.command()
@click.overwrite('--overwrite', is_flag=True)
def add(overwrite):
    """
    this is the add command
    """
    click.echo("add overwrite={}".format(overwrite))


@cli.command()
def remove():
    """
    this is the remove command
    """
    click.echo('remove')


if __name__ == '__main__':
    cli()

When I run the following:

python cli.py --help

I get the desired output of:

Usage cli.py [OPTIONS] COMMAND [ARGS]...

  this is a tool that has an add and remove command

Options:
  --directory TEXT  [required]
  --help            Show this message and exit.

Commands:
  add     this is the add command
  remove  this is the remove command

But if I run this:

python cli.py add --help

I get the following error:

Usage cli.py [OPTIONS] COMMAND [ARGS]...
Try "cli.py --help" for help.

Error: Missing option "--directory"

How do I get the help for the add command to show without having to supply the --directory option?


回答1:


You can use a custom click.Group class to ignore the required args when --help is requested like:

Custom Class:

class IgnoreRequiredWithHelp(click.Group):
    def parse_args(self, ctx, args):
        try:
            return super(IgnoreRequiredWithHelp, self).parse_args(ctx, args)
        except click.MissingParameter as exc:
            if '--help' not in args:
                raise

            # remove the required params so that help can display
            for param in self.params:
                param.required = False
            return super(IgnoreRequiredWithHelp, self).parse_args(ctx, args)

Using the Custom Class:

To use the custom class, pass it as the cls argument to the group decorator like:

@click.group(cls=IgnoreRequiredWithHelp)
....
def my_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.

In this case we over ride click.Group.parse_args() and catch the click.MissingParameter exception. We then negate the required attribute from all of the params, and retry the parse.

Test Code:

import click

@click.group(cls=IgnoreRequiredWithHelp)
@click.option('--directory', required=True)
def cli(directory):
    """
    this is a tool that has an add and remove command
    """
    click.echo(directory)

@cli.command()
@click.option('--overwrite', is_flag=True)
def add(overwrite):
    """
    this is the add command
    """
    click.echo("add overwrite={}".format(overwrite))


@cli.command()
def remove():
    """
    this is the remove command
    """
    click.echo('remove')


if __name__ == "__main__":
    commands = (
        'add --help',
        '--help',
        '--directory a_dir add'
        '',
    )

    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)
            cli(cmd.split())

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

Results:

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)]
-----------
> add --help

Usage: test.py add [OPTIONS]

  this is the add command

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

  this is a tool that has an add and remove command

Options:
  --directory TEXT
  --help            Show this message and exit.

Commands:
  add     this is the add command
  remove  this is the remove command
-----------
> --directory a_dir add
a_dir
add overwrite=False


来源:https://stackoverflow.com/questions/55818737/python-click-application-required-parameters-have-precedence-over-sub-command-he

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!