classification
Title: argparse can't handle positional argument after list (help message is wrong)
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.6, Python 3.5, Python 2.7
process
Status: closed Resolution: duplicate
Dependencies: Superseder: document “--” as a way to distinguish option w/ narg='+' from positional argument in argparse
View: 9182
Assigned To: Nosy List: atpage, bethard, martin.panter, paul.j3
Priority: normal Keywords:

Created on 2016-01-22 16:35 by atpage, last changed 2016-01-28 00:19 by paul.j3. This issue is now closed.

Messages (3)
msg258823 - (view) Author: Alex (atpage) Date: 2016-01-22 16:35
This code is meant to take a filename and a list of integers as arguments.  The filename is required, the integers are optional:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('filename')
parser.add_argument('-L', metavar='integer', type=int, nargs='+')
args = parser.parse_args()
print(args)  # see what we got

It produces the following help message:
usage: demo.py [-h] [-L integer [integer ...]] filename

However, the filename argument does not work if it's given in that position (after the list of ints).  Instead, it tries to use filename as another list element:

$ python demo.py -L 1 2 3 test.txt
usage: demo.py [-h] [-L integer [integer ...]] filename
demo.py: error: argument -L: invalid int value: 'test.txt'

Changing the order of the arguments works as intended:

$ python demo.py test.txt -L 1 2 3 
Namespace(L=[1, 2, 3], filename='test.txt')

Probably the simplest fix would be to amend the help message to show the positional argument before the list:

usage: demo.py [-h] filename [-L integer [integer ...]]
msg258988 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2016-01-27 02:21
I think we should discuss this in the existing reports:

Issue 9182: Mention the “--” divider in the documentation and usage as a workaround. Perhaps you could mention your proposal to put positional arguments before the options there.

Issue 9338: Change the implementation to be smarter in this situation.
msg259074 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2016-01-28 00:19
There are 2 issues

parsing - how to reserve one or more arguments for use by following 'positionals'.  Fixes have been proposed in other bug/issues, but aren't trivial.

usage formatting - the stock formatter displays all optionals first, followed by all positionals.  In a multiline display positionals go on a new line.

Changes to the help formatter that would block this reordering have been discussed on Stackoverflow, but I don't recall such an issue here.  It can be done by changing one method in a subclassed formatter.

The immediate solution is to give your parser a custom usage line - one that puts the positional in the correct order.
History
Date User Action Args
2016-01-28 00:19:19paul.j3setnosy: + paul.j3
messages: + msg259074
2016-01-27 02:21:19martin.pantersetstatus: open -> closed

nosy: + martin.panter
messages: + msg258988

superseder: document “--” as a way to distinguish option w/ narg='+' from positional argument in argparse
resolution: duplicate
2016-01-23 11:28:20SilentGhostsetnosy: + bethard

versions: + Python 3.5, Python 3.6, - Python 3.4
2016-01-22 16:35:32atpagecreate