From a9cab433bbf02f3a1de59d14dc8f583181ffe2d5 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Wed, 30 May 2018 00:04:08 +0900 Subject: [PATCH] bpo-33197: Update a error message of invalid inspect.Parameters. (GH-6636) --- Lib/inspect.py | 47 ++++++++++++------- Lib/test/test_inspect.py | 25 ++++++++-- .../2018-04-29-23-56-20.bpo-33197.dgRLqr.rst | 2 + 3 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-04-29-23-56-20.bpo-33197.dgRLqr.rst diff --git a/Lib/inspect.py b/Lib/inspect.py index e5d312eb302..409c05880de 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2402,6 +2402,16 @@ _VAR_POSITIONAL = _ParameterKind.VAR_POSITIONAL _KEYWORD_ONLY = _ParameterKind.KEYWORD_ONLY _VAR_KEYWORD = _ParameterKind.VAR_KEYWORD +_PARAM_NAME_MAPPING = { + _POSITIONAL_ONLY: 'positional-only', + _POSITIONAL_OR_KEYWORD: 'positional or keyword', + _VAR_POSITIONAL: 'variadic positional', + _KEYWORD_ONLY: 'keyword-only', + _VAR_KEYWORD: 'variadic keyword' +} + +_get_paramkind_descr = _PARAM_NAME_MAPPING.__getitem__ + class Parameter: """Represents a parameter in a function signature. @@ -2436,15 +2446,14 @@ class Parameter: empty = _empty def __init__(self, name, kind, *, default=_empty, annotation=_empty): - - if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD, - _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD): - raise ValueError("invalid value for 'Parameter.kind' attribute") - self._kind = kind - + try: + self._kind = _ParameterKind(kind) + except ValueError: + raise ValueError(f'value {kind!r} is not a valid Parameter.kind') if default is not _empty: - if kind in (_VAR_POSITIONAL, _VAR_KEYWORD): - msg = '{} parameters cannot have default values'.format(kind) + if self._kind in (_VAR_POSITIONAL, _VAR_KEYWORD): + msg = '{} parameters cannot have default values' + msg = msg.format(_get_paramkind_descr(self._kind)) raise ValueError(msg) self._default = default self._annotation = annotation @@ -2453,19 +2462,21 @@ class Parameter: raise ValueError('name is a required attribute for Parameter') if not isinstance(name, str): - raise TypeError("name must be a str, not a {!r}".format(name)) + msg = 'name must be a str, not a {}'.format(type(name).__name__) + raise TypeError(msg) if name[0] == '.' and name[1:].isdigit(): # These are implicit arguments generated by comprehensions. In # order to provide a friendlier interface to users, we recast # their name as "implicitN" and treat them as positional-only. # See issue 19611. - if kind != _POSITIONAL_OR_KEYWORD: - raise ValueError( - 'implicit arguments must be passed in as {}'.format( - _POSITIONAL_OR_KEYWORD - ) + if self._kind != _POSITIONAL_OR_KEYWORD: + msg = ( + 'implicit arguments must be passed as ' + 'positional or keyword arguments, not {}' ) + msg = msg.format(_get_paramkind_descr(self._kind)) + raise ValueError(msg) self._kind = _POSITIONAL_ONLY name = 'implicit{}'.format(name[1:]) @@ -2736,8 +2747,12 @@ class Signature: name = param.name if kind < top_kind: - msg = 'wrong parameter order: {!r} before {!r}' - msg = msg.format(top_kind, kind) + msg = ( + 'wrong parameter order: {} parameter before {} ' + 'parameter' + ) + msg = msg.format(_get_paramkind_descr(top_kind), + _get_paramkind_descr(kind)) raise ValueError(msg) elif kind > top_kind: kind_defaults = False diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index ee227a66b17..35e86b5748e 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1499,6 +1499,20 @@ class TestGetcallargsFunctions(unittest.TestCase): with self.assertRaisesRegex(TypeError, "'a', 'b' and 'c'"): inspect.getcallargs(f6) + # bpo-33197 + with self.assertRaisesRegex(ValueError, + 'variadic keyword parameters cannot' + ' have default values'): + inspect.Parameter("foo", kind=inspect.Parameter.VAR_KEYWORD, + default=42) + with self.assertRaisesRegex(ValueError, + "value 5 is not a valid Parameter.kind"): + inspect.Parameter("bar", kind=5, default=42) + + with self.assertRaisesRegex(TypeError, + 'name must be a str, not a int'): + inspect.Parameter(123, kind=4) + class TestGetcallargsMethods(TestGetcallargsFunctions): def setUp(self): @@ -3099,7 +3113,8 @@ class TestParameterObject(unittest.TestCase): self.assertIs(p.annotation, p.empty) self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) - with self.assertRaisesRegex(ValueError, 'invalid value'): + with self.assertRaisesRegex(ValueError, "value '123' is " + "not a valid Parameter.kind"): inspect.Parameter('foo', default=10, kind='123') with self.assertRaisesRegex(ValueError, 'not a valid parameter name'): @@ -3189,7 +3204,9 @@ class TestParameterObject(unittest.TestCase): self.assertEqual(p2.kind, p2.POSITIONAL_OR_KEYWORD) self.assertNotEqual(p2, p) - with self.assertRaisesRegex(ValueError, 'invalid value for'): + with self.assertRaisesRegex(ValueError, + "value " + "is not a valid Parameter.kind"): p2 = p2.replace(kind=p2.empty) p2 = p2.replace(kind=p2.KEYWORD_ONLY) @@ -3202,7 +3219,9 @@ class TestParameterObject(unittest.TestCase): @cpython_only def test_signature_parameter_implicit(self): with self.assertRaisesRegex(ValueError, - 'implicit arguments must be passed in as'): + 'implicit arguments must be passed as ' + 'positional or keyword arguments, ' + 'not positional-only'): inspect.Parameter('.0', kind=inspect.Parameter.POSITIONAL_ONLY) param = inspect.Parameter( diff --git a/Misc/NEWS.d/next/Library/2018-04-29-23-56-20.bpo-33197.dgRLqr.rst b/Misc/NEWS.d/next/Library/2018-04-29-23-56-20.bpo-33197.dgRLqr.rst new file mode 100644 index 00000000000..1bbb44b2fc3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-29-23-56-20.bpo-33197.dgRLqr.rst @@ -0,0 +1,2 @@ +Update error message when constructing invalid inspect.Parameters +Patch by Dong-hee Na.