I am using click within a local module and I would like to adjust how the help is displayed:
Currently output with --help:
Usage: __main__.py [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
foo Foo is a program very nice and pretty...
By default the prog name is __main__.py and the text is trimmed to 78 chars.
I discovered that this can be adjusted using the HelpFormatter class. But I don't know how to use it in this context.
Current Code:
import click
#click.group()
def main(ctx):
pass
#main.command()
def foo():
pass
click.CommandCollection(sources=[main])()
Expected output:
Usage: my_module_name [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
foo Foo is a program very nice and pretty and this sentence is very long.
If you are trying to to avoid the truncation of the help string, this can be accomplished via the short_help parameter. short_help is generally derived from help but truncated. If passed explicitly, the entire string will be displayed.
To display the string my_module_name, that can be passed under the parameter prog_name
Test Code:
import click
#click.group()
def main(ctx):
pass
#main.command(short_help='Foo is a program very nice and pretty and '
'this sentence is very long.')
def foo():
pass
main(['--help'], prog_name='my_module_name')
Results of short_help:
Usage: my_module_name [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
foo Foo is a program very nice and pretty and this sentence is very long.
Related
I have the following click code:
#click.group(invoke_without_command=True)
def cli():
click.echo("Starting CallFlow....")
setup_logging()
# ##################----GEN---##################
#cli.command(help="a sub command")
#click.option(
"--folder", help="Tests folder path", type=str, nargs=1,
)
def sub1(folder):
# run some code here
Running my prog name that uses the above cli like this:
prog-name --help
shows me the correct help text:
Usage: prog-name [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
sub1 Help text
But running
prog-name sub1 --help --folder
I get an error that folder requires an argument like so:
Error: --folder option requires an argument
I thought that --help was an eager parameter and gets evaluated first. shouldn't that produce a help text?
From the documentation, the concept of eagerness refers only to the order of execution. Usually, the command line options will be processed in the order they are defined; making options like --help and --version eager means that they will be evaluated first.
If --help were not eager, your example would require --folder to always be passed first, like:
prog-name sub1 --folder test_folder --help
Context:
I'm having several scripts with loads of sub commands that I'd like to convert to using click
At the moment all these commands do accept -h and --help in order to display help options. I'd like to keep this behavior.
Problem:
click accepts by default --help to display the help text, but not -h
for a click command this can be changed easily by adding.
#click.group()
#click.help_option("--help", "-h")
def cli():
""" the doc string """
enter code here
#cli.command()
#click.help_option("--help", "-h")
def mycommand()
pass
#cli.command()
#click.help_option("--help", "-h")
def mycommand1()
pass
...
However if I'm having tens of commands I have to reapply the decorator line
#click.help_option("--help", "-h")
fort each sub command.
Would there be any trick to avoid having to write this line everywhere?
You need to define a CONTEXT_SETTINGS and use it like this:
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
#click.command(context_settings=CONTEXT_SETTINGS)
def cli():
pass
From the click documentation:
Help Parameter Customization Changelog The help parameter is
implemented in Click in a very special manner. Unlike regular
parameters it’s automatically added by Click for any command and it
performs automatic conflict resolution. By default it’s called --help,
but this can be changed. If a command itself implements a parameter
with the same name, the default help parameter stops accepting it.
There is a context setting that can be used to override the names of
the help parameters called help_option_names.
This example changes the default parameters to -h and --help instead
of just --help:
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
#click.command(context_settings=CONTEXT_SETTINGS) def cli():
pass And what it looks like:
$ cli -h Usage: cli [OPTIONS]
Options: -h, --help Show this message and exit.
I am doing some practice Python exercises and I found one which is asking to create a Python module with various functions. I created a Python package and implemented the functions. So far so good, but a request is that if you call the module with the argument "-h", the message "Help" will be displayed, if the module is being imported, nothing is being displayed. How can we do this, is there any default function that needs to be overwritten? I'm not sure on how can we call a module, I thought we just use a package to better encapsulate our methods
Many thanks and sorry for being noob
Python is an interpreted language, that just starts with the top-level source code no main function, you might have seen in other languages. Files to be imported are written exactly the same way. All of the code, that is outside of functions is executed.
e.g.
myscript.py
def fn(a, b):
return a+b
print(fn(1, 1))
This as a fully working program, printing out the answer to, how much is 1+1. But what if you would like to import it to use the fn function inside another script? Doing import myscript would print 2 (and then finally provide you the fn function). The workaround is checking for __name__ == '__main__': inside myscript.py, which will evaluate to true, when being executed only (e.g. python myscript.py). It will be false otherwise (import myscript).
See the related Q&A.
Reference: https://docs.python.org/2/howto/argparse.html
$ cat sample.py
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--foo", help="sample argument", action="store", dest='foo')
args = parser.parse_args()
if args.foo:
print("foo = {}".format(args.foo))
$ python sample.py --help
$ python sample.py --help
usage: sample.py [-h] [--foo FOO]
optional arguments:
-h, --help show this help message and exit
--foo FOO sample argument
$
$ python sample.py --foo argument_value
$ python sample.py --foo bar
foo = bar
$ python sample.py --foo=10
foo = 10
$
I am trying to make my python script very user friendly, so I like to write some sort of help for it. What is your advise for this? I could just put in some logic that if the user passed help as a paramater to the script, they get help. Is there a best practise or convention for this?
Use argparse.
For example, with test.py:
import argparse
parser=argparse.ArgumentParser(
description='''My Description. And what a lovely description it is. ''',
epilog="""All is well that ends well.""")
parser.add_argument('--foo', type=int, default=42, help='FOO!')
parser.add_argument('bar', nargs='*', default=[1, 2, 3], help='BAR!')
args=parser.parse_args()
Running
% test.py -h
yields
usage: test.py [-h] [--foo FOO] [bar [bar ...]]
My Description. And what a lovely description it is.
positional arguments:
bar BAR!
optional arguments:
-h, --help show this help message and exit
--foo FOO FOO!
All is well that ends well.
Best practice is to use argparse to handle all your commandline arguments. It includes a default --help which you can customize to your likings.
Here's the simplest example:
import argparse
parser = argparse.ArgumentParser(description='This is my help')
args = parser.parse_args()
Which results in:
% python argparse_test.py -h
usage: argparse_test.py [-h]
This is my help
optional arguments:
-h, --help show this help message and exit
You can define all your arguments with argparse and set a help message for each one of them. The resulting filtered/validated arguments are returned by parser.parse_args().
An alternative to the built-in argparse is a 3rd-party package called Click which features "automatic help page generation" and "arbitrary nesting of commands" (which also produces nested help pages). Internally, it's based on argparse, but, for me, makes the creation of complex CLI more convenient using decorators.
Here's a sample code:
import click
#click.command()
#click.argument("things", nargs=-1)
#click.option("-t", show_default=True, default="int", help="Data type")
#click.option("-o", help="Output format")
def combine(things, t):
"""Combines things into a single element"""
pass
if __name__ == "__main__":
combine()
And the generated help page:
$ python myapp.py --help
Usage: myapp.py [OPTIONS] [THINGS]...
Combines things into a single element
Options:
-t TEXT Data type [default: int]
-o TEXT Output format
--help Show this message and exit.
One of the nice things about it is that it uses the method docstrings as part of the help page, which is convenient because the docstring can now be used both for developer documentation and for script usage help.
You can also have nested command groups:
import click
#click.command()
#click.argument("numbers", nargs=-1)
#click.option("-e", help="Extra option for add")
def add(numbers, e):
"""Adds numbers"""
print(f"This method should add {numbers}")
#click.command()
#click.argument("numbers", nargs=-1)
#click.option("-e", help="Extra option for mul")
def mul(numbers, e):
"""Multiplies numbers"""
print(f"This method should multiply {numbers}")
#click.group()
def calc():
pass
calc.add_command(add)
calc.add_command(mul)
if __name__ == "__main__":
calc()
And it will produce nested help pages:
$ python myapp.py --help
Usage: myapp.py [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
add Adds numbers
mul Multiplies numbers
$ python myapp.py add --help
Usage: myapp.py add [OPTIONS] [NUMBERS]...
Adds numbers
Options:
-e TEXT Extra option for add
--help Show this message and exit.
$ python myapp.py mul --help
Usage: myapp.py mul [OPTIONS] [NUMBERS]...
Multiplies numbers
Options:
-e TEXT Extra option for mul
--help Show this message and exit.
For more information, see the Documenting Scripts section of the docs.
How can I disable printing subcommand choices, the ones between curly brackets? Using an example at http://docs.python.org/dev/library/argparse.html#sub-commands, the normal output is:
usage: [-h] {foo,bar} ...
optional arguments:
-h, --help show this help message and exit
subcommands:
{foo,bar} additional help
What I want is to print this:
usage: [-h] {foo,bar} ...
optional arguments:
-h, --help show this help message and exit
subcommands:
Removing just the last line.
To avoid spamming my users with the huge ugly curly-braced list of dozens of sub-commands, I simply set the metavar attribute of the subcommand object. My code looks like:
import argparse
parser = argparse.ArgumentParser(description='Stack Overflow example')
subs = parser.add_subparsers()
subs.metavar = 'subcommand'
sub = subs.add_parser('one', help='does something once')
sub = subs.add_parser('two', help='does something twice')
parser.parse_args()
And the output of running this script with a single -h argument is:
usage: tmp.py [-h] subcommand ...
Stack Overflow example
positional arguments:
subcommand
one does something once
two does something twice
optional arguments:
-h, --help show this help message and exit
The result is not exactly what you illustrate as your best desired case, but I think that it may be the closest you can get without subclassing argparse.ArgumentParser and overriding the things you need adjusted, which would be messy work.
Override ArgumentParser.print_usage() with your own method to print whatever, however you want. If all you want to do is eliminate the last line, call the original version, capture the results (by sending it to a file) and print just the part(s) you want.