Command Line Parser ------ argparse vs docopt

Overall, argparse is easier to use, and can accommodate different argument data types. However, it is tricky when the number of positional arguments varies.

docopt can deal with flexible number and combinations of positional arguments. However, it cannot set data types directly.

An argparse module example in exampleArgparse.py

import argparse

import math

def squareopt(args):

print('The power of {} is {}'.format(args.inputNum,(args.inputNum)**2))

def squarerootopt(args):

print('The square root of {} is {}'.format(args.inputNum,math.sqrt(args.inputNum)))

commands = {

'squareopt': squareopt,

'squarerootopt': squarerootopt

}

parser = argparse.ArgumentParser(description='Test of argparse module')

# positional arguments

parser.add_argument("operation", help="The operation you want")

parser.add_argument("inputNum", help="The number to be operated",type=int)

# optional arguments

parser.add_argument('--echo', default='', help="The string to be printed")

parser.add_argument('--epochs', default=100, type=int, help="Number of epochs")

parser.add_argument('-r', '--routings', default=3, type=int, help="Number of iterations, should > 0")

parser.add_argument('-z', '--zebra', default=3, type=int, help="Number of zebras, should > 0")

parser.add_argument('--train', default=0, type=int, help="trainmode 0: train 1: test")

parser.add_argument('--save_dir', default='./result', help="Directory to save the results")

parser.add_argument('--lr', default=0.001, type=float, help="Initial learning rate")

if __name__ == '__main__':

args = parser.parse_args()

print(args)

print(args.echo)

print(args.epochs)

func = commands[args.operation]

func(args)

And from the terminal:

% python3 exampleArgparse.py --help

usage: exampleArgparse.py [-h] [--echo ECHO] [--epochs EPOCHS] [-r ROUTINGS]

[-z ZEBRA] [--train TRAIN] [--save_dir SAVE_DIR]

[--lr LR]

operation inputNum

Test of argparse module

positional arguments:

operation The operation you want

inputNum The number to be operated

optional arguments:

-h, --help show this help message and exit

--echo ECHO The string to be printed

--epochs EPOCHS Number of epochs

-r ROUTINGS, --routings ROUTINGS

Number of iterations, should > 0

-z ZEBRA, --zebra ZEBRA

Number of zebras, should > 0

--train TRAIN trainmode 0: train 1: test

--save_dir SAVE_DIR Directory to save the results

--lr LR Initial learning rate

% python3 exampleArgparse.py squareopt 4 --echo="long long long time ago" --epochs=500

Namespace(echo='long long long time ago', epochs=500, inputNum=4, lr=0.001, operation='squareopt', routings=3, save_dir='./result', train=0, zebra=3)

long long long time ago

500

The power of 4 is 16


A docopt module example in exampleDocopt.py

"""

Usage:

exampleDocopt.py [options] (-h | --help)

exampleDocopt.py singleNum [options] <operation> <inputNum>

exampleDocopt.py doubleNum [options] <operation2> <inputNum1> <inputNum2>

exampleDocopt.py [options] <operation2> <inputNum1> <inputNum2>

Options:

-h --help show this help message and exit

-v,--verbose show debugging messages

--echo ECHO The string to be printed [default: The string to be printed]

--epochs EPOCHS Number of epochs [default: 100]

-r ROUTINGS, --routings ROUTINGS

Number of iterations, should > 0 [default: 3]

-z=ZEBRA --zebra=ZEBRA

Number of zebras, should > 0 [default: 3]

--train TRAIN [default: 0] trainmode 0: train 1: test

--save_dir SAVE_DIR Directory to save the results [default: ./result]

--lr LR Initial learning rate [default: 0.001]

"""

from docopt import docopt

import math

def squareopt(args):

print('The power of {} is {}'.format(args['<inputNum>'],(float(args['<inputNum>']))**2))

def squarerootopt(args):

print('The square root of {} is {}'.format(args['<inputNum>'],math.sqrt(float(args['<inputNum>']))))

commands = {

'squareopt': squareopt,

'squarerootopt': squarerootopt

}

def plus(args):

print('The sum of {} and {} is {}'.format(args['<inputNum1>'],args['<inputNum2>'], float(args['<inputNum1>'])+float(args['<inputNum2>']) ))

def minus(args):

print('The differnce between {} and {} is {}'.format(args['<inputNum1>'],args['<inputNum2>'], float(args['<inputNum1>'])-float(args['<inputNum2>']) ))

commands2 = {

'plus': plus,

'minus': minus

}

if __name__ == '__main__':

arguments = docopt(__doc__)

print(arguments)

print(arguments['--echo'])

print(arguments['--epochs'])

if arguments['<operation>'] is not None:

func = commands[arguments['<operation>']]

func(arguments)

if arguments['<operation2>'] is not None:

func = commands2[arguments['<operation2>']]

func(arguments)

And from the terminal:

% python3 exampleDocopt.py --help

Usage:

exampleDocopt.py [options] (-h | --help)

exampleDocopt.py singleNum [options] <operation> <inputNum>

exampleDocopt.py doubleNum [options] <operation2> <inputNum1> <inputNum2>

exampleDocopt.py [options] <operation2> <inputNum1> <inputNum2>

Options:

-h --help show this help message and exit

-v,--verbose show debugging messages

--echo ECHO The string to be printed [default: The string to be printed]

--epochs EPOCHS Number of epochs [default: 100]

-r ROUTINGS, --routings ROUTINGS

Number of iterations, should > 0 [default: 3]

-z=ZEBRA --zebra=ZEBRA

Number of zebras, should > 0 [default: 3]

--train TRAIN [default: 0] trainmode 0: train 1: test

--save_dir SAVE_DIR Directory to save the results [default: ./result]

--lr LR Initial learning rate [default: 0.001]

% python3 exampleDocopt.py singleNum --echo="long long long time ago" --epochs=500 squareopt 4

{'--echo': 'long long long time ago',

'--epochs': '500',

'--help': False,

'--lr': '0.001',

'--routings': '3',

'--save_dir': './result',

'--train': '0',

'--verbose': False,

'--zebra': '3',

'<inputNum1>': None,

'<inputNum2>': None,

'<inputNum>': '4',

'<operation2>': None,

'<operation>': 'squareopt',

'doubleNum': False,

'singleNum': True}

long long long time ago

500

The power of 4 is 16.0

% python3 exampleDocopt.py --echo="long long long time ago" --epochs=500 plus 3 4

{'--echo': 'long long long time ago',

'--epochs': '500',

'--help': False,

'--lr': '0.001',

'--routings': '3',

'--save_dir': './result',

'--train': '0',

'--verbose': False,

'--zebra': '3',

'<inputNum1>': '3',

'<inputNum2>': '4',

'<inputNum>': None,

'<operation2>': 'plus',

'<operation>': None,

'doubleNum': False,

'singleNum': False}

long long long time ago

500

The sum of 3 and 4 is 7.0