One nuisance with building command line options in argparse, click, or any other system is duplicates in the parameter list. When using argparse, I would call various functions to add a set of arguments to my ArgumentParser (e.g., for shared output parameters/configuration):
# shared_args.py
def add_output_arguments(parser: ArgumentParser):
"""A function that can be called from multiple
parser.add_argument('--outdir')
parser.add_argument('--filetype', default='csv')
parser.add_argument('--encoding', default='utf8')
# etc.
return parser
# do_something.py
parser = ArgumentParser()
parser.add_argument('--file')
parser = add_output_arguments(parser)
main(**vars(parser.parse_args()))
Treat the above (and below) as pseudocode, but hopefully they gets the idea across.
With click, however, figuring out how to do this is less clear since everything is built using decorators. A single variable can be used to store an argument or command:
# shared_args.py
outdir = click.option('--outdir')
filetype = click.option('--filetype', default='csv')
encoding = click.option('--encoding', default='utf8')
# do_something.py
@command()
@click.argument('file')
@outdir
@filetype
@encoding
def main(file, outdir, filetype, encoding):
...
Yes, but this still isn’t as good as argparse‘s solution of calling a function. I want all of these options to always be added, and not forget to add one. They should be treated as a group — all or nothing.
One solution is to place these into a function, with each of these options nested inside another one (i.e., manually transcribing the decorator).
# shared_args.py
outdir = click.option('--outdir')
filetype = click.option('--filetype', default='csv')
encoding = click.option('--encoding', default='utf8')
def output_arguments(func):
return outdir(filetype(encoding(func)))
# do_something.py
@command()
@click.argument('file')
@output_arguments
def main(file, **output_arguments):
result = do_something(file)
build_output(result, **output_arguments)
Now, multiple functions can all be decorated with the same options. More importantly, if I wanted to add an option, I would only need to update the output_arguments function and build_output and things would just work.