Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Argparse nargs="+" is eating positional argument

Here's a subsection of my parser configuration

parser.add_argument(
    'infile', help="The file to be imported",
    type=argparse.FileType('r'), default=sys.stdin
)

parser.add_argument(
    '--carpark', nargs='+', dest='CarparkID', type=int, default=[],
    help="One or many carpark IDs"
)

However, the --carpark argument seems to be too greedy and eats anything that follows it:

$ mycommand --carpark 17 ~/path-to-file
mycommand: error: argument --carpark: invalid int value: '/home/oli/path-to-file'

What's a good way around something like this? I need to pass a list of integer IDs into the command but also have a positional file (which can also be stdin).

Is there —for example— a non-greedy nargs option that will only parse as much of this as makes sense?

like image 386
Oli Avatar asked Jan 06 '23 08:01

Oli


1 Answers

If you want to specify multiple car park IDs, I would do one of two things instead of using nargs='+':

  1. Use the option once per ID (mycommand --carpark 17 --carpark 18)

    parser.add_argument('--carpark',
                        dest='carpark_ids',
                        type=int,
                        action='append',
                        default=[],
                        help="One carpark ID (can be used multiple times)"
    )
    
  2. Take a single, comma-delimited argument instead (mycommand --carpark 17,18)

    def intlist(s):
        rv = []
        for x in s.split(','):
            try:
                x = int(x)
            except ValueError:
                raise ArgumentTypeError("Non-integer carpark id {x}" % (x,))
            rv.append(x)
        return rv
    
    parser.add_argument('--carpark',
                        type=intlist,
                        dest='carpark_ids',
                        default=[],
                        help="One or more carpark IDs"
    )
    

    With a little more work, you could modify this to allow multiple uses of --carpark to accumulate all its values into a single list.

A third alternative, one I'm not particularly fond of, is to abandon the positional argument, making it an optional argument instead. (mycommand --carpark 17 18 --infile ~/path-to-file).

parser.add_argument('--infile',
                    help="The file to be imported",
                    type=argparse.FileType('r'),
                    default=sys.stdin
)

parser.add_argument('--carpark',
                    nargs='+',
                    dest='CarparkID',
                    type=int,
                    default=[],
                    help="One or many carpark IDs"
)
like image 118
chepner Avatar answered Jan 17 '23 16:01

chepner