Skip to content

Commit 6e4101a

Browse files
bpo-45235: Fix argparse overrides namespace with subparser defaults (GH-28420) (GH-28442)
1 parent 5683902 commit 6e4101a

File tree

3 files changed

+15
-6
lines changed

3 files changed

+15
-6
lines changed

Lib/argparse.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,8 @@ def __call__(self, parser, namespace, values, option_string=None):
12081208
# namespace for the relevant parts.
12091209
subnamespace, arg_strings = parser.parse_known_args(arg_strings, None)
12101210
for key, value in vars(subnamespace).items():
1211-
setattr(namespace, key, value)
1211+
if not hasattr(namespace, key):
1212+
setattr(namespace, key, value)
12121213

12131214
if arg_strings:
12141215
vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, [])
@@ -1842,11 +1843,6 @@ def parse_known_args(self, args=None, namespace=None):
18421843
if action.default is not SUPPRESS:
18431844
setattr(namespace, action.dest, action.default)
18441845

1845-
# add any parser defaults that aren't present
1846-
for dest in self._defaults:
1847-
if not hasattr(namespace, dest):
1848-
setattr(namespace, dest, self._defaults[dest])
1849-
18501846
# parse the arguments and exit if there are any errors
18511847
if self.exit_on_error:
18521848
try:
@@ -1857,6 +1853,11 @@ def parse_known_args(self, args=None, namespace=None):
18571853
else:
18581854
namespace, args = self._parse_known_args(args, namespace)
18591855

1856+
# add any parser defaults that aren't present
1857+
for dest in self._defaults:
1858+
if not hasattr(namespace, dest):
1859+
setattr(namespace, dest, self._defaults[dest])
1860+
18601861
if hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR):
18611862
args.extend(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR))
18621863
delattr(namespace, _UNRECOGNIZED_ARGS_ATTR)

Lib/test/test_argparse.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3060,6 +3060,12 @@ def test_set_defaults_on_parent_and_subparser(self):
30603060
xparser.set_defaults(foo=2)
30613061
self.assertEqual(NS(foo=2), parser.parse_args(['X']))
30623062

3063+
def test_set_defaults_on_subparser_with_namespace(self):
3064+
parser = argparse.ArgumentParser()
3065+
xparser = parser.add_subparsers().add_parser('X')
3066+
xparser.set_defaults(foo=1)
3067+
self.assertEqual(NS(foo=2), parser.parse_args(['X'], NS(foo=2)))
3068+
30633069
def test_set_defaults_same_as_add_argument(self):
30643070
parser = ErrorRaisingArgumentParser()
30653071
parser.set_defaults(w='W', x='X', y='Y', z='Z')
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix an issue where argparse would not preserve values in a provided namespace
2+
when using a subparser with defaults.

0 commit comments

Comments
 (0)