diff -r 9ea84f006892 Lib/argparse.py
--- a/Lib/argparse.py Wed May 01 15:15:50 2013 +0200
+++ b/Lib/argparse.py Mon Sep 09 15:27:36 2013 -0700
@@ -1801,12 +1801,15 @@
def take_action(action, argument_strings, option_string=None):
seen_actions.add(action)
- argument_values = self._get_values(action, argument_strings)
+ argument_values, using_default = self._get_values(action, argument_strings)
# 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:
+ # refine test so that only values set by _get_values() to
+ # action.default count as not-really-present
+
+ if not using_default:
seen_non_default_actions.add(action)
for conflict_action in action_conflicts.get(action, []):
if conflict_action in seen_non_default_actions:
@@ -2212,6 +2215,7 @@
# ========================
def _get_values(self, action, arg_strings):
# for everything but PARSER, REMAINDER args, strip out first '--'
+ using_default = False
if action.nargs not in [PARSER, REMAINDER]:
try:
arg_strings.remove('--')
@@ -2224,6 +2228,7 @@
value = action.const
else:
value = action.default
+ using_default = True
if isinstance(value, str):
value = self._get_value(action, value)
self._check_value(action, value)
@@ -2234,6 +2239,7 @@
not action.option_strings):
if action.default is not None:
value = action.default
+ using_default = True
else:
value = arg_strings
self._check_value(action, value)
@@ -2260,7 +2266,7 @@
self._check_value(action, v)
# return the converted value
- return value
+ return value, using_default
def _get_value(self, action, arg_string):
type_func = self._registry_get('type', action.type, action.type)
diff -r 9ea84f006892 Lib/test/test_argparse.py
--- a/Lib/test/test_argparse.py Wed May 01 15:15:50 2013 +0200
+++ b/Lib/test/test_argparse.py Mon Sep 09 15:27:36 2013 -0700
@@ -2689,6 +2689,52 @@
-c c help
'''
+
+class TestMutuallyExclusiveDefaults(MEMixin, TestCase):
+ '''Narrow seen_non_default_actions criteria:
+ _get_values() sets argument_values = action.default only for positionals
+ with empty strings and '?*' nargs. Optionals with a value that equals
+ (or 'is') the default don't count
+ '''
+ def get_parser(self, required=None):
+ parser = ErrorRaisingArgumentParser(prog='PROG')
+ group = parser.add_mutually_exclusive_group(required=required)
+ group.add_argument('--foo', default='test')
+ group.add_argument('--bar', default='test')
+ group.add_argument('--small', type=int, default=42)
+ group.add_argument('--large', type=int, default=257)
+ return parser
+
+ failures = ['--foo X --bar Y',
+ '--small 0 --large 34',
+ '--foo test --bar Y',
+ '--large 257 --foo X',
+ '--small 42 --foo X',
+ ]
+ successes = [
+ ('--foo X', NS(bar='test', foo='X', large=257, small=42)),
+ ('--small 42', NS(bar='test', foo='test', large=257, small=42)),
+ ]
+ successes_when_not_required = [
+ ('', NS(foo='test', bar='test', small=42, large=257)),
+ ]
+ usage_when_required = '''\
+ usage: PROG [-h] (--foo FOO | --bar BAR | --small SMALL | --large LARGE)
+ '''
+ usage_when_not_required = '''\
+ usage: PROG [-h] [--foo FOO | --bar BAR | --small SMALL | --large LARGE]
+ '''
+ help = '''\
+
+ optional arguments:
+ -h, --help show this help message and exit
+ --foo FOO
+ --bar BAR
+ --small SMALL
+ --large LARGE
+ '''
+
+
# =================================================
# Mutually exclusive group in parent parser tests
# =================================================