Cleo 0.2 is now out with a lot of improvements and new features.
What is cleo?
Cleo eases the creation of beautiful and testable command line interfaces.
It is heavily inspired by the Symfony Console Component , with some useful additions.
Full documentation available here: http://cleo.readthedocs.org
Installation
You can install Cleo in two different ways:
Usage
The Application object manages the CLI application:
from cleo import Application
console = Application ()
console . run ()
The run()
method parses the arguments and options passed on the command
line and executes the right command.
Registering a new command can easily be done via the register()
method,
which returns a Command
instance:
from cleo.input import InputArgument , InputOption
def hello ( input_ , output_ ):
name = input_ . get_argument ( 'name' )
output_ . writeln ( 'Hello <info> % s</info>' % name )
console \
. register ( 'hello' ) \
. set_definition ([
InputArgument ( 'name' , InputArgument . REQUIRED , 'The name' ),
]) \
. set_description ( 'Says hello!' ) \
. set_code ( hello )
You can also register new commands via classes.
from cleo import Command
class HelloCommand ( Command ):
def configure ( self ):
self . set_name ( 'hello' ) \
. set_description ( 'Says hello!' ) \
. add_argument ( 'name' , InputArgument . REQUIRED , 'The name' )
def execute ( input_ , output_ ):
name = input_ . get_argument ( 'name' )
output_ . writeln ( 'Hello <info> % s</info>' % name )
console . add ( HelloCommand ())
But it might be a little too verbose for some. That's why commands can also be declared and registered via dictionaries.
hello_command = {
'name' : 'hello' ,
'description' : 'Says hello!' ,
'arguments' : [
'name' : {
'mode' : 'required' ,
'description' : 'The name'
}
],
'code' : hello
}
console . add ( hello_command )
With dictionaries, you will not be able to do as many things as with classes declaration since you won't have access to the Command
instance.
Output coloring
Cleo provides output coloring out of the box, you just need to surround the text with tags:
# green text
output_ . writeln ( '<info>foo</info>' )
# yellow text
output_ . writeln ( '<comment>foo</comment>' )
# black text on a cyan background
output_ . writeln ( '<question>foo</question>' )
# white text on a red background
output_ . writeln ( '<error>foo</error>' )
Those are the default styles but you can easily define your own :
style = OutputFormatterStyle ( 'red' , 'yellow' , [ 'bold' , 'blink' ])
output_ . get_formatter () . set_style ( 'fire' , style )
output_ . writeln ( '<fire>foo</fire>' )
If you don't want to set the styles upfront, you can just as easily set the colors and options inside the tagnames :
# green text
output_ . writeln ( '<fg=green>foo</fg=green>' )
# black text on a cyan background
output_ . writeln ( '<fg=black;bg=cyan>foo</fg=black;bg=cyan>' )
# bold text on a yellow background
output_ . writeln ( '<bg=yellow;options=bold>foo</bg=yellow;options=bold>' )
Testable commands
Cleo provides input and output abstraction so that you can easily unit-test your commands, especially with the CommandTester
class:
from unittest import TestCase
from cleo import Application , CommandTester
class GreetCommandTest ( TestCase ):
def test_execute ( self ):
application = Application ()
application . add ( greet_command )
# Or application.add(GreetCommand()) if using classes
commmand = application . find ( 'demo:greet' )
command_tester = CommandTester ( command )
command_tester . execute ([( 'command' , command . get_name ())])
self . assertRegex ( '...' , command_tester . get_display ())
# ...
Basically, the get_display()
method returns what would have been displayed during a normal call from the console.
Helpers
Cleo comes bundled with some nice helpers that will cover some basic needs when developing command-line interfaces.
The DialogHelper
will, basically, prompt the user for answers:
# ...
if dialog . ask_confirmation (
output_ ,
'<question>Continue with this action?</question>' ,
False
):
# Some code
This code will prompt for a yes/no anwser, while this code:
# ...
name = dialog . ask (
output_ ,
'Please enter your name' ,
'John Doe'
)
will prompt for a more generic answer.
The ProgressHelper
allows you to display a progress bar for actions that might take a while:
progress = self . get_helper_set () . get ( 'progress' )
progress . start ( output_ , 50 )
for _ in range ( 50 )
# ... do some work
# advance the progress bar 1 unit
progress . advance ()
progress . finish ()
And the TableHelper
will display automatically tabular data:
table = app . get_helper_set () . get ( 'table' )
table . set_headers ([ 'ISBN' , 'Title' , 'Author' ])
table . set_rows ([
[ '99921-58-10-7' , 'Divine Comedy' , 'Dante Alighieri' ],
[ '9971-5-0210-0' , 'A Tale of Two Cities' , 'Charles Dickens' ],
[ '960-425-059-0' , 'The Lord of the Rings' , 'J. R. R. Tolkien' ],
[ '80-902734-1-6' , 'And Then There Were None' , 'Agatha Christie' ]
])
table . render ( output_ )
There is a lot more you can do with Cleo, you can just give a look at the documentation: http://cleo.readthedocs.org .
And if you are interested by how it all works, you can just check out the Github Repository , and feel free to contribute.
And, finally, here are some features for the 0.3 version:
Set commands with decorators
Validators for the arguments and options
Autocompletion of commands
You can check the advancement on the Github project