I\'m having a small issue with argparse
. I have an option xlim
which is the xrange
of a plot. I want to be able to pass numbers like <
Another workaround is to pass in the argument using '=
' symbol in addition to quoting the argument - i.e., --xlim="-2.3e14"
If you specify the value for your option with an equals sign, argparse
will not treat it as a separate option, even if it starts with -
:
./blaa.py --xlim='-0.002 1e4'
# As opposed to --xlim '-0.002 1e4'
And if the value does not have spaces in it, you can drop the quotes:
./blaa.py --xlim=-0.002
See: https://www.gnu.org/software/guile/manual/html_node/Command-Line-Format.html
With this, there is no need to write your own type=
parser or redefine the prefix character from -
to @
as the accepted answer suggests.
As already pointed out by the comments, the problem is that a -
prefix is parsed as an option instead of as an argument. One way to workaround this is change the prefix used for options with prefix_chars argument:
#!/usr/bin/python
import argparse
parser = argparse.ArgumentParser(prefix_chars='@')
parser.add_argument('@@xlim', nargs = 2,
help = 'X axis limits',
action = 'store', type = float,
default = [-1.e-3, 1.e-3])
print parser.parse_args()
Example output:
$ ./blaa.py @@xlim -2.e-3 1e4
Namespace(xlim=[-0.002, 10000.0])
Edit: Alternatively, you can keep using -
as separator, pass xlim
as a single value and use a function in type
to implement your own parsing:
#!/usr/bin/python
import argparse
def two_floats(value):
values = value.split()
if len(values) != 2:
raise argparse.ArgumentError
values = map(float, values)
return values
parser = argparse.ArgumentParser()
parser.add_argument('--xlim',
help = 'X axis limits',
action = 'store', type=two_floats,
default = [-1.e-3, 1.e-3])
print parser.parse_args()
Example output:
$ ./blaa.py --xlim "-2e-3 1e4"
Namespace(xlim=[-0.002, 10000.0])
One workaround I've found is to quote the value, but adding a space. That is,
./blaa.py --xlim " -2.e-3" 1e4
This way argparse won't think -2.e-3 is an option name because the first character is not a hyphen-dash, but it will still be converted properly to a float because float(string) ignores spaces on the left.
If you are up to modifying argparse.py
itself, you could change the negative number matcher to handle scientific notation:
In class _ActionsContainer.__init__()
self._negative_number_matcher = _re.compile(r'^-(\d+\.?|\d*\.\d+)([eE][+\-]?\d+)?$')
Or after creating the parser, you could set parser._negative_number_matcher
to this value. This approach might have problems if you are creating groups or subparsers, but should work with a simple parser.
Inspired by andrewfn's approach, I created a separate helper function to do the sys.argv
fiddling:
def _tweak_neg_scinot():
import re
import sys
p = re.compile('-\\d*\\.?\\d*e', re.I)
sys.argv = [' ' + a if p.match(a) else a for a in sys.argv]
The regex looks for:
-
: a negative sign\\d*
: zero or more digits (for oddly formatted values like -.5e-2
or -4354.5e-6
)\\.?
: an optional period (e.g., -2e-5
is reasonable)\\d*
: another set of zero or more digits (for things like -2e-5
and -7.e-3
)e
: to match the exponent markerre.I
makes it match both -2e-5
and -2E-5
. Using p.match
means that it only searches from the start of each string.