classification
Title: argparse mx_group is required, when action value equal default will be ignore
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.7
process
Status: closed Resolution: duplicate
Dependencies: Superseder: argparse: default args in mutually exclusive groups
View: 18943
Assigned To: Nosy List: louielu, paul.j3
Priority: normal Keywords:

Created on 2017-04-26 02:33 by louielu, last changed 2017-04-27 10:06 by berker.peksag. This issue is now closed.

Messages (6)
msg292293 - (view) Author: Louie Lu (louielu) * Date: 2017-04-26 02:33
When adding mutually exclusive group and required is True, and the group argument has default value. If we type its default value, argparse will ignore the input and return `argument is required`


------- PoC --------
import argparse

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-v', type=int, default=10)

print(parser.parse_args())

-----

$ python tests.py -v 10
usage: tests.py [-h] -v V
tests.py: error: one of the arguments -v is required
$ python tests.py -v 11
Namespace(v=11)
msg292295 - (view) Author: Louie Lu (louielu) * Date: 2017-04-26 03:22
Strange, this will only trigger when that argument type is int.
msg292298 - (view) Author: Louie Lu (louielu) * Date: 2017-04-26 04:06
Maybe documentation should note that:
"""
# error if this argument is not allowed with other previously
# seen arguments, assuming that actions that use the default
# value don't really count as "present"
"""
msg292302 - (view) Author: paul j3 (paul.j3) * Date: 2017-04-26 05:48
And only for integers smaller than 257!

The problem is with this test in `take_action` function

            # error if this argument is not allowed with other previously
            # seen arguments, assuming that actions that use the default
            # value don't really count as "present"
            if argument_values is not action.default:
                seen_non_default_actions.add(action)
                for conflict_action in action_conflicts.get(action, []):
                    if conflict_action in seen_non_default_actions:
                        msg = _('not allowed with argument %s')
                        action_name = _get_action_name(conflict_action)
                        raise ArgumentError(action, msg % action_name)

Specifically with the

    argument_values is not action.default

test.  In CPython integers below 257 are unique, so that

    In [33]: int('10') is 10
    Out[33]: True
    In [34]: int('257') is 257
    Out[34]: False

(and strings from 'sys.argv' do not match in the 'is' sense with strings set via 'default'.  So the problem is unique to small integers.)

The test is really meant to catch the default that is added in '_get_values()' for positionals with optional nargs ('?').

This issue was raised by some PyPy developers several years ago. 
 PyPy does not treat the small integers as unique.  I'll have to dig around to see what the resolution was, if any.

For now the solution is to use a string '10' as the default.
msg292304 - (view) Author: paul j3 (paul.j3) * Date: 2017-04-26 06:01
This issue was raised in 2013.  The proposed patch is still pending

http://bugs.python.org/issue18943

I'm going to close this new one, though it is a good reminder of a rare, but persistent bug.
msg292306 - (view) Author: Louie Lu (louielu) * Date: 2017-04-26 06:04
Thanks, paul. Your msg help a lot.

Will you work on #18943? I can help for this or review the pending patch.
History
Date User Action Args
2017-04-27 10:06:35berker.peksagsetsuperseder: argparse: default args in mutually exclusive groups
2017-04-26 06:04:53louielusetresolution: duplicate
messages: + msg292306
2017-04-26 06:01:41paul.j3setstatus: open -> closed
stage: resolved
2017-04-26 06:01:28paul.j3setmessages: + msg292304
2017-04-26 05:48:52paul.j3setnosy: + paul.j3
messages: + msg292302
2017-04-26 04:06:09louielusetmessages: + msg292298
2017-04-26 03:22:25louielusetmessages: + msg292295
2017-04-26 02:33:13louielusettype: behavior
2017-04-26 02:33:05louielucreate