diff -r a26df2d03989 Lib/argparse.py --- a/Lib/argparse.py Mon Apr 22 22:54:16 2013 +0300 +++ b/Lib/argparse.py Wed Apr 24 18:39:23 2013 -0700 @@ -582,6 +582,9 @@ elif action.nargs == PARSER: result = '%s ...' % get_metavar(1) else: + if not isinstance(action.nargs, int): + valid_nargs = [None,OPTIONAL,ZERO_OR_MORE,ONE_OR_MORE,REMAINDER,PARSER] + raise ValueError('nargs %r not integer or %s'%(action.nargs, valid_nargs)) formats = ['%s' for _ in range(action.nargs)] result = ' '.join(formats) % get_metavar(action.nargs) return result @@ -1325,6 +1328,9 @@ if not callable(type_func): raise ValueError('%r is not callable' % (type_func,)) + if hasattr(self, "_check_argument"): + self._check_argument(action) + # raise an error if the metavar does not match the type if hasattr(self, "_get_formatter"): try: @@ -1534,6 +1540,7 @@ self._has_negative_number_optionals = \ container._has_negative_number_optionals self._mutually_exclusive_groups = container._mutually_exclusive_groups + self._check_argument = container._check_argument def _add_action(self, action): action = super(_ArgumentGroup, self)._add_action(action) @@ -1707,6 +1714,18 @@ for action in self._actions if not action.option_strings] + def _check_argument(self, action): + # check action arguments + # focus on the arguments that the parent container does not know about + # check nargs and metavar tuple + try: + self._get_formatter()._format_args(action, None) + except ValueError as e: + raise ArgumentError(action, str(e)) + except TypeError: + #raise ValueError("length of metavar tuple does not match nargs") + raise ArgumentError(action, "length of metavar tuple does not match nargs") + # ===================================== # Command line argument parsing methods # ===================================== @@ -2197,6 +2216,8 @@ # all others should be integers else: + if not isinstance(action.nargs, int): + raise ValueError('nargs %r not integer or valid string'%(action.nargs)) nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs) # if this is an optional action, -- is not allowed diff -r a26df2d03989 Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py Mon Apr 22 22:54:16 2013 +0300 +++ b/Lib/test/test_argparse.py Wed Apr 24 18:39:23 2013 -0700 @@ -4251,6 +4251,40 @@ self.assertRaises(Success, parser.add_argument, 'spam', action=Action, default=Success, const=Success) + def test_nargs_value(self): + """test for invalid values of nargs, not integer or accepted string + tests parser and groups""" + error_msg = r"nargs (.*) not integer or" + error_msg = r"argument --foo: nargs (.*) not integer or \[(.*)\]" + error_type = argparse.ArgumentError + parser = ErrorRaisingArgumentParser() + group = parser.add_argument_group('g') + m = parser.add_mutually_exclusive_group() + + with self.assertRaisesRegexp(error_type, error_msg): + parser.add_argument('--foo', nargs='1') + with self.assertRaisesRegexp(error_type, error_msg): + group.add_argument('--foo', nargs='**') + with self.assertRaisesRegexp(error_type, error_msg): + m.add_argument('--foo', nargs='1') + + def test_nargs_metavar_tuple(self): + "test that metavar tuple matches with nargs; test parser and groups" + error_msg = r'length of metavar tuple does not match nargs' + error_type = ValueError + error_msg = r'argument (.*): length of metavar tuple does not match nargs' + error_type = argparse.ArgumentError + parser = ErrorRaisingArgumentParser() + group = parser.add_argument_group('g') + m = parser.add_mutually_exclusive_group() + + with self.assertRaisesRegexp(error_type, error_msg): + parser.add_argument('-w', help='w', nargs='+', metavar=('W1',)) + with self.assertRaisesRegexp(error_type, error_msg): + group.add_argument('-x', help='x', nargs='*', metavar=('X1', 'X2', 'x3')) + with self.assertRaisesRegexp(error_type, error_msg): + m.add_argument('-y', help='y', nargs=3, metavar=('Y1', 'Y2')) + # ================================ # Actions returned by add_argument # ================================ @@ -4720,19 +4754,23 @@ class TestAddArgumentMetavar(TestCase): - EXPECTED_MESSAGE = "length of metavar tuple does not match nargs" + EXPECTED_MESSAGE = "argument --foo: length of metavar tuple does not match nargs" + EXPECTED_ERROR = argparse.ArgumentError def do_test_no_exception(self, nargs, metavar): parser = argparse.ArgumentParser() parser.add_argument("--foo", nargs=nargs, metavar=metavar) + #def do_test_exception(self, nargs, metavar): + # parser = argparse.ArgumentParser() + # with self.assertRaises(ValueError) as cm: + # parser.add_argument("--foo", nargs=nargs, metavar=metavar) + # self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE) + def do_test_exception(self, nargs, metavar): parser = argparse.ArgumentParser() - with self.assertRaises(ValueError) as cm: + with self.assertRaisesRegex(self.EXPECTED_ERROR, self.EXPECTED_MESSAGE): parser.add_argument("--foo", nargs=nargs, metavar=metavar) - self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE) - - # Unit tests for different values of metavar when nargs=None def test_nargs_None_metavar_string(self): self.do_test_no_exception(nargs=None, metavar="1")