This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Add disable_interspersed_args() to argparse.ArgumentParser
Type: enhancement Stage: patch review
Components: Library (Lib) Versions: Python 3.10
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Laszlo.Attila.Toth, bethard, kalt, paul.j3, python-dev, rhettinger
Priority: normal Keywords: patch

Created on 2012-02-08 07:49 by Laszlo.Attila.Toth, last changed 2022-04-11 14:57 by admin.

Files
File name Uploaded Description Edit
argparse.patch Laszlo.Attila.Toth, 2012-02-08 07:49 Adding disable_interspersed_args()
argparse-disable_interspersed.patch Laszlo.Attila.Toth, 2012-02-17 15:46 Adding disable_interspersed_args() with unit tests
argparse.disable_interspersed_args.python35.diff Laszlo.Attila.Toth, 2015-02-28 13:35 Documented and tested version of disable_interspersed_args() review
Pull Requests
URL Status Linked Edit
PR 30071 open python-dev, 2021-12-12 10:36
Messages (11)
msg152839 - (view) Author: László Attila Tóth (Laszlo.Attila.Toth) * Date: 2012-02-08 07:49
If someone ports his code from optparse to argparse, there is a limit, that options and non-options can be mixed by default, and this behaviour cannot be disabled easily, an extra '--' argument is required in the command line.

In some cases it is much prettier to explicitly disable this, as was available in the deprecated optparse module.

I attach a patch that does this, adds disable_interspersed_args() to argparse.ArgumentParser.
msg153044 - (view) Author: Christophe Kalt (kalt) Date: 2012-02-10 13:50
nice, thank you!
msg153087 - (view) Author: Steven Bethard (bethard) * (Python committer) Date: 2012-02-11 03:54
The idea and patch seem okay to me. Needs tests though.
msg153552 - (view) Author: László Attila Tóth (Laszlo.Attila.Toth) * Date: 2012-02-17 15:46
I added unit test, which revealed some bugs. These are fixe now.
The attached file contains both the unit tests and the updated patch.
msg166079 - (view) Author: Steven Bethard (bethard) * (Python committer) Date: 2012-07-21 21:51
The argparse changes and tests look good. The new method needs to be documented. You can see some other things (e.g. Misc/NEWS) that also need to be updated by running "make patchcheck" as described here:

http://docs.python.org/devguide/patch.html
msg181164 - (view) Author: László Attila Tóth (Laszlo.Attila.Toth) * Date: 2013-02-02 11:54
Unfortunatelly the implementation bugous as of now. I wrote additional tests.

self.parser = ErrorRaisingArgumentParser()
self.parser.add_argument('-a', action='store_true')
self.parser.add_argument('-b')
self.parser.add_argument('rem', nargs=argparse.REMAINDER)
self.assertEquals(self.parser.parse_args('-b 4 -a  -b 5'.split()), NS(a=True, b='5', rem=[]))

This part is OK. But with the new option:
self.parser.disable_interspersed_args()
self.assertEquals(self.parser.parse_args('-b 4 -a -b 5'.split()), NS(a=False, b='4',  rem=['-a', '-b', '5']))

This assertation also passes because it contains the actual result, which is unexpected. This is because the code doesn't handle properly the arguments that are non-options, such as '-b' in this case.

I can't see a good solution for this.
msg185993 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2013-04-04 02:12
The optparse page gives a reason for disable_interspersed_args():

"Use this if you have a command processor which runs another command which has options of its own and you want to make sure these options don’t get confused. For example, each command might have a different set of options."

In argparse:
"argparse.REMAINDER. All the remaining command-line arguments are gathered into a list. This is commonly useful for command line utilities that dispatch to other command line utilities:"

If you have only one positional argument, and its nargs is REMAINDER, you have effectively disabled interspersed.

Argparse doesn't prohibit all interspersed positionals.  You could, for example, have one or more positionals with other nargs that could be interspersed.  But the REMAINDER one has to be last.

In the library, profile.py uses 'optparse.disable_interspersed'.  I just replaced optparse with argparse using the REMAINDER, and got the same behavior.  (Actually I used argparse.PARSER which effectively requires at least one argument.)
msg186000 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2013-04-04 03:26
Oops, I was wrong about this:
"Argparse doesn't prohibit all interspersed positionals.  You could, for example, have one or more positionals with other nargs that could be interspersed.  But the REMAINDER one has to be last."

    parser.add_argument('a')
    parser.add_argument('--foo')
    parser.add_argument('rest', nargs='...')
    parser.parse_args('a --foo b c'.split(' ')

produces:

    Namespace(a='a', foo=None, rest=['--foo', 'b', 'c'])

That is because, 'rest' matches an empty list of arguments.  With an nargs='*' or '?', the same thing happens, both 'a' and 'rest' are used up when processing the first positional argument string.

nargs=argparse.PARSER (= 'A...') gives the expected

    Namespace(a='a', foo='b', rest=['c'])

In this case, 'rest' has to wait till the second set of positionals.

Documentation warns "Note that it generally doesn’t make much sense to have more than one positional argument with nargs='*'".  Maybe it should warn against combining any of the 'zero or more' positionals with other positionals.
msg186046 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2013-04-04 17:39
Looking further at test_argparse.py, I should say that the behavior of multiple positionals when there is one cluster of positional argstrings is well illustrated in the tests.  It's the behavior when there are multiple clusters (interspersed positionals) that can go against some intuitions.
msg216882 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2014-04-19 21:48
http://bugs.python.org/issue14191
implements the other side of optparse behavior - allowing a complete intermixing of optionals and positionals. 

It does that with a new 'ArgumentParser.parse_intermixed_args()'  method.
msg236882 - (view) Author: László Attila Tóth (Laszlo.Attila.Toth) * Date: 2015-02-28 13:35
It seems I found the solution in the attached file argparse.disable_interspersed_args.python35.diff, and it's much-much easier than I thought. I assume that this patch can cleanly applied to earlier versions (python 3.2-3.4), but I didn't check it.
History
Date User Action Args
2022-04-11 14:57:26adminsetgithub: 58174
2021-12-12 10:36:45python-devsetnosy: + python-dev

pull_requests: + pull_request28291
stage: patch review
2020-12-05 04:30:19rhettingersetassignee: rhettinger ->
versions: + Python 3.10, - Python 3.2, Python 3.3, Python 3.4, Python 3.5
2019-08-30 03:32:06rhettingersetassignee: bethard -> rhettinger

nosy: + rhettinger
2015-02-28 13:35:25Laszlo.Attila.Tothsetfiles: + argparse.disable_interspersed_args.python35.diff

messages: + msg236882
versions: + Python 3.2, Python 3.4, Python 3.5
2014-04-19 21:48:30paul.j3setmessages: + msg216882
2013-04-04 17:39:01paul.j3setmessages: + msg186046
2013-04-04 03:26:25paul.j3setmessages: + msg186000
2013-04-04 02:12:42paul.j3setnosy: + paul.j3
messages: + msg185993
2013-02-02 11:54:26Laszlo.Attila.Tothsetmessages: + msg181164
2012-07-21 21:51:54bethardsetmessages: + msg166079
2012-02-17 15:46:53Laszlo.Attila.Tothsetfiles: + argparse-disable_interspersed.patch

messages: + msg153552
2012-02-11 03:54:08bethardsetmessages: + msg153087
2012-02-11 03:48:32eric.araujosetassignee: bethard

type: enhancement
nosy: + bethard
versions: + Python 3.3, - Python 2.7
2012-02-10 13:50:12kaltsetnosy: + kalt
messages: + msg153044
2012-02-08 07:49:27Laszlo.Attila.Tothcreate