3

I have this code that works fine:

import click

@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--team_name', required=True, help='Team name')
@click.option('--input_file', default='url_file.txt', help='Input file name for applications, URLs')
@click.option('--output_file', default='test_results_file.txt', help='Output file name to store test results')
def main(team_name, input_file, output_file):
    # function body

if __name__ == '__main__':
    main()                  # how does this work?

As you see, main is being called with no arguments though it is supposed to receive three. How does this work?

1
  • 2
    This ties into how decorators work. You've applied many of them to click, and presumably your method call to main() goes through all of those decorators before actually reaching the function body of main(). And each of click's decorators adds one parameter in as default, since it wasn't specified in your initial call. So by the time you get down to the actual main() call, the decorators have provided all the default arguments. Commented Jul 15, 2019 at 19:06

1 Answer 1

4

As mentioned in comments, this is taken care by the decorators. The click.command decorator turns the function into an instance of click.Command.

Each of options decorators build an instance of a click.Option and attach it to the click.Command object to be used later.

This click.Command object implements a __call__ method which is invoked by your call to main().

def __call__(self, *args, **kwargs):
    """Alias for :meth:`main`."""
    return self.main(*args, **kwargs)

It is quite simple and simply invokes click.Command.main().

Near the top of click.Command.main() is:

if args is None:
    args = get_os_args()
else:
    args = list(args)

This code gets argv from the command line or uses a provided list of args. Further code in this method does, among other things, the parsing of the command line into a context, and the eventual calling of your main() with the values from the click.Option instances built earlier:

with self.make_context(prog_name, args, **extra) as ctx:
    rv = self.invoke(ctx)

This is the source of the mysterious 3 arguments.

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

2 Comments

By the way, same rules applies if using click.argument?
@zygimantus, once the command handler is called, the Options and Arguments are just their requisite values and are no longer click objects.

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.