Using pyCLI vs commando to create some commands and subcommands.
https://gist.github.com/1202975.git
git clone [email protected]:1202975.git python-hello-subcommand
How to write a well behaved console application? The ones with the best UIs allow configuration of core commands in a flexible config file, can override important defaults from the environment, and use the subcommand pattern to logically organize commands.
It should be tab-completable, with nice help output.
Circa 2013, there's still not a good way to do this. Here are a few attempts.
In terms of frameworks, this one is the only one with the needed pre-setup hook needed to do an initial pass over the arguments to sniff any parameters which might be used to then initialize the rest of the arguments. This happens, for example, when determining which configuration file to use. If we know there is a configuration file, why not make the configured values default?
Goal is to get a combination of tab completion + subcommands in such a way that will allow me to implement independent python modules as a main command, and then re-use the implementation as a subcommand in my main app.
This attempt just uses argparse to iterate over a bunch of example
subcommands. The behavior is pretty close to what we want; it's clear
where to add reading from environment variables, and the set_parser
method offers a nice way to set arguments, regardless of where the
parser came form. argparse does not allow any way of re-using parser
logic for subcommands.
At one point I tried separating the parsing into two phases, one for the core to find the subcommand, and then another to pass the remaining args to the subcommand as a main parser, but autocompletion failed to cope with this setup.
These examples on the other hand are tab completable subcommands with default configuration read from a config file.
$ ./simple
usage: simple [-h] [-d] [-c CONFIG] {qux,fux,bux,lux} ...
optional arguments:
-h, --help show this help message and exit
-d, --debug
-c CONFIG, --config CONFIG
Title Group A:
This is a long description on a simple command.
{qux,fux,bux,lux} some help on group A
$ ./simple
bux --config --debug -h lux
-c -d fux --help qux
$ ./simple lux
final pass Namespace(command='lux', config='example.conf', debug=False, foo='XXX', run=<bound method F.main of <__main__.F object at 0x2417d50>>) None
Hello, I'm lux.
['lux',
'params',
<__main__.F object at 0x2417d50>,
Namespace(command='lux', config='example.conf', debug=False, foo='XXX', run=<bound method F.main of <__main__.F object at 0x2417d50>>)]
$ ./simple qux
final pass Namespace(command='qux', config='example.conf', debug=False, foo='baz', run=<bound method F.main of <__main__.F object at 0x1c632d0>>) None
Hello, I'm qux.
['qux',
'params',
<__main__.F object at 0x1c632d0>,
Namespace(command='qux', config='example.conf', debug=False, foo='baz', run=<bound method F.main of <__main__.F object at 0x1c632d0>>)]
$ ./simple qux --help
usage: simple qux [-h] [--foo FOO]
long desc of qux
optional arguments:
-h, --help show this help message and exit
--foo FOO
So the only thing missing is the default values from the help output.
@n-west on completion: