9

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.

4

2 Answers 2

9

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.

Sign up to request clarification or add additional context in comments.

2 Comments

How to you inspect the arguments in the Python script? eg if args.start: start() elif args.stop: stop() ?
sys.argv is a list of the arguments. You can examine and parse that directly.
5

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}

1 Comment

The argparse solution does not produce unnecessary data fields, so I find it cleaner and more robust.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.