click: Can't access help of subcommands without going through parent's prompts

I have a script with subcommands that both require a username/password. I abstracted this to the parent. Here’s a short example demonstrating the issue:

import click

@click.group()
@click.option('--username', default='admin', prompt=True)
@click.password_option()
def cli(username, password):
    """This is my parent description"""
    pass

@cli.command()
@click.option('--reference', help="I should be able to see this without entering a username and password.")
def subcommand(reference):
    """This is my subcommand"""
    pass

If you access the main help:

my_prog --help

It displays the help page without any prompting for username or password, as expected. However, if you try to access the help page for the subcommand:

my_prog subcommand --help

It prompts for username and password before displaying the help page of the subcommand. This makes sense, but it still isn’t expected behavior by the end user. As my sample program says, I should be able to see help without entering a username and password.

What’s the correct way to model my desired behavior? Do I have to move and duplicate the username and password prompt options into each of my sub commands?

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 15
  • Comments: 15 (3 by maintainers)

Commits related to this issue

Most upvoted comments

This is a tough one to fix and I am not sure if it will be entirely possible without causing more issues elsewhere. 😦

I don’t think this is solvable within Click in a general way.

Click parses and process all args and callbacks for a command before moving on to a subcommand. The subcommand can be resolved dynamically based on the current command’s context, so it’s not possible to guarantee what commands and params will be processed before actually running the pipeline. Additionally, the help option isn’t guaranteed to be --help, and --help could also show up as the value of another option, so it’s not possible to guarantee that --help showing up in the raw args means the help callback will be executed.

There are a few different solutions a project can implement:

  • #1618 will introduce a new prompt_required argument, that changes the behavior of prompts so they’re only shown if the option is required or if the flag without a value is given. This applies to prompts, but it doesn’t apply to missing required parameters.
  • Instead of using prompt=True in the parameters, use a helper function before the values are actually used that will call click.prompt() if they weren’t provided.
  • The parameters can be moved to each command, with a decorator to avoid repetition.
  • The group --help param can be customized to figure out the subcommand and show its help.
  • A dedicated help command (like git help <command name>) is fairly straightforward to implement using group.get_command(ctx, name) and command.get_help(ctx).
  • Use a project like sphinx-click or click-man to generate external documentation.