1

I want to make a simple CLI program that would accept --edit-config option to open its config in an editor. However, I can't figure out how to make Click ignore Missing Argument error if I specify the --edit-config flag only.

import click

@click.group(invoke_without_command=True)
@click.argument("name")
@click.option("--edit-config", is_flag=True)
def cli(name, edit_config):
    # If we run it like
    # $ myprog --edit-config | Missing Argument: NAME
    if edit_config:
        click.echo("Editing config")
        ...
        exit(0)
    
    # But this is the main functionality
    # $ myprog John
    click.echo(f"Hello, {name}")

@cli.command()
def command_a():
    ...
...

The first command causes Missing Argument error. There can be workarounds, like nargs=-1 or required=False, however, it seems that this makes the help page to either go completely or the name argument to be marked as optional in the help message, which is not true in the majority of use cases.

Is there is a simple way to make Click not raise Missing Argument error if a certain option is specified?

4
  • You could specify a default for name in the click decorator or put the code under an if name: condition. Commented Apr 10, 2021 at 20:37
  • Why is --edit-config an option and not a command at the same level as command_a? Commented Apr 11, 2021 at 16:13
  • 1
    @StephenRauch I thought that --edit-config would be cleaner than a whole subcommand because the usage I'm planning is: default command: myapp John -> Hello John, some other action: myapp John bye -> Bye John and myapp --edit-config to just edit the config. In all usages except when editing config (with click.edit()) you specify John as an argument for the whole program and then do whatever you need with it. So using an option to essentially completely alter the program's behavior seems more logical to me. Commented Apr 11, 2021 at 20:25
  • 1
    @EricTruett default="" behaves like nargs=-1, it marks the argument in help page as optional which is not true, and it also breaks the help page when nothing is passed to myapp. default=None doesn't change anything, the Missing argument error is still raised. Putting the code in if name: ... doesn't work as it is never reached because of the error. Commented Apr 11, 2021 at 20:42

1 Answer 1

1

After reading the docs further I've found this section, which provides a way of implementing --edit-config or any other option that completely alters the execution flow.

def edit_config(ctx, param, value):
    if not value or ctx.resilient_parsing:
        return
    click.echo("Editing config")
    ctx.exit()

@click.group(invoke_without_command=True)
@click.argument("name")
@click.option("--edit-config", is_flag=True, callback=edit_config,
              is_eager=True, expose_value=False)
def cli(name):
    print(f"Hello, {name}!")

@cli.command()
def howareyou():
    print(f"How are you?")
 $ myapp John
Hello, John!

 $ myapp John howareyou
Hello, John!
How are you?

 $ myapp --edit-config
Editing config

 $ myapp --help
Usage: myapp [OPTIONS] NAME COMMAND [ARGS]...

Options:
  --edit-config 
  --help         Show this message and exit.

Commands:
  howareyou
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.