pythonpython-click

Click help text shows 'dynamic' when an option has the default set to a lambda


I have this code in a CLI:

@click.option(
    "--username",
    default=lambda: os.environ.get("USER", None),
    show_default=True,
    help="User name for SSH configuration.",
)

When I invoke the CLI with --help option, I get this:

  --username TEXT         User name for SSH configuration.  [default:
                          (dynamic)]

Is there a way to make click invoke the lambda function and show the actual username instead of (dynamic)? I know I can call that function before invoking the click decorator and pass that retrieved value as the default instead of lambda. I am trying to do better than that.


Solution

  • The Option.get_default method has a call option to call the default value when it's a callable.

    The option is True by default but is passed False only when generating help, so you can make the help generator call the the callable simply by overriding Option.get_default with a wrapper that forces the call option to be True:

    import click
    
    class DefaultCallingOption(click.Option):
        def get_default(self, ctx, call=True):
            return super().get_default(ctx, True)
    

    so that:

    @click.command()
    @click.option(
        "--username",
        default=lambda: 'foo',
        show_default=True,
        help="User name to say hello to.",
        cls=DefaultCallingOption # use the custom Option class
    )
    def hello(username):
        print(f'hello {username}')
    
    hello()
    

    produces the following help when given the --help option in the command line:

    Usage: test.py [OPTIONS]
    
    Options:
      --username TEXT  User name to say hello to.  [default: foo]
      --help           Show this message and exit.