python3 --help
usage: python3 [option] ... [-c cmd | -m mod | file | -] [arg] ...
Options (and corresponding environment variables):
...
file
and [arg]...
in sys.argv
# %load ../../args.py
import sys
print(sys.argv)
%py ../../args.py -v 1 2 3 Hello
['../../args.py', '-v', '1', '2', '3', 'Hello']
--help
Program usage
--verbose
Diagnostics
--path test
Testing
app COMMAND
Subcommands to execute diferent tasks
app TEMPERATURE
Validate the data
['../../args.py', '-v', '1', '2', '3', 'Hello']
Parse the list
Validate, convert and store in variables
Issue error messages
Supply default values
Create usage information
There are various options, we will cover these here:
Tool | Comment |
---|---|
argparse |
In the Python standard library, used by other standard library modules and in Django, Alembic, Jupyter, Rich |
Click | Created by the author of Flask |
Typer | Based on Click, optionally uses Rich for color, panels and text alignment |
argparse
¶import argparse
parser = argparse.ArgumentParser()
args = parser.parse_args()
if args.attribute:
#do something
minimal.py
print('Running!')
minimal.py
import argparse
parser = argparse.ArgumentParser()
args = parser.parse_args()
print('Running!')
%py minimal.py
Running!
%py minimal.py Pizza
usage: minimal.py [-h] minimal.py: error: unrecognized arguments: Pizza
%py minimal.py -h
usage: minimal.py [-h] options: -h, --help show this help message and exit
product
# %load product.py
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('product', help='a product name')
args = parser.parse_args()
print('Running!', args.product)
%py product.py -h
usage: product.py [-h] product positional arguments: product a product name options: -h, --help show this help message and exit
%py product.py Pizza
Running! Pizza
Missing parameter:
%py product.py
usage: product.py [-h] product product.py: error: the following arguments are required: product
[--count COUNT]
# %load option.py
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('product', help='a product name')
parser.add_argument('--count', help='a count')
args = parser.parse_args()
print('Running!', args.product, args.count)
%py option.py -h
usage: option.py [-h] [--count COUNT] product positional arguments: product a product name options: -h, --help show this help message and exit --count COUNT a count
%py option.py Sandwich --count 5
Running! Sandwich 5
%py option.py Sandwich
Running! Sandwich None
%py option.py Pie --count ''
Running! Pie
👍 We can check if an option is absent:
if arg.c is None:
print('-c was not supplied')
# %load flag.py
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('product', help='a product name')
parser.add_argument('--count', help='a count')
parser.add_argument('-v', action='store_true',
help='show more information')
args = parser.parse_args()
if args.v:
print('Starting')
print('Running!', args.product, args.count)
if args.v:
print('Ending')
%py flag.py Desert -h
usage: flag.py [-h] [--count COUNT] [-v] product positional arguments: product a product name options: -h, --help show this help message and exit --count COUNT a count -v show more information
%py flag.py Desert -v
Starting Running! Desert None Ending
# %load prog.py
import argparse
parser = argparse.ArgumentParser(
usage='%(prog)s [OPTIONS] PRODUCT',
description='Displays a product and count.',
epilog='A fist CLI app.')
parser.add_argument('product', metavar='PRODUCT', help='product name')
parser.add_argument('--count', metavar='NUMBER')
parser.add_argument('-v', action='store_true',
help='show more information')
args = parser.parse_args()
if args.v:
print('Starting')
print('Running!', args.product, args.c)
if args.v:
print('Ending')
%py prog.py -h
usage: prog.py [OPTIONS] PRODUCT Displays a product and count. positional arguments: PRODUCT product name options: -h, --help show this help message and exit --count NUMBER -v show more information A fist CLI app.
Click
¶# %load click/help.py
import click
@click.command()
@click.argument('product')
@click.option('--count')
@click.option('-v', is_flag=True, help='Show more information.')
def main(product, count, v):
"""Displays a product and count.
PRODUCT is the product name"""
if v:
print('Starting')
print('Running!', product, count)
if v:
print('Ending')
main()
%py click/help.py --help
Usage: help.py [OPTIONS] PRODUCT Displays a product and count. PRODUCT is the product name Options: --count TEXT -v Show more information. --help Show this message and exit.
%py click/help.py
Usage: help.py [OPTIONS] PRODUCT Try 'help.py --help' for help. Error: Missing argument 'PRODUCT'.
Exit code is 2
Typer
¶# %load typer/prog1.py
#! /usr/bin/python3
import typer
def main(product: str, count: int=None,
v: bool=typer.Option(False, '-v',
help="Show more information.")):
"""Displays a product and count.
PRODUCT is the product name"""
if v:
print('Starting')
print('Running!', product, count)
if v:
print('Ending')
typer.run(main)
%py typer/prog1.py --help
Usage: prog1.py [OPTIONS] PRODUCT
Displays a product and count.
PRODUCT is the product name
╭─ Arguments ─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ * product TEXT [default: None] [required] │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ───────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ --count INTEGER [default: None] │ │ -v Show more information. │ │ --help Show this message and exit. │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
# %load typer/prog.py
#! /usr/bin/python3
import typer
app = typer.Typer()
@app.command()
def main(product: str, count: int=None,
v: bool=typer.Option(False, '-v',
help="Show more information.")):
"""Displays a product and count.
PRODUCT is the product name"""
if v:
print('Starting')
print('Running!', product, count)
if v:
print('Ending')
app()
%py typer/prog.py --help
Usage: prog.py [OPTIONS] PRODUCT
Displays a product and count.
PRODUCT is the product name
╭─ Arguments ─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ * product TEXT [default: None] [required] │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ───────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ --count INTEGER [default: None] │ │ -v Show more information. │ │ --install-completion [bash|zsh|fish|powershell|pwsh] Install completion for the specified shell. │ │ [default: None] │ │ --show-completion [bash|zsh|fish|powershell|pwsh] Show completion for the specified shell, to copy │ │ it or customize the installation. │ │ [default: None] │ │ --help Show this message and exit. │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
app.py
def mul(a: float, b: float) -> float:
'Display the result of a times b.'
print(a*b)
def concat(source: str, target: str, upper: bool = False):
'Display the concatenation of source and target.'
if upper:
print((source + target).upper())
else:
print(source + target)
def add(numbers) -> int:
'Return the sum of one or more numbers'
print(sum(numbers))
Click
and of type hints in Typer
reduces linesargparse
> click
> typer
%py ../argparse/app.py
usage: app.py [-h] {mul,concat,add} ... positional arguments: {mul,concat,add} mul Return a x b. concat Return source and target concatenated. add Return the sum of one or more numbers options: -h, --help show this help message and exit
%py ../click/app.py
Usage: app.py [OPTIONS] COMMAND [ARGS]... Options: --help Show this message and exit. Commands: add Return the sum of one or more numbers concat Return source and target concatenated. mul Return a x b.
%py ../typer/app-no-comp.py --help
Usage: app-no-comp.py [OPTIONS] COMMAND [ARGS]...
╭─ Options ───────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ --help Show this message and exit. │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ add Return the sum of one or more numbers │ │ concat Return source and target concatenated. │ │ mul Return a x b. │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
%py ../argparse/app.py concat Py thon --upper
PYTHON
%py ../typer/app.py mul 5 3
15.0
%py ../click/app.py add 1 2 3 4
10
argparse
is not required by default. To change this:subparsers = parser.add_subparsers(required=True)
click
and typer
use the docstrings of the functions as the subcommand help. For argparse
use:add_parser('add', help=add.__doc__)
typer
includes auto completeRequires adding #! /usr/bin/python3
to the script
Feature | argparse | Click | Typer |
---|---|---|---|
Usage | yes | yes | yes |
Help | yes | yes | yes |
Internationalization | yes | yes | yes |
Argument type and validation | yes | yes | yes |
Custom type and validation | yes | yes | yes |
File type | yes | yes | yes |
Mix options and positionals | yes | yes | yes |
Choices | yes | yes | yes |
Zero or more values [N [N ...]] |
yes | yes | yes |
Display name | yes | yes | yes |
Count | yes | yes | yes |
Mutually exclusive options [-v|-q] |
yes | yes | yes |
Dispatch a function | yes | yes | yes |
Subcommands | yes | yes | yes |
Command alias | yes | yes | yes |
Feature | argparse | Click | Typer |
---|---|---|---|
Environment variables | yes | yes | |
Prompt | yes | yes | |
- Hide entry text | yes | yes | |
Confirmation prompt [y/n] |
yes | yes | |
--accept/--reject |
yes | yes | |
Invocation Context | yes | yes | |
Nested subcommands | yes | yes | |
Color | yes | yes | |
Tables, panels, alignment | yes | yes | |
Create auto completion scripts | yes | yes |
rich
¶from rich import print
print(sys.path)
[ '/home/pp/Documents/learn/python/run/create-a-cli-in-python', '/usr/lib/python311.zip', '/usr/lib/python3.11', '/usr/lib/python3.11/lib-dynload', '', '/home/pp/envs/jupyter/lib/python3.11/site-packages' ]
python3 -m rich.pretty
python3 -m rich.table
python3 -m rich.progress
Add two línes:
from rich_argparse import RichHelpFormatter
parser = argparse.ArgumentParser(formatter_class=RichHelpFormatter)
%py ../argparse/app-color.py --help
Usage: app-color.py [-h] {mul,concat,add} ... Positional Arguments: {mul,concat,add} Options: -h, --help show this help message and exit