Reputation: 239820
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?
Upvotes: 6
Views: 3119
Reputation: 531205
If you want to specify multiple car park IDs, I would do one of two things instead of using nargs='+'
:
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)"
)
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"
)
Upvotes: 7
Reputation: 231395
Does this work?
$ mycommand ~/path-to-file --carpark 17
There is a Python bug/issue over +
Actions that consume too many arguments, leaving none for following Actions.
The argument allocation is based on argument counts, not on type
. The type
function is applied after allocation, and there's no provision for returning 'rejected' arguments.
In correct behavior it should take into account that infile
is expecting an argument - and there aren't any further flag strings - and thus reserve one string to that Action.
I could look that bug/issue up, but for now the fix is to supply the arguments in a different order. Or define a --infile
action (instead of the positional).
An earlier question, with the bug/issue link (my answer focuses more on getting the usage
right).
Argparse - do not catch positional arguments with `nargs`.
Upvotes: 4