A CLI toolkit
Project description
Piou
A CLI tool to build beautiful command-line interfaces with type validation.
It is as simple as
from piou import Cli, Option
cli = Cli(description='A CLI tool')
@cli.command(cmd='foo', help='Run foo command')
def foo_main(
bar: int = Option(..., help='Bar positional argument (required)'),
baz: str = Option(..., '-b', '--baz', help='Baz keyword argument (required)'),
foo: str = Option(None, '--foo', help='Foo keyword argument'),
):
pass
if __name__ == '__main__':
cli.run()
The output will look like this:
Why ?
I could not find a library that provided:
- the same developer experience than FastAPI
- customization of the interface (to build a CLI similar to the one of Poetry)
- type validation / casting
Typer is the closest alternative in terms of experience but lacks the possibility to format the output is a custom way using external libraries (like Rich).
Piou provides all these possibilities and lets you define your own Formatter.
Install
You can install piou
with either:
pip install piou
conda install piou -c conda-forge
Features
Commands
from piou import Cli, Option
cli = Cli(description='A CLI tool')
@cli.command(cmd='foo',
help='Run foo command')
def foo_main(
foo1: int = Option(..., help='Foo arguments'),
foo2: str = Option(..., '-f', '--foo2', help='Foo2 arguments'),
foo3: str = Option(None, '-g', '--foo3', help='Foo3 arguments'),
):
pass
@cli.command(cmd='bar',
help='Run bar command')
def bar_main(
foo1: int = Option(..., help='Foo arguments'),
foo2: str = Option(..., '-f', '--foo2', help='Foo2 arguments'),
foo3: str = Option(None, '-g', '--foo3', help='Foo3 arguments'),
):
pass
if __name__ == '__main__':
cli.run()
In this case, foo1
is a positional argument while foo2
and foo3
are keyword arguments.
You can optionally specify global options that will be passed to all commands:
cli = Cli(description='A CLI tool')
cli.add_option('-q', '--quiet', help='Do not output any message')
The help can also be extracted from the function docstring, both functions here have the same one.
@cli.command(cmd='bar', help='Run foo command')
def bar_main():
pass
@cli.command(cmd='bar2')
def bar_2_main():
"""
Run foo command
"""
pass
A command can also be asynchronous, it will be run automatically using asyncio.run
.
@cli.command(cmd='bar', help='Run foo command')
async def bar_main():
pass
Command Groups / Sub-commands
You can group commands into sub-commands:
from piou import Cli, Option
cli = Cli(description='A CLI tool')
@cli.command(cmd='foo', help='Run foo command')
def foo_main():
pass
sub_cmd = cli.add_sub_parser(cmd='sub', description='A sub command')
sub_cmd.add_option('--test', help='Test mode')
@sub_cmd.command(cmd='bar', help='Run bar command')
def sub_bar_main(**kwargs):
pass
@sub_cmd.command(cmd='foo', help='Run foo command')
def sub_foo_main(
test: bool,
foo1: int = Option(..., help='Foo argument'),
foo2: str = Option(..., '-f', '--foo2', help='Foo2 argument'),
):
pass
if __name__ == '__main__':
cli.run()
So when running python run.py sub -h
it will output the following:
Options processor
Sometimes, you want to run a function using the global arguments before running the actual command (for instance
initialize a logger based on the verbose
level).
To do so, you use set_options_processor
that will receive all the current global options of the CLI.
from piou import Cli
cli = Cli(description='A CLI tool')
cli.add_option('--verbose', help='Increase verbosity')
def processor(verbose: bool):
print(f'Processing {verbose=}')
cli.set_options_processor(processor)
Help / Errors Formatter
You can customize the help and the different errors displayed by the CLI by passing a Formatter.
The default one is the Rich formatter:
cmd_color
: set the color of the command in the helpoption_color
: set the color of the positional / keyword arguments in the helpshow_default
: show the default values if the keyword arguments (if available)
You can create your own Formatter by subclassing the Formatter
class (see the Rich formatter
for example).
Complete example
You can try a more complete example by running python -m piou.test
Moving from argparse
If you are migrating code from argparse
to piou
here are some differences:
add_argument('--pick', choices=['foo', 'bar'])
is replaced withpick: Literal['foo', 'bar'] = Option(None, '--pick')
add_argument('--verbose', action='store_true')
is replaced withverbose: bool = Option(False, '--verbose')
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.