summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/argparse.py21
-rw-r--r--Lib/test/test_argparse.py48
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS6
4 files changed, 69 insertions, 7 deletions
diff --git a/Lib/argparse.py b/Lib/argparse.py
index 0ee8c08..f77c0c2 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -1714,10 +1714,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
if action.dest is not SUPPRESS:
if not hasattr(namespace, action.dest):
if action.default is not SUPPRESS:
- default = action.default
- if isinstance(action.default, str):
- default = self._get_value(action, default)
- setattr(namespace, action.dest, default)
+ setattr(namespace, action.dest, action.default)
# add any parser defaults that aren't present
for dest in self._defaults:
@@ -1945,12 +1942,22 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
if positionals:
self.error(_('too few arguments'))
- # make sure all required actions were present
+ # make sure all required actions were present, and convert defaults.
for action in self._actions:
- if action.required:
- if action not in seen_actions:
+ if action not in seen_actions:
+ if action.required:
name = _get_action_name(action)
self.error(_('argument %s is required') % name)
+ else:
+ # Convert action default now instead of doing it before
+ # parsing arguments to avoid calling convert functions
+ # twice (which may fail) if the argument was given, but
+ # only if it was defined already in the namespace
+ if (action.default is not None and
+ hasattr(namespace, action.dest) and
+ action.default is getattr(namespace, action.dest)):
+ setattr(namespace, action.dest,
+ self._get_value(action, action.default))
# make sure all required groups had one option present
for group in self._mutually_exclusive_groups:
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index 3a29761..cc05160 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -1462,6 +1462,22 @@ class TestFileTypeR(TempDirMixin, ParserTestCase):
('readonly', NS(x=None, spam=RFile('readonly'))),
]
+class TestFileTypeDefaults(TempDirMixin, ParserTestCase):
+ """Test that a file is not created unless the default is needed"""
+ def setUp(self):
+ super(TestFileTypeDefaults, self).setUp()
+ file = open(os.path.join(self.temp_dir, 'good'), 'w')
+ file.write('good')
+ file.close()
+
+ argument_signatures = [
+ Sig('-c', type=argparse.FileType('r'), default='no-file.txt'),
+ ]
+ # should provoke no such file error
+ failures = ['']
+ # should not provoke error because default file is created
+ successes = [('-c good', NS(c=RFile('good')))]
+
class TestFileTypeRB(TempDirMixin, ParserTestCase):
"""Test the FileType option/argument type for reading files"""
@@ -4468,6 +4484,38 @@ class TestArgumentTypeError(TestCase):
else:
self.fail()
+# ================================================
+# Check that the type function is called only once
+# ================================================
+
+class TestTypeFunctionCallOnlyOnce(TestCase):
+
+ def test_type_function_call_only_once(self):
+ def spam(string_to_convert):
+ self.assertEqual(string_to_convert, 'spam!')
+ return 'foo_converted'
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--foo', type=spam, default='bar')
+ args = parser.parse_args('--foo spam!'.split())
+ self.assertEqual(NS(foo='foo_converted'), args)
+
+# ================================================================
+# Check that the type function is called with a non-string default
+# ================================================================
+
+class TestTypeFunctionCallWithNonStringDefault(TestCase):
+
+ def test_type_function_call_with_non_string_default(self):
+ def spam(int_to_convert):
+ self.assertEqual(int_to_convert, 0)
+ return 'foo_converted'
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--foo', type=spam, default=0)
+ args = parser.parse_args([])
+ self.assertEqual(NS(foo='foo_converted'), args)
+
# ======================
# parse_known_args tests
# ======================
diff --git a/Misc/ACKS b/Misc/ACKS
index a46ee84..f534143 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -305,6 +305,7 @@ Nils Fischbeck
Frederik Fix
Matt Fleming
Hernán Martínez Foffani
+Arnaud Fontaine
Michael Foord
Amaury Forgeot d'Arc
Doug Fort
diff --git a/Misc/NEWS b/Misc/NEWS
index 8b0b145..c78dc96 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -112,6 +112,12 @@ Core and Builtins
Library
-------
+- Issue #12776,#11839: call argparse type function (specified by add_argument)
+ only once. Before, the type function was called twice in the case where the
+ default was specified and the argument was given as well. This was
+ especially problematic for the FileType type, as a default file would always
+ be opened, even if a file argument was specified on the command line.
+
- Issue #13370: Ensure that ctypes works on Mac OS X when Python is
compiled using the clang compiler