Skip to content

Commit 9db2cad

Browse files
[3.14] gh-78526: Add tests for PEP 468 and PEP 520 (GH-155387) (GH-155677)
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 533578b commit 9db2cad

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
@@ -1051,5 +1051,65 @@ def __init__(self):
10511051
self.fail("MemoryError was not raised during deallocation")
10521052
self.fail("the dictionary was not cleared")
10531053

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

0 commit comments

Comments
 (0)