Proper CLI is a Python library for creating composable, nestable, and ridiculously good looking command-line-user-interfaces from simple classes.
- Made for interfacing with humans.
- Arbitrary nesting and composition of commands.
- Automatic help page generation
- No need to redeclare paramaters and options with decorators, just write Python methods
- The help of a command is its docstring, why make it more complex?
Declare a class that inherits from proper_cli.Cli. Every method/attribute that does not starts with an underscore will be a command.
from proper_cli import Cli
class Manage(Cli):
    def first(self, arg1, arg2=3):
        pass
    def second(self):
        pass
    def _not_a_command(self):
        passThen, instance that class and call it.
# run.py
cli = Manage()
if __name__ == "__main__":
    cli()The class dosctring will be printed at the beginning of the help page.
The arguments can be then passed by position:
python run.py first foo baror by name:
python run.py first -arg1 foo -arg2 barTo pass a True use the name without a value, for a False, prepend the name of the argument with no-:
python run.py first -arg1 -no-arg2If an attribute is a subclass of proper_cli.Cli, it will be a subgroup:
from proper_cli import Cli
class DBSub(Cli):
    def migrate(self):
        pass
class Manage(Cli):
    # A subgroup
    db = DBSub  # NOT `DBSub()`You can pass any named argument as context to be used by your commands. This will be stored at the _env attribute.
Example:
>>> cli = Manage(lorem="ipsum")
>>> print(cli._env)
{"lorem": "ipsum"}The image at the top was autogenerated by running this example:
# example.py
from proper_cli import Cli
class DBCli(Cli):
    """Database-related commands
    """
    def migrate(self, message):
        """Autogenerate a new revision file.
        This is an alias for "revision --autogenerate".
        Arguments:
        - message: Revision message
        """
        pass
    def branches(self):
        """Show all branches."""
        pass
class MyCli(Cli):
    """Welcome to Proper CLI 3
    """
    def new(self, path, quiet=False):
        """Creates a new Proper application at `path`.
        Arguments:
        - path: Where to create the new application.
        - quiet [False]: Supress all output.
        """
        pass
    def hello(count, name):
        """Simple program that greets NAME for a total of COUNT times."""
        pass
    # A subgroup!
    db = DBCli
cli = MyCli()
if __name__ == "__main__":
    cli()Whenever you output text, you can surround the text with tags to color its output (thanks to https://github.com/sdispater/pastel).
This is automatically enabled for the docstrings, but you can also have it by using proper_cli.echo()
as a drop-in replacement of print().
# green text
echo("<fg=green>foo</fg=green>")
# black text on a cyan background
echo("<fg=black;bg=cyan>foo</>")
# bold text on a yellow background
echo("<bg=yellow;options=bold>foo</>")Available foreground and background colors are: black, red, green, yellow, blue, magenta, cyan and white.
The available options are: bold, underscore, blink, reverse and conceal.
The closing tag can be replaced by </>, which revokes all formatting options established by the last opened tag.
These four styles are available by default:
# green text
echo("<info>foo</info>")
# yellow text
echo("<comment>foo</comment>")
# black text on a cyan background
echo("<question>foo</question>")
# white text on a red background
echo("<error>foo</error>")It is possible to define your own styles using the proper_cli.add_style() method:
add_style("fire", fg="red", bg="yellow", options=["bold", "blink"])
echo("<fire>foo</fire>")Beyond the CLI builder, proper_cli also includes some commonly-used helper functions
Ask a yes/no question via and return their answer.
Ask a question via input() and return their answer.
I find it too verbose.
Are you kidding? Because this looks better and is easier to use and understand.
Because this library fits better my mental model. I hope it matches yours as well.
