[Python-checkins] cpython: inspect.Signature: ensure that non-default params don't follow default ones

yury.selivanov python-checkins at python.org
Wed Jan 29 16:58:50 CET 2014


http://hg.python.org/cpython/rev/ca974997280d
changeset:   88811:ca974997280d
user:        Yury Selivanov <yselivanov at sprymix.com>
date:        Wed Jan 29 10:58:16 2014 -0500
summary:
  inspect.Signature: ensure that non-default params don't follow default ones #20427

files:
  Lib/inspect.py           |  21 ++++++++++++++++++++-
  Lib/test/test_inspect.py |  13 ++++++++++++-
  2 files changed, 32 insertions(+), 2 deletions(-)


diff --git a/Lib/inspect.py b/Lib/inspect.py
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -1924,6 +1924,7 @@
             if __validate_parameters__:
                 params = OrderedDict()
                 top_kind = _POSITIONAL_ONLY
+                kind_defaults = False
 
                 for idx, param in enumerate(parameters):
                     kind = param.kind
@@ -1933,9 +1934,27 @@
                         msg = 'wrong parameter order: {} before {}'
                         msg = msg.format(top_kind, kind)
                         raise ValueError(msg)
-                    else:
+                    elif kind > top_kind:
+                        kind_defaults = False
                         top_kind = kind
 
+                    if (kind in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD) and
+                                                     not param._partial_kwarg):
+                        # If we have a positional-only or positional-or-keyword
+                        # parameter, that does not have its default value set
+                        # by 'functools.partial' or other "partial" signature:
+                        if param.default is _empty:
+                            if kind_defaults:
+                                # No default for this parameter, but the
+                                # previous parameter of the same kind had
+                                # a default
+                                msg = 'non-default argument follows default ' \
+                                      'argument'
+                                raise ValueError(msg)
+                        else:
+                            # There is a default for this parameter.
+                            kind_defaults = True
+
                     if name in params:
                         msg = 'duplicate parameter name: {!r}'.format(name)
                         raise ValueError(msg)
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -1522,11 +1522,13 @@
 
         self.assertEqual(str(S()), '()')
 
-        def test(po, pk, *args, ko, **kwargs):
+        def test(po, pk, pod=42, pkd=100, *args, ko, **kwargs):
             pass
         sig = inspect.signature(test)
         po = sig.parameters['po'].replace(kind=P.POSITIONAL_ONLY)
+        pod = sig.parameters['pod'].replace(kind=P.POSITIONAL_ONLY)
         pk = sig.parameters['pk']
+        pkd = sig.parameters['pkd']
         args = sig.parameters['args']
         ko = sig.parameters['ko']
         kwargs = sig.parameters['kwargs']
@@ -1549,6 +1551,15 @@
         with self.assertRaisesRegex(ValueError, 'duplicate parameter name'):
             S((po, pk, args, kwargs2, ko))
 
+        with self.assertRaisesRegex(ValueError, 'follows default argument'):
+            S((pod, po))
+
+        with self.assertRaisesRegex(ValueError, 'follows default argument'):
+            S((po, pkd, pk))
+
+        with self.assertRaisesRegex(ValueError, 'follows default argument'):
+            S((pkd, pk))
+
     def test_signature_immutability(self):
         def test(a):
             pass

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list