Skip to content

Commit 4cb15a2

Browse files
serhiy-storchakamiss-islington
authored andcommitted
gh-78526: Add tests for PEP 468 and PEP 520 (GH-155387)
Test that the order of keyword arguments and the order of class attribute definitions are preserved. (cherry picked from commit 116caab) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent 160a9e2 commit 4cb15a2

2 files changed

Lines changed: 108 additions & 0 deletions

File tree

Lib/test/test_call.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,54 @@ def fn(**kw):
4141
self.assertIsInstance(res, dict)
4242
self.assertEqual(list(res.items()), expected)
4343

44+
def test_kwargs_order_preserved(self):
45+
# PEP 468: Preserving Keyword Argument Order
46+
def fn(**kw):
47+
return list(kw)
48+
49+
self.assertEqual(fn(b=1, a=2, c=3), ['b', 'a', 'c'])
50+
self.assertEqual(fn(c=3, a=2, b=1), ['c', 'a', 'b'])
51+
# Unpacked mappings are merged in place, keeping their own order.
52+
self.assertEqual(fn(z=0, **{'x': 1, 'a': 2}, y=3),
53+
['z', 'x', 'a', 'y'])
54+
self.assertEqual(fn(**{'b': 1}, **{'a': 2}), ['b', 'a'])
55+
# Named parameters are removed from **kwargs without reordering
56+
# the rest.
57+
def fn2(a, c=None, **kw):
58+
return list(kw)
59+
60+
self.assertEqual(fn2(d=1, a=2, b=3, c=4, e=5), ['d', 'b', 'e'])
61+
62+
def test_kwargs_order_preserved_in_methods(self):
63+
# PEP 468: Preserving Keyword Argument Order
64+
class C:
65+
def __init__(self, **kw):
66+
self.init_kw = list(kw)
67+
68+
def meth(self, **kw):
69+
return list(kw)
70+
71+
@classmethod
72+
def cmeth(cls, **kw):
73+
return list(kw)
74+
75+
@staticmethod
76+
def smeth(**kw):
77+
return list(kw)
78+
79+
c = C(b=1, a=2, c=3)
80+
self.assertEqual(c.init_kw, ['b', 'a', 'c'])
81+
self.assertEqual(c.meth(b=1, a=2, c=3), ['b', 'a', 'c'])
82+
self.assertEqual(C.cmeth(b=1, a=2, c=3), ['b', 'a', 'c'])
83+
self.assertEqual(C.smeth(b=1, a=2, c=3), ['b', 'a', 'c'])
84+
85+
def test_kwargs_order_preserved_in_c_functions(self):
86+
# PEP 468: Preserving Keyword Argument Order
87+
self.assertEqual(list(dict(b=1, a=2, c=3)), ['b', 'a', 'c'])
88+
self.assertEqual(list(dict(**{'b': 1}, a=2)), ['b', 'a'])
89+
self.assertEqual(list(collections.OrderedDict(b=1, a=2, c=3)),
90+
['b', 'a', 'c'])
91+
4492
def test_frames_are_popped_after_failed_calls(self):
4593
# GH-93252: stuff blows up if we don't pop the new frame after
4694
# recovering from failed calls:

Lib/test/test_class.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,5 +1034,65 @@ def __init__(self):
10341034
self.fail("MemoryError was not raised during deallocation")
10351035
self.fail("the dictionary was not cleared")
10361036

1037+
class DefinitionOrderTests(unittest.TestCase):
1038+
# PEP 520: Preserving Class Attribute Definition Order
1039+
1040+
@staticmethod
1041+
def defined_names(namespace):
1042+
# Skip the names added by the compiler, like __firstlineno__.
1043+
return [name for name in namespace if not name.startswith('__')]
1044+
1045+
def test_definition_order(self):
1046+
class C:
1047+
b = 1
1048+
a = 2
1049+
def m(self): pass
1050+
@staticmethod
1051+
def s(): pass
1052+
z = 3
1053+
1054+
self.assertEqual(self.defined_names(C.__dict__),
1055+
['b', 'a', 'm', 's', 'z'])
1056+
1057+
def test_definition_order_redefinition(self):
1058+
class C:
1059+
b = 1
1060+
a = 2
1061+
b = 3
1062+
1063+
self.assertEqual(self.defined_names(C.__dict__), ['b', 'a'])
1064+
self.assertEqual(C.b, 3)
1065+
1066+
def test_definition_order_after_deletion(self):
1067+
class C:
1068+
a = 1
1069+
b = 2
1070+
del a
1071+
a = 3
1072+
1073+
self.assertEqual(self.defined_names(C.__dict__), ['b', 'a'])
1074+
1075+
def test_definition_order_in_namespace(self):
1076+
namespaces = []
1077+
class Meta(type):
1078+
def __new__(mcls, name, bases, namespace, **kwds):
1079+
namespaces.append(list(namespace))
1080+
return super().__new__(mcls, name, bases, namespace, **kwds)
1081+
1082+
class C(metaclass=Meta):
1083+
b = 1
1084+
a = 2
1085+
def m(self): pass
1086+
1087+
self.assertEqual(self.defined_names(namespaces[0]), ['b', 'a', 'm'])
1088+
1089+
def test_prepare_preserves_order(self):
1090+
namespace = type.__prepare__('C', ())
1091+
namespace['b'] = 1
1092+
namespace['a'] = 2
1093+
namespace['b'] = 3
1094+
self.assertEqual(list(namespace), ['b', 'a'])
1095+
1096+
10371097
if __name__ == '__main__':
10381098
unittest.main()

0 commit comments

Comments
 (0)