summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlarryhastings <larry@hastings.org>2018-01-28 19:13:09 (GMT)
committerGitHub <noreply@github.com>2018-01-28 19:13:09 (GMT)
commitf36ba12809d5db1b76464d8f1f04dad8d685ec78 (patch)
tree62de617e1bd3fc4609e1f95338755887db22f4b5
parentbec2372b7e1da5dfdbadaf242aa8e994b164cace (diff)
downloadcpython-f36ba12809d5db1b76464d8f1f04dad8d685ec78.zip
cpython-f36ba12809d5db1b76464d8f1f04dad8d685ec78.tar.gz
cpython-f36ba12809d5db1b76464d8f1f04dad8d685ec78.tar.bz2
bpo-32697: Definition order of kwonly params is now guaranteed preserved. (#5391)
Definition order of kwonly params is now guaranteed preserved.
-rw-r--r--Doc/library/inspect.rst15
-rw-r--r--Lib/test/test_inspect.py47
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2018-01-28-09-52-12.bpo-32697.RHlu6k.rst3
3 files changed, 63 insertions, 2 deletions
diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst
index 147e802..bc4316f 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 cb51f8a..1a856f6 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 @@ class TestClassesAndFunctions(unittest.TestCase):
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 TestSignatureObject(unittest.TestCase):
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 0000000..97bc310
--- /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.