mirror of https://github.com/python/cpython
bpo-32697: Definition order of kwonly params is now guaranteed preserved. (#5391)
Definition order of kwonly params is now guaranteed preserved.
This commit is contained in:
parent
bec2372b7e
commit
f36ba12809
|
@ -602,7 +602,13 @@ function.
|
||||||
.. attribute:: Signature.parameters
|
.. attribute:: Signature.parameters
|
||||||
|
|
||||||
An ordered mapping of parameters' names to the corresponding
|
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
|
.. attribute:: Signature.return_annotation
|
||||||
|
|
||||||
|
@ -895,7 +901,7 @@ Classes and functions
|
||||||
*defaults* is an *n*-tuple of default argument values corresponding to the
|
*defaults* is an *n*-tuple of default argument values corresponding to the
|
||||||
last *n* positional parameters, or ``None`` if there are no such defaults
|
last *n* positional parameters, or ``None`` if there are no such defaults
|
||||||
defined.
|
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*
|
*kwonlydefaults* is a dictionary mapping parameter names from *kwonlyargs*
|
||||||
to the default values used if no argument is supplied.
|
to the default values used if no argument is supplied.
|
||||||
*annotations* is a dictionary mapping parameter names to annotations.
|
*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
|
single-source Python 2/3 code migrating away from the legacy
|
||||||
:func:`getargspec` API.
|
: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)
|
.. function:: getargvalues(frame)
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,31 @@ def revise(filename, *args):
|
||||||
|
|
||||||
git = mod.StupidGit()
|
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):
|
class IsTestBase(unittest.TestCase):
|
||||||
predicates = set([inspect.isbuiltin, inspect.isclass, inspect.iscode,
|
predicates = set([inspect.isbuiltin, inspect.isclass, inspect.iscode,
|
||||||
inspect.isframe, inspect.isfunction, inspect.ismethod,
|
inspect.isframe, inspect.isfunction, inspect.ismethod,
|
||||||
|
@ -829,6 +854,17 @@ class TestClassesAndFunctions(unittest.TestCase):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
inspect.getfullargspec(builtin)
|
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):
|
def test_getargspec_method(self):
|
||||||
class A(object):
|
class A(object):
|
||||||
def m(self):
|
def m(self):
|
||||||
|
@ -2969,6 +3005,17 @@ class TestSignatureObject(unittest.TestCase):
|
||||||
sig = MySignature.from_callable(_pickle.Pickler)
|
sig = MySignature.from_callable(_pickle.Pickler)
|
||||||
self.assertTrue(isinstance(sig, MySignature))
|
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):
|
class TestParameterObject(unittest.TestCase):
|
||||||
def test_signature_parameter_kinds(self):
|
def test_signature_parameter_kinds(self):
|
||||||
|
|
|
@ -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.
|
Loading…
Reference in New Issue