Composable, nestable, and ridiculously good looking CLI interfaces
Project description
Proper CLI
Proper CLI is a Python library for creating composable, nestable, and ridiculously good looking command-line-user-interfaces from simple classes.
Features
- 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?
Usage
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):
pass
Then, 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 bar
or by name:
python run.py first -arg1 foo -arg2 bar
To 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-arg2
Subgroups
If 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()`
Context
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"}
An example
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()
Coloring the Output
Whenever you output text, you can surround the text with tags to color its output
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("<color fg:green-3>foo</color>")
# bold green text
echo("<color fg:green-3 b>foo</color>")
# black text on a cyan background
echo("<color fg:cyan-1 r>foo</color>")
# italic underlined yellow text
echo("<color fg:yellow-2 iu>foo</color>")
The available styles are: bold (b), italic (i), underline (u), strikeout (s), reverse (r), and dim (d)
The closing tag </color> revokes all formatting options established by the last opened tag.
Run proper_cli/colors.py directly to preview the full palette of available colors in your terminal:
Helpers
Beyond the CLI builder, proper_cli also includes some commonly-used helper functions
confirm(question, default=False, yes_choices=YES_CHOICES, no_choices=NO_CHOICES)
Ask a yes/no question via and return their answer.
ask(question, default=None, alternatives=None)
Ask a question via input() and return their answer.
API
Everything below is importable directly from proper_cli.
Cli class
Base class for a command group. Subclass it; every method and attribute whose name does not start with an underscore becomes a command (or a subgroup, if it is itself a Cli subclass).
Cli(
*,
parent: str = "",
indent: str = " ",
initial_indent: str = " ",
indent_start: int = 0,
show_params: bool = True,
colors: dict[str, str] | None = None,
**env,
)
parent: Prefix shown in the generated usage line. Set automatically fromsys.argv[0]when the instance is called.indent,initial_indent,indent_start: Control the indentation of the help page.show_params: WhenFalse, command arguments and options are omitted from the help page.colors: A dict mapping the components of the help page to color strings, i.e.:"command": "fg:lime-2".**env: Arbitrary context, stored as the_envdict and inherited by subgroups.
Calling the instance (cli()) parses sys.argv, dispatches to the matching command or subgroup, and prints the help page when no command is given or --help is passed.
FAQ
Why don't just use optparse or argparse?
I find it too verbose.
Why don't just use click?
ABecause this looks better and is easier to use and understand.
Why don't just use...?
Because this library fits better my mental model. I hope it matches yours as well.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file proper_cli-2.0.0.tar.gz.
File metadata
- Download URL: proper_cli-2.0.0.tar.gz
- Upload date:
- Size: 15.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1a3713706bcb0b9c4e17bb2e430b735df373724f2427ce4f1067f65776039166
|
|
| MD5 |
be6c235908f6d3fc5b04cfe31a16e970
|
|
| BLAKE2b-256 |
f84a206e06a40b4379444cb3c251f5ecd7883c19b01287a61185ad64c73cf581
|
File details
Details for the file proper_cli-2.0.0-py3-none-any.whl.
File metadata
- Download URL: proper_cli-2.0.0-py3-none-any.whl
- Upload date:
- Size: 10.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a1a997a6aabf1adb317d96d31bc3ffb5aa501c947a03c6e533c582c199459e3f
|
|
| MD5 |
9ecc5ccda0d70efff8850720bb29f300
|
|
| BLAKE2b-256 |
e55944cc79b68dc88d61a4cc341c2bf538593ff0e6572be933bbe6495de41042
|