Alternatives to Clize

Many argument parsers exist in Python. This document shortly presents the major argument parsers in the Python ecosystem and relates them to Clize. It also lists other parsers including some similar to Clize.

Note

The code examples below are excerpts from the other parsers’ respective documentation. Please see the respective links for the relevant copyright information.

argparse

argparse is Python’s standard library module for building argument parsers. It was built to replace getopt and optparse, offering more flexibility and handling of positional arguments.

Here’s an example from the standard library:

import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
                    help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
                    const=sum, default=max,
                    help='sum the integers (default: find the max)')

args = parser.parse_args()
print(args.accumulate(args.integers))

It demonstrates the use of accumulator arguments (building a list), supplying values using flags.

A developer wishing to use argparse for their argument parsing would:

  1. Instantiate a parser as above
  2. Tell it what to expect using the add_argument method
  3. Tell it to parse the arguments
  4. Execute your program logic

The above example can be performed using Clize as follows:

import clize

def accumulator(*integers, sum_=False):
    """Process some integers.

    :param integers: integers for the accumulator
    :param sum_: sum the integers (default: find the max)
    """
    f = sum if sum_ else max
    return f(integers)

clize.run(main)

argparse idioms and their Clize counterpart:

argparse Clize
API user creates a parser object and configures parameters. API user creates a function. Clize creates a CLI from it.
Document the CLI using the description and help arguments of the parser object. Document the CLI by writing a docstring for your function(s).
argparse reads arguments and produces an object with the state these arguments represent. Clize reads arguments and calls the associated function with the arguments translated into Python equivalents.
Use subparsers to create subcommands and share parameters across functionalities. Pass multiple functions to run in order to create subcommands.
Use decorators to share parameters between functions.
Extend the parser using Action. Extend the parser using custom parameter classes and converters.
Specify converter functions for arguments using the type argument of add_argument. Specify a value converter.
Specify the value label in documentation using the metavar argument.
Ask the parser to only parse known arguments using parse_known_args. Forward extra arguments to another function using *args, **kwargs.
Specify a parameter as LAST_OPTION and collect the rest in *args.
Specify allowed values with the choices argument. Use one_of.
Specify quantifiers using nargs. Use default arguments and/or use clize.parameters.multi.

Click

click is a third-party command-line argument parsing library based on optparse. It aims to cater to large scale projects and was created to support Flask and its ecosystem. It also contains various utilities for working with terminal environments.

import click

@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
              help='The person to greet.')
def hello(count, name):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello %s!' % name)

if __name__ == '__main__':
    hello()

A click user writes a function containing some behavior. Each parameter is matched with an option or argument decorator, and this is decorated with command. This function becomes a callable that will parse the arguments given to the program.

It also supports nestable subcommands:

@click.group()
@click.option('--debug/--no-debug', default=False)
def cli(debug):
    click.echo('Debug mode is %s' % ('on' if debug else 'off'))

@cli.command()
def sync():
    click.echo('Synching')

click idioms and their Clize counterpart:

click Clize
API user creates a function and configures parameters using decorators. API user creates a function. Clize creates a CLI from it. API user can specify options using parameter annotations.
Subcommands are created by using the group decorator then the command method. Subcommands are created by passing a dict or iterable to clize.run. It is possible to extend Clize to do it like click.
Command group functions can parse arguments. Decorators can be used to share parameters between functions.
Use pass_context to share global state between functions. Use value_inserter and the meta dict to share global state between functions without using parameters.
Add conversion types by extending ParamType. Add conversion types with the value_converter decorator.

Docopt

docopt is a command-line interface description language with parsers implemented in several languages.

"""Naval Fate.

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

"""
from docopt import docopt


if __name__ == '__main__':
    arguments = docopt(__doc__, version='Naval Fate 2.0')
    print(arguments)

A docopt user will write a string containing the help page for the command (as would be displayed when using --help) and hand it to docopt. It will parse arguments from the command-line and produce a dict-like object with the values provided. The user then has to dispatch to the relevant code depending on this object.

docopt Clize
API user writes a formatted help string which docopt parses and draws a CLI from. API user writes Python functions and Clize draws a CLI from them.
docopt parses arguments and returns a dict-like object mapping parameters to strings. Clize parses arguments and calls your function, with the arguments converted to Python types.
The string passed to docopt is used for help output directly. This help output does not reflow depending on terminal size. Clize creates the help output from the function signature and fetches parameter descriptions from the docstring. The user can reorder option descriptions, label them and add paragraphs. The output is adapted to the output terminal width.
The usage line is printed on parsing errors. A relevant message and/or suggestion is displayed on error.
Specify exclusivity constraints in the usage signature. Use Python code inside your function (or decorator) or custom parameters to specify exclusivity constraints.
The entire CLI must be defined in one string. You can compose your CLI using subcommands, function decorators, function composition, parameter decorators, ...

Other parsers similar to Clize

Parsers based on argparse

defopt is similar to Clize: it uses annotations to supplement the default configurations for parameters. A notable difference is that it supports Sphinx-compatible docstrings, but does not support composition.

With argh you can amend these parameter definitions (or add new parameters) using a decorator that takes the same arguments as argparse.ArgumentParser.add_argument.

fire also converts callables to CLIs. It observes slightly different conventions than common CLIs and doesn’t support keyword-only parameters. Instead, all parameters can be passed by position or by name. It does not help you generate help, though ./program -- --help will print the docstring, usage information, and other technical information. It allows chaining commands with each taking the output of the previoous command.

And then some more:

Other similar parsers

Other parsers

  • Clint – Multiple CLI tools, including a schemaless argument parser
  • twisted.usage – subclass-based approach