Reputation: 4622
I'm trying to pass a parameter which is a list of values:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--cb_ticks', required=False, default='')
args = vars(parser.parse_args())
print(args['cb_ticks'])
For most cases, this code works as expected:
But when I'm trying to pass more than one value, where the first is negative:
I'm getting the following error: test.py:
error: argument --cb_ticks: expected one argument
Upvotes: 6
Views: 9856
Reputation: 1145
To accept the inputs as specified in the question, you must pre-process the arguments. I tried many things, from where the negative number issue appears in the documentation, from here and from Python Argparse: Issue with optional arguments which are negative numbers, but those methods didn't work in this specific kind of case (my case was https://github.com/poikilos/minetestmapper-python/blob/master/minetestmapper-numpy.py). I solved the issue as follows.
Step 1: Before using argparse, do the following:
cb_ticks_str = None
i = 0
while i < len(sys.argv):
if sys.argv[i] == "--cb_ticks":
del sys.argv[i]
cb_ticks_str = ''
elif cb_ticks_str == '':
cb_ticks_str = sys.argv[i]
del sys.argv[i]
break
else:
i += 1
i = None
Step 2: Use argpase as normal except don't use it for any non-numerical argument that starts with a hyphen:
parser = argparse.ArgumentParser()
# parser.add_argument('--cb_ticks', required=False, default='')
args = vars(parser.parse_args())
Step 3: Split your argument manually then add it to your args dict:
if cb_ticks_str is not None:
args['cb_ticks'] = [int(v) for v in cb_ticks_str.split(",")]
# ^ raises ValueError if a non-int is in the list
if len(args['cb_ticks']) != 2:
raise ValueError("cb_ticks must have 2 values separated by a comma.")
Alternatively:
If you were using the parser directly instead of using vars like in the question, (do #1 as I described) then in #2 change args = vars(parser.parse_args())
to args = parser.parse_args()
, then for #3 instead do:
Step 3: Split your argument manually then add it to an args object:
if cb_ticks_str is not None:
args.cb_ticks = [int(v) for v in cb_ticks_str.split(",")]
# ^ raises ValueError if a non-int is in the list
if len(args.cb_ticks) != 2:
raise ValueError("cb_ticks must have 2 values separated by a comma.")
Upvotes: 1
Reputation: 231395
-1,2
is allowed as a optionals flag:
In [39]: parser.add_argument('-1,2')
...
In [40]: parser.print_help()
usage: ipython3 [-h] [--cb_ticks CB_TICKS] [-1,2 1,2]
optional arguments:
-h, --help show this help message and exit
--cb_ticks CB_TICKS
-1,2 1,2
In [44]: args=parser.parse_args(['--cb_ticks','foo','-1,2','bar'])
In [45]: args
Out[45]: Namespace(cb_ticks='foo', **{'1,2': 'bar'}) # curious display
In [46]: vars(args)
Out[46]: {'1,2': 'bar', 'cb_ticks': 'foo'}
In [47]: getattr(args, '1,2')
Out[47]: 'bar'
This is an edge case, a consequence of code that tries not to constrain what flags (and/or dest
) the user can define.
Upvotes: 0
Reputation: 347
The add_argument
method allows you to tell the argument parser to expect multiple (or no) values:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--cb_ticks', nargs='*')
args = vars(parser.parse_args())
print(args['cb_ticks'])
but the values are expected to be space separated, so you'll have to execute your script as:
python test.py --cb_ticks -1 2
See reference.
Upvotes: 5