I am using docopt in my simple Python program:
#!/usr/bin/env python
"""
Farmers market
Usage:
farmersmarket.py buy -i <item> -q <quantity> [<quantity>] [-p <price>] [-dvh]
farmersmarket.py -d | --debug
farmersmarket.py -v | --version
farmersmarket.py -h | --help
Options:
-i --item Item.
-q --quantity Quantity.
-p --price Price.
-d --debug Show debug messages.
-h --help Show this screen.
-v --version Show version.
"""
from docopt import docopt
print docopt(__doc__)
If I run:
farmersmarket.py buy --item eggs --quantity 100 115 --price 0.25
The expected behaviour is to buy a random quantity of eggs between the values 100 and 115 at the price 0.25. This works without problems at least when it comes to interpreting the arguments. In other words docopt gets everything as intended:
{'--debug': False,
'--help': False,
'--item': True,
'--price': True,
'--quantity': True,
'--version': False,
'<item>': 'eggs',
'<price>': '0.25',
'<quantity>': ['100', '115'],
'buy': True}
However sometimes I do not want to buy a random amount of eggs but a specific amount. In this case the --quantity
option takes only one argument:
farmersmarket.py buy --item eggs --quantity 471 --price 0.25
But this fails as docopt interprets --price 0.25
as a repeating element of --quantity
and loses the value of <price>
:
{'--debug': False,
'--help': False,
'--item': True,
'--price': True,
'--quantity': True,
'--version': False,
'<item>': 'eggs',
'<price>': None,
'<quantity>': ['471', '0.25'],
'buy': True}
How can I get other options to work after repeating elements?
actually, you forgot to add the
<price>
argument to theOptions:
description part ; the following code:is working as you expect:
edit:
but actually, what you try to achieve is wrong. If you look at the parsed arguments you'll see:
which means that you defined a boolean
--quantity
argument, and a positionalquantity
argument. Both unrelated… Consequently the following:gives the result:
which is not what you want… So let's get back to what you want: you say you want an argument that takes two values to define a min and an optional max. But I'm sorry to tell you that this exact rule is no more possible in
geptopt
,argparse
than indocopt
.The solution will always involve a little logic once the parsing is done, or you need to change the way you're parsing your arguments. So I can see for you four options:
Two switches
Here, the simplest, yet I think best solution, is to use two different options for setting up the maximal and minimal boundaries. It's the only way that the parser can handle a
{1,2}
number of arguments and, afaict, the way it should be implemented.Use a single argument
The closest way to get you to actually have an argument with a list, is to actually "play" with the syntax:
Then you can use:
and get your min and max values through:
if len(docopt(__doc__)['--quantity'].split(',')) == 2: qmin, qmax = docopt(__doc__)['--quantity'].split(',')
.Use positional arguments only
Finally your last solution would be to use positional arguments only:
and then it works when you call:
List of options
But it looks like you want to get an argument list, and the only way to achieve that with command line options, is to repeat the option
-q 1 -q 2 -q 3…
. To tell docopt that's what you want, you need to add an ellipsis after the option's argument:Then you can call:
but then, you'll have to check that
len(docopt(__doc__)['--quantity']) < 2
(as the parser will enforce that you give at least one). But then you have to really state clearly in the description how you mean it to be used and give one or two examples.Finally, I'd advice you to use one of the three other options than the list of options, because they make it more obvious how you want your program to be called.