Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

optional python arguments without dashes but with additional parameters?

what I'd like to do in Python is accept arguments of the following format:

script.py START | STOP | STATUS | MOVEABS <x> <y> | MOVEREL <x> <y>

So in other words,

  1. I don't want to deal with hyphens;
  2. I have multiple possibilities, ONE of which is required;
  3. Each is mutually exclusive;
  4. Some of the commands (E.G. moveabs and moverel) have additional required arguments, but these args and should not be present with any other argument.

Can this be done in python and would I use argparse or something else? Thanks.

like image 955
astronomerdave Avatar asked Apr 25 '14 23:04

astronomerdave


2 Answers

add_parser with subparsers would do the trick

import argparse
parser = argparse.ArgumentParser(prog='script.py')
sp = parser.add_subparsers(dest='cmd')
for cmd in ['START', 'STOP', 'STATUS']:
    sp.add_parser(cmd)
for cmd in ['MOVEABS', 'MOVEREL']:
    spp = sp.add_parser(cmd)
    spp.add_argument('x', type=float)
    spp.add_argument('y', type=float)
parser.print_help()
args = parser.parse_args()
print(args)

producing the likes of:

2137:~/mypy$ python2.7 stack23304740.py MOVEREL -h
usage: script.py [-h] {START,STOP,STATUS,MOVEABS,MOVEREL} ...

positional arguments:
  {START,STOP,STATUS,MOVEABS,MOVEREL}

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

usage: script.py MOVEREL [-h] x y

positional arguments:
  x
  y

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

and

2146:~/mypy$ python2.7 stack23304740.py MOVEREL 1.0 2.0
...
Namespace(cmd='MOVEREL', x=1.0, y=2.0)

and

2147:~/mypy$ python2.7 stack23304740.py START
...
Namespace(cmd='START')

The MOVEREL arguments could be named <x> and <y>, but then you'd have to access them via args['<y>'] instead of args.y. metavar='<x>' could be used to change the display but not the Namespace name.

You could also use spp.add_argument('point', nargs=2, type=float). Unfortunately there's a bug that keeps us from using a metavar in this nargs=2 case, http://bugs.python.org/issue14074.

like image 64
hpaulj Avatar answered Oct 30 '22 02:10

hpaulj


Using docopt you can do this quite easily.

Install docopt first:

$ pip install docopt

Write the script.py:

"""
Usage:
    script.py (start | stop | status | moveabs <x> <y> | moverel <x> <y>)
"""
from docopt import docopt

if __name__ == "__main__":
    args = docopt(__doc__)
    print args

and run it:

first showing basic help:

$ python script.py
Usage:
    script.py (start | stop | status | moveabs <x> <y> | moverel <x> <y>)

then try subcommands:

start

$ python script.py start
{'<x>': None,
 '<y>': None,
 'moveabs': False,
 'moverel': False,
 'start': True,
 'status': False,
 'stop': False}

stop

$ python script.py stop
{'<x>': None,
 '<y>': None,
 'moveabs': False,
 'moverel': False,
 'start': False,
 'status': False,
 'stop': True}

moveabs

$ python script.py moveabs 11 22
{'<x>': '11',
 '<y>': '22',
 'moveabs': True,
 'moverel': False,
 'start': False,
 'status': False,
 'stop': False}

moverel

$ python script.py moverel 11 22
{'<x>': '11',
 '<y>': '22',
 'moveabs': False,
 'moverel': True,
 'start': False,
 'status': False,
 'stop': False}
like image 44
Jan Vlcinsky Avatar answered Oct 30 '22 03:10

Jan Vlcinsky