Skip to content

Commit 116caab

Browse files
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.
1 parent 582a2d3 commit 116caab

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
@@ -47,6 +47,54 @@ def fn(**kw):
4747
self.assertIsInstance(res, dict)
4848
self.assertEqual(list(res.items()), expected)
4949

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

Lib/test/test_class.py

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

1055+
class DefinitionOrderTests(unittest.TestCase):
1056+
# PEP 520: Preserving Class Attribute Definition Order
1057+
1058+
@staticmethod
1059+
def defined_names(namespace):
1060+
# Skip the names added by the compiler, like __firstlineno__.
1061+
return [name for name in namespace if not name.startswith('__')]
1062+
1063+
def test_definition_order(self):
1064+
class C:
1065+
b = 1
1066+
a = 2
1067+
def m(self): pass
1068+
@staticmethod
1069+
def s(): pass
1070+
z = 3
1071+
1072+
self.assertEqual(self.defined_names(C.__dict__),
1073+
['b', 'a', 'm', 's', 'z'])
1074+
1075+
def test_definition_order_redefinition(self):
1076+
class C:
1077+
b = 1
1078+
a = 2
1079+
b = 3
1080+
1081+
self.assertEqual(self.defined_names(C.__dict__), ['b', 'a'])
1082+
self.assertEqual(C.b, 3)
1083+
1084+
def test_definition_order_after_deletion(self):
1085+
class C:
1086+
a = 1
1087+
b = 2
1088+
del a
1089+
a = 3
1090+
1091+
self.assertEqual(self.defined_names(C.__dict__), ['b', 'a'])
1092+
1093+
def test_definition_order_in_namespace(self):
1094+
namespaces = []
1095+
class Meta(type):
1096+
def __new__(mcls, name, bases, namespace, **kwds):
1097+
namespaces.append(list(namespace))
1098+
return super().__new__(mcls, name, bases, namespace, **kwds)
1099+
1100+
class C(metaclass=Meta):
1101+
b = 1
1102+
a = 2
1103+
def m(self): pass
1104+
1105+
self.assertEqual(self.defined_names(namespaces[0]), ['b', 'a', 'm'])
1106+
1107+
def test_prepare_preserves_order(self):
1108+
namespace = type.__prepare__('C', ())
1109+
namespace['b'] = 1
1110+
namespace['a'] = 2
1111+
namespace['b'] = 3
1112+
self.assertEqual(list(namespace), ['b', 'a'])
1113+
1114+
10551115
if __name__ == '__main__':
10561116
unittest.main()

0 commit comments

Comments
 (0)