How to

Create and customise your CLI

Add commands

Commands are generated from the ‘commands’ dictionary passed to ArgParse.

Just add entry to the dictonary as key: command name, value: command function or class.

With a function:

entry_point.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class EntryPoint:
    def __init__(self):
        self.commands = {
            'test': self.test_command
        }
        self.arg_parse_opt = {
            'description': 'Test CLI.'
        }

    def test_command(self):
        print('Hello World')

    def run(self):
        ArgParser(self.arg_parse_opt, self.commands).parse()


if __name__ == '__main__':
    EntryPoint().run()
$ python entry_point.py test
Hello World

With a class:

entry_point.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class TestCommand:
    def run(self):
        print('Hello World')


class EntryPoint:
    def __init__(self):
        self.commands = {
            'test': TestCommand
        }
        self.arg_parse_opt = {
            'description': 'Test CLI.'
        }

    def run(self):
        ArgParser(self.arg_parse_opt, self.commands).parse()


if __name__ == '__main__':
    EntryPoint().run()
$ python entry_point.py test
Hello World

Notice that we only pass the class in the commands dictionary, parser will instantiate and call the run method by itself, this is to avoid useless class instantiation.

Tip

If you need to give parameters to your classe, one option is to use partial.

Setup command arguments

Command arguments is generated from the function signature, function required parameters will result in command arguments and function optional parameters in command optional arguments.

1
2
def test_command(req_arg, opt_arg='default'):
    print('{} {}'.format(req_arg, opt_arg))
$ python entry_point.py test Hello
Hello default

$ python entry_point.py test Hello --opt_arg=World
Hello World

Customise command helper

Helper are generated from the function docstring, first line of docstring is for the command description and docstring param for the command arguments.

1
2
3
4
5
6
7
8
def test_command(req_arg, opt_arg='default'):
    """
    Testing command.

    :param str req_arg: required argument.
    :param str opt_arg: optional argument.
    """
    print('{} {}'.format(req_arg, opt_arg))
$ python entry_point.py -h
usage: entry_point.py [-h] {test} ...

Test CLI.

positional arguments:
  {test}
    test              Testing command.

optional arguments:
  -h, --help         show this help message and exit

$ python entry_point.py dev -h
usage: entry_point.py dev [-h] [--opt_arg opt_arg] req_arg

positional arguments:
  req_arg            required argument.

optional arguments:
  -h, --help         show this help message and exit
  --opt_arg opt_arg  optional argument.

Define a list of choices for a command

You can define a list of choices by using annotation.

1
2
3
4
5
6
7
8
def test_command(req_arg: ['foo', 'bar'], opt_arg='default'):
    """
    Testing command.

    :param str req_arg: required argument.
    :param str opt_arg: optional argument.
    """
    print('{} {}'.format(req_arg, opt_arg))
$ python entry_point.py dev -h
usage: entry_point.py dev [-h] [--opt_arg opt_arg] req_arg

positional arguments:
  req_arg            required argument. (choices: bar, foo)

optional arguments:
  -h, --help         show this help message and exit
  --opt_arg opt_arg  optional argument.

Tip

For big list choices consider using a variable.

1
2
3
_choices = ['arg' ...]
def test_command(req_arg: _choices):
    pass

Override sub parser behavior for a command

To define a custom sub parser behavior you must use a classe and define a ‘setup_sub_parser’ function in it who take 3 arguments:

  • sub_pars: subparser object from argparser, result of add_parser method from add_subparsers.
  • signature: function signature, result of inspect.signature method.
  • docstring: docstring arguments as dict. key: arg name, value: arg description.

Create and customise your settings with yaml

WIP

Manipulating a database

WIP

Create a web app

WIP

Customise your logging

WIP