Skip to main content

A low information-redundancy cli framework.

Project description



A low information-redundancy CLI framework for a quick and dirty way of converting python a script to a command line tool.

The idea behind this framework is that functions and classes have one-to-one correspondence to command line interfaces with functions as commands and arguments as flags. This framework allows users to define a function or a class in plain python and turn it into a CLI with one decorator.

This was inspired by fire and click.


pip install py-dispatch


import sys
from dispatch import command

def hello(name: str, verbose: bool, debug: bool, file: str = 'stdout'):
    '''Run the 'hello' command line interface.

    :v verbose: Run the command verbosly
    :name: Name of the person you are saying hello to.
    :file: Either stdout or stderr
    if debug:
        print(f'debugging with {name}', file=getattr(sys, file))
        print(f'hello, {name}', file=getattr(sys, file))

if __name__ == '__main__':
$ python --help
Run the 'hello' command line interface.

    hello [options]

        --name      Name of the person you are saying hello to.
    -v, --verbose   Run the command verbosly
        --file      Either stdout or stderr (default: 'stdout')
    -h, --help      Get help.


Arguments can be retrieved in two ways, either from Command.args or with positional only arguments. When a cli function is run, it is replaced with a Command object so the cli function can use the command in it's own body.

def cli(verbose: bool):

Running this cli with python hello --verbose these are some args will result in ['hello', 'these', 'are', 'some', 'args'].

The Other way to get arguments is to give the cli function a positional only argument at the beginning of the parameters list.

def cli(*args, verbose: bool):

Running this cli as before will have the same result. However, it only works when the args tuple is the first function parameter.

Properties of Flags

Because flags are specified by function arguments, the properties of flags are a little bit weird.

Boolean Flags

All boolean flags have a default of False.

A positional argument with no default and no type annotation is assumed to be a boolean flag and will default to a value of False.

def cli(verbose):
    if verbose:
        print('the verbose flag has been given')
        print('using default of False for verbose')

Flag Types

Dispatch uses type annotations to infer flag types and will use those annotations to convert the arguments given.

def cli(num: complex, decimal: float):

When the program is executed it will convert each argument to its type.

python --num=5+3j --decimal=5.9

For this command, the parser internals will eventually call complex('5+3j') and float('5.9') before giving the values as function arguments. What this means is that you can use any type as long it has an __init__ function that takes one argument. If a flag is given a default value and no type annotation, the flag will inherit whatever type is given as default.

Default Values

@dispatch.command(hidden_defaults={'one', 'two'})
def cli(one=1, two=2, other_stuff=None): pass

To specify a default value, simply set the function argument as you would with regular python code. The default values will be displayed in the help view of the command unless a set of type str is passed to the decorator as the 'hidden_defaults' argument. This will hide any default values from the help message. Falsy defaults that are non-boolean like an empty string will also be hidden.

Multiple Commands

For more complicated command line interfaces, you need more than just flags. To do this you simply use the same command decorator on a class instead of a function.

from dispatch import command

class multicommand:
    ''':v verbose: print stuff verbosly'''

    verbose: bool
    filename = ''

    def cat(self, file: str):
        '''Print a file

        :f file: print this file'''
        if self.verbose:
            print('doing the thing verbosly')
        print(open(file, 'r').read())

    def do(self, thing):
        '''Do a thing

        :thing: the thing you will be doing'''
        print('doing', thing)

    def _helper(self):
        '''functions that start with an underscore are not
        interpreted as commands (not even hidden commands).

if __name__ == "__main__":

This small program is used just like any other cli.

python --help
    multicommand [options] [command]

    cat   Print a file
    do    Do a thing

        --filename   default: ''
    -v, --verbose    print stuff verbosly
    -h, --help       Get help.

Group Flags

You can define flags that are used at a class level and can be accessed by all commands in the cli. To do this you can set a class variable or you can use a type annotation if you do not want the flag to have a default value. When retrieving the value of these flags you can simply use them like any class attribute with self.attr_name.

class cli:
    verbose: bool
    filename = 'notes.txt'

Command Aliases

Aliasing commands is really simple. All you need to do is assign the function you want to alias to another variable inside the class.

class cli:
    def command(self):
        '''This is a command.'''

    cmd = command
    cli [options] [command]

    -h, --help   Get help.

    command, cmd   This is a command.

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

py-dispatch-0.0.3.tar.gz (15.6 kB view hashes)

Uploaded source

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring Facebook / Instagram Facebook / Instagram PSF Sponsor Fastly Fastly CDN Google Google Object Storage and Download Analytics Huawei Huawei PSF Sponsor Microsoft Microsoft PSF Sponsor NVIDIA NVIDIA PSF Sponsor Pingdom Pingdom Monitoring Salesforce Salesforce PSF Sponsor Sentry Sentry Error logging StatusPage StatusPage Status page