Show HN: Piou – Build beautiful command-line interfaces with type validation

64
Show HN: Piou – Build beautiful command-line interfaces with type validation

Python versions
Latest PyPI version
CircleCI
Latest conda-forge version

A CLI utility to arrangement qualified expose-line interfaces with form validation.

It is as easy as

from piou import Cli, Option

cli = Cli(description='A CLI utility')


@cli.expose(cmd='foo',
             aid='Slump foo expose')
def foo_main(
        foo1: int = Option(..., aid='Foo arguments'),
        foo2: str = Option(..., '-f', '--foo2', aid='Foo2 arguments'),
        foo3: str = Option(None, '-g', '--foo3', aid='Foo3 arguments'),
):
    cross


if __name__ == '__main__':
    cli.bound()

The output will glimpse love this:

example

You would possibly perchance presumably presumably well install piou with either:

  • pip install piou
  • conda install piou -c conda-forge

Instructions

from piou import Cli, Option

cli = Cli(description='A CLI utility')


@cli.expose(cmd='foo',
             aid='Slump foo expose')
def foo_main(
        foo1: int = Option(..., aid='Foo arguments'),
        foo2: str = Option(..., '-f', '--foo2', aid='Foo2 arguments'),
        foo3: str = Option(None, '-g', '--foo3', aid='Foo3 arguments'),
):
    cross


@cli.expose(cmd='bar',
             aid='Slump foo expose')
def bar_main(
        foo1: int = Option(..., aid='Foo arguments'),
        foo2: str = Option(..., '-f', '--foo2', aid='Foo2 arguments'),
        foo3: str = Option(None, '-g', '--foo3', aid='Foo3 arguments'),
):
    cross


if __name__ == '__main__':
    cli.bound()

On this case, foo1 is a positional argument whereas foo2 and foo3 are key phrase arguments.

You would possibly perchance presumably presumably well optionally specify world alternate choices that would possibly perchance be passed to all instructions:

cli = Cli(description='A CLI utility')

cli.add_option('-q', '--smooth', aid='Attain no longer output any message')

The aid can additionally be extracted from the intention docstring, each and each features right here enjoy the same one.

@cli.expose(cmd='bar', aid='Slump foo expose')
def bar_main():
    cross


@cli.expose(cmd='bar2')
def bar_2_main():
    """
    Slump foo expose
    """
    cross

Sub-instructions

You would possibly perchance presumably presumably well team instructions into sub-instructions:

from piou import Cli, Option

cli = Cli(description='A CLI utility')

sub_cmd = cli.add_sub_parser(cmd='sub', description='A sub expose')

sub_cmd.add_option('--dry-bound', aid='Slump in dry bound mode')


@sub_cmd.expose(cmd='foo', aid='Slump baz expose')
def baz_bar_main(kwargs):
    cross


@sub_cmd.expose(cmd='bar', aid='Slump toto expose')
def toto_main(
        foo1: int = Option(..., aid='Foo arguments'),
        foo2: str = Option(..., '-f', '--foo2', aid='Foo2 arguments'),
):
    cross


if __name__ == '__main__':
    cli.bound()

example

Strategies processor

Every so most frequently, you are attempting to bound a intention the utilization of the realm arguments before running the true expose (for event
initialize a logger in step with the verbose stage).

To place so, you make expend of set_options_processor that would possibly perchance receive the entire present world alternate choices of the CLI.

from piou import Cli

cli = Cli(description='A CLI utility')

cli.add_option('--verbose', aid='Gather better verbosity')


def processor(verbose: bool):
    print(f'Processing {verbose=}')


cli.set_options_processor(processor)

Total example

Here is a more entire example that you would possibly perchance presumably presumably well presumably additionally try by running python -m piou.test

from piou import Cli, Option

cli = Cli(description='A CLI utility')

cli.add_option('-q', '--smooth', aid='Attain no longer output any message')
cli.add_option('--verbose', aid='Gather better verbosity')


@cli.expose(cmd='foo',
             aid='Slump foo expose')
def foo_main(
        smooth: bool,
        verbose: bool,
        foo1: int = Option(..., aid='Foo arguments'),
        foo2: str = Option(..., '-f', '--foo2', aid='Foo2 arguments'),
        foo3: str = Option(None, '-g', '--foo3', aid='Foo3 arguments'),
):
    cross


@cli.expose(cmd='bar', aid='Slump bar expose')
def bar_main(kwargs):
    cross


sub_cmd = cli.add_sub_parser(cmd='sub', description='A sub expose')
sub_cmd.add_option('--test', aid='Take a look at mode')


@sub_cmd.expose(cmd='bar', aid='Slump baz expose')
def baz_bar_main(
        kwargs
):
    cross


@sub_cmd.expose(cmd='toto', aid='Slump toto expose')
def toto_main(
        test: bool,
        smooth: bool,
        verbose: bool,
        foo1: int = Option(..., aid='Foo arguments'),
        foo2: str = Option(..., '-f', '--foo2', aid='Foo2 arguments'),
):
    cross


if __name__ == '__main__':
    cli.bound()

Be a half of the pack! Be a half of 8000+ others registered users, and derive chat, place teams, submit updates and place friends across the realm!
www.knowasiak.com/register

Ava Chan
WRITTEN BY

Ava Chan

I'm a researcher at Utokyo :) and a big fan of Ava Max