classification
Title: argparse.add_mutually_exclusive_group fails for optional positional arguments
Type: Stage:
Components: Library (Lib) Versions: Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: paul.j3, rrt
Priority: normal Keywords:

Created on 2020-09-24 20:23 by rrt, last changed 2020-10-17 07:41 by rrt.

Messages (3)
msg377460 - (view) Author: Reuben Thomas (rrt) Date: 2020-09-24 20:23
The following code:

group = parser.add_mutually_exclusive_group()
group.add_argument('--install-only', action='store_true',
                    help='just install the program, do not run it')
group.add_argument('args', metavar='ARGUMENT', nargs='*', default=None,
                    help='arguments to PROGRAM')

gives the following error:

    group.add_argument('args', metavar='ARGUMENT', nargs='*',
  File "/usr/lib/python3.8/argparse.py", line 1398, in add_argument
    return self._add_action(action)
  File "/usr/lib/python3.8/argparse.py", line 1621, in _add_action
    raise ValueError(msg)
ValueError: mutually exclusive arguments must be optional

But the 'args' argument *is* optional, as there can be 0 of them.
msg378795 - (view) Author: paul j3 (paul.j3) * (Python triager) Date: 2020-10-17 00:34
Give the positional a non-none default:

e.g.

    group.add_argument('args', metavar='ARGUMENT', nargs='*', default=[],
                     help='arguments to PROGRAM')

Since a '*' or '?' positional works with an empty list of arguments, it is "always seen".  It requires some special handling to allow it to work in the mutually exclusive context.  It's a tricky piece of code that might not be well documented (if at all).
msg378803 - (view) Author: Reuben Thomas (rrt) Date: 2020-10-17 07:41
Thanks for the hint; could this be documented, please?
History
Date User Action Args
2020-10-17 07:41:14rrtsetmessages: + msg378803
2020-10-17 00:34:43paul.j3setnosy: + paul.j3
messages: + msg378795
2020-09-24 20:23:50rrtcreate