Package: proper-cli
Proper CLIProper CLI is a Python library for creating composable, nestable, and ridiculously good looking command-line-user-interfaces from simple classes.FeaturesMade for interfacingwith humans.Arbitrary nesting and composition of commands.Automatic help page generationNo need to redeclare paramaters and options with decorators, just write Python methodsThe help of a command is its docstring, why make it more complex?UsageDeclare a class that inherits fromproper_cli.Cli. Every method/attribute that does not starts with an underscore will be a command.fromproper_cliimportCliclassManage(Cli):deffirst(self,arg1,arg2=3):passdefsecond(self):passdef_not_a_command(self):passThen, instance that class and call it.# run.pycli=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:pythonrun.pyfirstfoobaror by name:pythonrun.pyfirst-arg1foo-arg2barTo pass aTrueuse the name without a value, for aFalse, prepend the name of the argument withno-:pythonrun.pyfirst-arg1-no-arg2SubgroupsIf an attribute is a subclass ofproper_cli.Cli, it will be a subgroup:fromproper_cliimportCliclassDBSub(Cli):defmigrate(self):passclassManage(Cli):# A subgroupdb=DBSub# NOT `DBSub()`ContextYou can pass any named argument as context to be used by your commands. This will be stored at the_envattribute.Example:>>>cli=Manage(lorem="ipsum")>>>print(cli._env){"lorem":"ipsum"}An exampleThe image at the top was autogenerated by running this example:# example.pyfromproper_cliimportCliclassDBCli(Cli):"""Database-related commands"""defmigrate(self,message):"""Autogenerate a new revision file.This is an alias for "revision --autogenerate".Arguments:- message: Revision message"""passdefbranches(self):"""Show all branches."""passclassMyCli(Cli):"""Welcome to Proper CLI 3"""defnew(self,path,quiet=False):"""Creates a new Proper application at `path`.Arguments:- path: Where to create the new application.- quiet [False]: Supress all output."""passdefhello(count,name):"""Simple program that greets NAME for a total of COUNT times."""pass# A subgroup!db=DBClicli=MyCli()if__name__=="__main__":cli()Coloring the OutputWhenever you output text, you can surround the text with tags to color its output (thanks tohttps://github.com/sdispater/pastel).
This is automatically enabled for the docstrings, but you can also have it by usingproper_cli.echo()as a drop-in replacement ofprint().# green textecho("<fg=green>foo</fg=green>")# black text on a cyan backgroundecho("<fg=black;bg=cyan>foo</>")# bold text on a yellow backgroundecho("<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.Custom stylesThese four styles are available by default:# green textecho("<info>foo</info>")# yellow textecho("<comment>foo</comment>")# black text on a cyan backgroundecho("<question>foo</question>")# white text on a red backgroundecho("<error>foo</error>")It is possible to define your own styles using theproper_cli.add_style()method:add_style("fire",fg="red",bg="yellow",options=["bold","blink"])echo("<fire>foo</fire>")HelpersBeyond the CLI builder, proper_cli also includes some commonly-used helper functionsconfirm(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.FAQWhy don't just use optparse or argparse?I find it too verbose.Why don't just use click?Are you kidding? Because 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.