How to parse positional arguments with leading minus sign (negative numbers) using argparse

12,685

Solution 1

You need to insert a -- into your command-line arguments:

$ python example.py --test -- -1,2,3,4
Namespace(positional='-1,2,3,4', test=True)

The double-dash stops argparse looking for any more optional switches; it's the defacto standard way of handling exactly this use case for command-line tools.

Solution 2

From the documentation:

The parse_args() method attempts to give errors whenever the user has clearly made a mistake, but some situations are inherently ambiguous. For example, the command-line argument -1 could either be an attempt to specify an option or an attempt to provide a positional argument. The parse_args() method is cautious here: positional arguments may only begin with - if they look like negative numbers and there are no options in the parser that look like negative numbers:

Since -1,2,3,4 does not look like a negative number you must "escape" it with the -- as in most *nix systems.

An other solution would be to use nargs for the positional and pass the numbers as space separated:

#test.py
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('positional', nargs='*') #'+' for one or more numbers

print parser.parse_args()

Output:

$ python test.py -1 2 3 -4 5 6
Namespace(positional=['-1', '2', '3', '-4', '5', '6'])

A third way to obtain what you want is to use parse_known_args instead of parse_args. You do not add the positional argument to the parser and parse it manually instead:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--test', action='store_true')

parsed, args = parser.parse_known_args()
print parsed
print args

Result:

$ python test.py  --test -1,2,3,4                                            
Namespace(test=True)
['-1,2,3,4']    

This has the disadvantage that the help text will be less informative.

Share:
12,685
Inactivist
Author by

Inactivist

Eclectic programmer. (Re)Discovering Python. Loving it. Some things I'm working on: WhatEvah: Discover Twitter Influencers for your choice of search terms. Twitter-Streamer: Python-based utility using Twitter's Streaming API. Capture Twitter streams with minimal fuss. What you do with it is up to you. Sylvestr Eats Tweets: Realtime stats for various things mentioned on Twitter. Uses a variant of Twitter-Streamer to capture Twitter's Streaming API data. WhoPlussed: Google+ app to view top commenters on a Google+ post.

Updated on June 04, 2022

Comments

  • Inactivist
    Inactivist about 2 years

    I would like to parse a required, positional argument containing a comma-separated list of integers. If the first integer contains a leading minus ('-') sign, argparse complains:

    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('positional')
    parser.add_argument('-t', '--test', action='store_true')
    opts = parser.parse_args()
    print opts
    
    $ python example.py --test 1,2,3,4
    Namespace(positional='1,2,3,4', test=True)
    
    $ python example.py --test -1,2,3,4
    usage: example.py [-h] [-t] positional
    example.py: error: too few arguments
    
    $ python example.py --test "-1,2,3,4"
    usage: example.py [-h] [-t] positional
    example.py: error: too few arguments
    

    I've seen people suggest using some other character besides - as the flag character, but I'd rather not do that. Is there another way to configure argparse to allow both --test and -1,2,3,4 as valid arguments?

  • Inactivist
    Inactivist over 11 years
    I saw the documentation, but was wondering if there were any tricks to alter the standard behavior. At this point, I think it would be better to require four separate positional arguments or use space delimiters than to use the -- escape mechanism. Thanks for the help.
  • Inactivist
    Inactivist over 11 years
    Ah, I was unaware of the 'standard' of having to use double-dash (still a *nix newbie of sorts, still learning...) Thanks for the info!
  • Bakuriu
    Bakuriu over 11 years
    @Inactivist I updated my answer with a third method to allow -1,2,3,4 style positional.
  • panzi
    panzi over 10 years
    That just gives me error: unrecognized arguments: -- (argparse under Python 2.7.3)
  • Martijn Pieters
    Martijn Pieters over 10 years
    @panzi: No such problems under Python 2.7.5.