[Python-checkins] bpo-32697: Definition order of kwonly params is now guaranteed preserved. (#5391)

larryhastings webhook-mailer at python.org
Sun Jan 28 14:13:12 EST 2018


https://github.com/python/cpython/commit/f36ba12809d5db1b76464d8f1f04dad8d685ec78
commit: f36ba12809d5db1b76464d8f1f04dad8d685ec78
branch: master
author: larryhastings <larry at hastings.org>
committer: GitHub <noreply at github.com>
date: 2018-01-28T11:13:09-08:00
summary:

bpo-32697: Definition order of kwonly params is now guaranteed preserved. (#5391)

Definition order of kwonly params is now guaranteed preserved.

files:
A Misc/NEWS.d/next/Core and Builtins/2018-01-28-09-52-12.bpo-32697.RHlu6k.rst
M Doc/library/inspect.rst
M Lib/test/test_inspect.py

diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst
index 147e802cac4b..bc4316fabaee 100644
--- a/Doc/library/inspect.rst
+++ b/Doc/library/inspect.rst
@@ -602,7 +602,13 @@ function.
    .. attribute:: Signature.parameters
 
       An ordered mapping of parameters' names to the corresponding
-      :class:`Parameter` objects.
+      :class:`Parameter` objects.  Parameters appear in strict definition
+      order, including keyword-only parameters.
+
+      .. versionchanged:: 3.7
+         Python only explicitly guaranteed that it preserved the declaration
+         order of keyword-only parameters as of version 3.7, although in practice
+         this order had always been preserved in Python 3.
 
    .. attribute:: Signature.return_annotation
 
@@ -895,7 +901,7 @@ Classes and functions
    *defaults* is an *n*-tuple of default argument values corresponding to the
    last *n* positional parameters, or ``None`` if there are no such defaults
    defined.
-   *kwonlyargs* is a list of keyword-only parameter names.
+   *kwonlyargs* is a list of keyword-only parameter names in declaration order.
    *kwonlydefaults* is a dictionary mapping parameter names from *kwonlyargs*
    to the default values used if no argument is supplied.
    *annotations* is a dictionary mapping parameter names to annotations.
@@ -921,6 +927,11 @@ Classes and functions
       single-source Python 2/3 code migrating away from the legacy
       :func:`getargspec` API.
 
+   .. versionchanged:: 3.7
+      Python only explicitly guaranteed that it preserved the declaration
+      order of keyword-only parameters as of version 3.7, although in practice
+      this order had always been preserved in Python 3.
+
 
 .. function:: getargvalues(frame)
 
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index cb51f8aff290..1a856f6387e8 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -57,6 +57,31 @@ def revise(filename, *args):
 
 git = mod.StupidGit()
 
+
+def signatures_with_lexicographic_keyword_only_parameters():
+    """
+    Yields a whole bunch of functions with only keyword-only parameters,
+    where those parameters are always in lexicographically sorted order.
+    """
+    parameters = ['a', 'bar', 'c', 'delta', 'ephraim', 'magical', 'yoyo', 'z']
+    for i in range(1, 2**len(parameters)):
+        p = []
+        bit = 1
+        for j in range(len(parameters)):
+            if i & (bit << j):
+                p.append(parameters[j])
+        fn_text = "def foo(*, " + ", ".join(p) + "): pass"
+        symbols = {}
+        exec(fn_text, symbols, symbols)
+        yield symbols['foo']
+
+
+def unsorted_keyword_only_parameters_fn(*, throw, out, the, baby, with_,
+                                        the_, bathwater):
+    pass
+
+unsorted_keyword_only_parameters = 'throw out the baby with_ the_ bathwater'.split()
+
 class IsTestBase(unittest.TestCase):
     predicates = set([inspect.isbuiltin, inspect.isclass, inspect.iscode,
                       inspect.isframe, inspect.isfunction, inspect.ismethod,
@@ -829,6 +854,17 @@ def test_getfullagrspec_builtin_func_no_signature(self):
         with self.assertRaises(TypeError):
             inspect.getfullargspec(builtin)
 
+    def test_getfullargspec_definition_order_preserved_on_kwonly(self):
+        for fn in signatures_with_lexicographic_keyword_only_parameters():
+            signature = inspect.getfullargspec(fn)
+            l = list(signature.kwonlyargs)
+            sorted_l = sorted(l)
+            self.assertTrue(l)
+            self.assertEqual(l, sorted_l)
+        signature = inspect.getfullargspec(unsorted_keyword_only_parameters_fn)
+        l = list(signature.kwonlyargs)
+        self.assertEqual(l, unsorted_keyword_only_parameters)
+
     def test_getargspec_method(self):
         class A(object):
             def m(self):
@@ -2969,6 +3005,17 @@ class MySignature(inspect.Signature): pass
         sig = MySignature.from_callable(_pickle.Pickler)
         self.assertTrue(isinstance(sig, MySignature))
 
+    def test_signature_definition_order_preserved_on_kwonly(self):
+        for fn in signatures_with_lexicographic_keyword_only_parameters():
+            signature = inspect.signature(fn)
+            l = list(signature.parameters)
+            sorted_l = sorted(l)
+            self.assertTrue(l)
+            self.assertEqual(l, sorted_l)
+        signature = inspect.signature(unsorted_keyword_only_parameters_fn)
+        l = list(signature.parameters)
+        self.assertEqual(l, unsorted_keyword_only_parameters)
+
 
 class TestParameterObject(unittest.TestCase):
     def test_signature_parameter_kinds(self):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-01-28-09-52-12.bpo-32697.RHlu6k.rst b/Misc/NEWS.d/next/Core and Builtins/2018-01-28-09-52-12.bpo-32697.RHlu6k.rst
new file mode 100644
index 000000000000..97bc310683c3
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2018-01-28-09-52-12.bpo-32697.RHlu6k.rst	
@@ -0,0 +1,3 @@
+Python now explicitly preserves the definition order of keyword-only
+parameters.  It's always preserved their order, but this behavior was never
+guaranteed before; this behavior is now guaranteed and tested.



More information about the Python-checkins mailing list