Python Argparse: Issue with optional arguments which are negative numbers

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.


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])

Here is the code that I use. (It is similar to jeremiahbuddha's but it answers the question more directly since it deals with negative numbers.)

Put this before calling argparse.ArgumentParser()

for i, arg in enumerate(sys.argv):
  if (arg[0] == '-') and arg[1].isdigit(): sys.argv[i] = ' ' + arg

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 (or other special characters given your shell), 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.