1 """Unit tests for zero-argument super() & related machinery."""
2
3 import unittest
4 from unittest.mock import patch
5 from test import shadowed_super
6
7
8 ADAPTIVE_WARMUP_DELAY = 2
9
10
11 class ESC[4;38;5;81mA:
12 def f(self):
13 return 'A'
14 @classmethod
15 def cm(cls):
16 return (cls, 'A')
17
18 class ESC[4;38;5;81mB(ESC[4;38;5;149mA):
19 def f(self):
20 return super().f() + 'B'
21 @classmethod
22 def cm(cls):
23 return (cls, super().cm(), 'B')
24
25 class ESC[4;38;5;81mC(ESC[4;38;5;149mA):
26 def f(self):
27 return super().f() + 'C'
28 @classmethod
29 def cm(cls):
30 return (cls, super().cm(), 'C')
31
32 class ESC[4;38;5;81mD(ESC[4;38;5;149mC, ESC[4;38;5;149mB):
33 def f(self):
34 return super().f() + 'D'
35 def cm(cls):
36 return (cls, super().cm(), 'D')
37
38 class ESC[4;38;5;81mE(ESC[4;38;5;149mD):
39 pass
40
41 class ESC[4;38;5;81mF(ESC[4;38;5;149mE):
42 f = E.f
43
44 class ESC[4;38;5;81mG(ESC[4;38;5;149mA):
45 pass
46
47
48 class ESC[4;38;5;81mTestSuper(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
49
50 def tearDown(self):
51 # This fixes the damage that test_various___class___pathologies does.
52 nonlocal __class__
53 __class__ = TestSuper
54
55 def test_basics_working(self):
56 self.assertEqual(D().f(), 'ABCD')
57
58 def test_class_getattr_working(self):
59 self.assertEqual(D.f(D()), 'ABCD')
60
61 def test_subclass_no_override_working(self):
62 self.assertEqual(E().f(), 'ABCD')
63 self.assertEqual(E.f(E()), 'ABCD')
64
65 def test_unbound_method_transfer_working(self):
66 self.assertEqual(F().f(), 'ABCD')
67 self.assertEqual(F.f(F()), 'ABCD')
68
69 def test_class_methods_still_working(self):
70 self.assertEqual(A.cm(), (A, 'A'))
71 self.assertEqual(A().cm(), (A, 'A'))
72 self.assertEqual(G.cm(), (G, 'A'))
73 self.assertEqual(G().cm(), (G, 'A'))
74
75 def test_super_in_class_methods_working(self):
76 d = D()
77 self.assertEqual(d.cm(), (d, (D, (D, (D, 'A'), 'B'), 'C'), 'D'))
78 e = E()
79 self.assertEqual(e.cm(), (e, (E, (E, (E, 'A'), 'B'), 'C'), 'D'))
80
81 def test_super_with_closure(self):
82 # Issue4360: super() did not work in a function that
83 # contains a closure
84 class ESC[4;38;5;81mE(ESC[4;38;5;149mA):
85 def f(self):
86 def nested():
87 self
88 return super().f() + 'E'
89
90 self.assertEqual(E().f(), 'AE')
91
92 def test_various___class___pathologies(self):
93 # See issue #12370
94 class ESC[4;38;5;81mX(ESC[4;38;5;149mA):
95 def f(self):
96 return super().f()
97 __class__ = 413
98 x = X()
99 self.assertEqual(x.f(), 'A')
100 self.assertEqual(x.__class__, 413)
101 class ESC[4;38;5;81mX:
102 x = __class__
103 def f():
104 __class__
105 self.assertIs(X.x, type(self))
106 with self.assertRaises(NameError) as e:
107 exec("""class X:
108 __class__
109 def f():
110 __class__""", globals(), {})
111 self.assertIs(type(e.exception), NameError) # Not UnboundLocalError
112 class ESC[4;38;5;81mX:
113 global __class__
114 __class__ = 42
115 def f():
116 __class__
117 self.assertEqual(globals()["__class__"], 42)
118 del globals()["__class__"]
119 self.assertNotIn("__class__", X.__dict__)
120 class ESC[4;38;5;81mX:
121 nonlocal __class__
122 __class__ = 42
123 def f():
124 __class__
125 self.assertEqual(__class__, 42)
126
127 def test___class___instancemethod(self):
128 # See issue #14857
129 class ESC[4;38;5;81mX:
130 def f(self):
131 return __class__
132 self.assertIs(X().f(), X)
133
134 def test___class___classmethod(self):
135 # See issue #14857
136 class ESC[4;38;5;81mX:
137 @classmethod
138 def f(cls):
139 return __class__
140 self.assertIs(X.f(), X)
141
142 def test___class___staticmethod(self):
143 # See issue #14857
144 class ESC[4;38;5;81mX:
145 @staticmethod
146 def f():
147 return __class__
148 self.assertIs(X.f(), X)
149
150 def test___class___new(self):
151 # See issue #23722
152 # Ensure zero-arg super() works as soon as type.__new__() is completed
153 test_class = None
154
155 class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
156 def __new__(cls, name, bases, namespace):
157 nonlocal test_class
158 self = super().__new__(cls, name, bases, namespace)
159 test_class = self.f()
160 return self
161
162 class ESC[4;38;5;81mA(metaclass=ESC[4;38;5;149mMeta):
163 @staticmethod
164 def f():
165 return __class__
166
167 self.assertIs(test_class, A)
168
169 def test___class___delayed(self):
170 # See issue #23722
171 test_namespace = None
172
173 class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
174 def __new__(cls, name, bases, namespace):
175 nonlocal test_namespace
176 test_namespace = namespace
177 return None
178
179 class ESC[4;38;5;81mA(metaclass=ESC[4;38;5;149mMeta):
180 @staticmethod
181 def f():
182 return __class__
183
184 self.assertIs(A, None)
185
186 B = type("B", (), test_namespace)
187 self.assertIs(B.f(), B)
188
189 def test___class___mro(self):
190 # See issue #23722
191 test_class = None
192
193 class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
194 def mro(self):
195 # self.f() doesn't work yet...
196 self.__dict__["f"]()
197 return super().mro()
198
199 class ESC[4;38;5;81mA(metaclass=ESC[4;38;5;149mMeta):
200 def f():
201 nonlocal test_class
202 test_class = __class__
203
204 self.assertIs(test_class, A)
205
206 def test___classcell___expected_behaviour(self):
207 # See issue #23722
208 class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
209 def __new__(cls, name, bases, namespace):
210 nonlocal namespace_snapshot
211 namespace_snapshot = namespace.copy()
212 return super().__new__(cls, name, bases, namespace)
213
214 # __classcell__ is injected into the class namespace by the compiler
215 # when at least one method needs it, and should be omitted otherwise
216 namespace_snapshot = None
217 class ESC[4;38;5;81mWithoutClassRef(metaclass=ESC[4;38;5;149mMeta):
218 pass
219 self.assertNotIn("__classcell__", namespace_snapshot)
220
221 # With zero-arg super() or an explicit __class__ reference,
222 # __classcell__ is the exact cell reference to be populated by
223 # type.__new__
224 namespace_snapshot = None
225 class ESC[4;38;5;81mWithClassRef(metaclass=ESC[4;38;5;149mMeta):
226 def f(self):
227 return __class__
228
229 class_cell = namespace_snapshot["__classcell__"]
230 method_closure = WithClassRef.f.__closure__
231 self.assertEqual(len(method_closure), 1)
232 self.assertIs(class_cell, method_closure[0])
233 # Ensure the cell reference *doesn't* get turned into an attribute
234 with self.assertRaises(AttributeError):
235 WithClassRef.__classcell__
236
237 def test___classcell___missing(self):
238 # See issue #23722
239 # Some metaclasses may not pass the original namespace to type.__new__
240 # We test that case here by forcibly deleting __classcell__
241 class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
242 def __new__(cls, name, bases, namespace):
243 namespace.pop('__classcell__', None)
244 return super().__new__(cls, name, bases, namespace)
245
246 # The default case should continue to work without any errors
247 class ESC[4;38;5;81mWithoutClassRef(metaclass=ESC[4;38;5;149mMeta):
248 pass
249
250 # With zero-arg super() or an explicit __class__ reference, we expect
251 # __build_class__ to raise a RuntimeError complaining that
252 # __class__ was not set, and asking if __classcell__ was propagated
253 # to type.__new__.
254 expected_error = '__class__ not set.*__classcell__ propagated'
255 with self.assertRaisesRegex(RuntimeError, expected_error):
256 class ESC[4;38;5;81mWithClassRef(metaclass=ESC[4;38;5;149mMeta):
257 def f(self):
258 return __class__
259
260 def test___classcell___overwrite(self):
261 # See issue #23722
262 # Overwriting __classcell__ with nonsense is explicitly prohibited
263 class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
264 def __new__(cls, name, bases, namespace, cell):
265 namespace['__classcell__'] = cell
266 return super().__new__(cls, name, bases, namespace)
267
268 for bad_cell in (None, 0, "", object()):
269 with self.subTest(bad_cell=bad_cell):
270 with self.assertRaises(TypeError):
271 class ESC[4;38;5;81mA(metaclass=ESC[4;38;5;149mMeta, cell=ESC[4;38;5;149mbad_cell):
272 pass
273
274 def test___classcell___wrong_cell(self):
275 # See issue #23722
276 # Pointing the cell reference at the wrong class is also prohibited
277 class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
278 def __new__(cls, name, bases, namespace):
279 cls = super().__new__(cls, name, bases, namespace)
280 B = type("B", (), namespace)
281 return cls
282
283 with self.assertRaises(TypeError):
284 class ESC[4;38;5;81mA(metaclass=ESC[4;38;5;149mMeta):
285 def f(self):
286 return __class__
287
288 def test_obscure_super_errors(self):
289 def f():
290 super()
291 with self.assertRaisesRegex(RuntimeError, r"no arguments"):
292 f()
293
294 class ESC[4;38;5;81mC:
295 def f():
296 super()
297 with self.assertRaisesRegex(RuntimeError, r"no arguments"):
298 C.f()
299
300 def f(x):
301 del x
302 super()
303 with self.assertRaisesRegex(RuntimeError, r"arg\[0\] deleted"):
304 f(None)
305
306 class ESC[4;38;5;81mX:
307 def f(x):
308 nonlocal __class__
309 del __class__
310 super()
311 with self.assertRaisesRegex(RuntimeError, r"empty __class__ cell"):
312 X().f()
313
314 def test_cell_as_self(self):
315 class ESC[4;38;5;81mX:
316 def meth(self):
317 super()
318
319 def f():
320 k = X()
321 def g():
322 return k
323 return g
324 c = f().__closure__[0]
325 self.assertRaises(TypeError, X.meth, c)
326
327 def test_super_init_leaks(self):
328 # Issue #26718: super.__init__ leaked memory if called multiple times.
329 # This will be caught by regrtest.py -R if this leak.
330 # NOTE: Despite the use in the test a direct call of super.__init__
331 # is not endorsed.
332 sp = super(float, 1.0)
333 for i in range(1000):
334 super.__init__(sp, int, i)
335
336 def test_super_argcount(self):
337 with self.assertRaisesRegex(TypeError, "expected at most"):
338 super(int, int, int)
339
340 def test_super_argtype(self):
341 with self.assertRaisesRegex(TypeError, "argument 1 must be a type"):
342 super(1, int)
343
344 def test_shadowed_global(self):
345 self.assertEqual(shadowed_super.C().method(), "truly super")
346
347 def test_shadowed_local(self):
348 class ESC[4;38;5;81msuper:
349 msg = "quite super"
350
351 class ESC[4;38;5;81mC:
352 def method(self):
353 return super().msg
354
355 self.assertEqual(C().method(), "quite super")
356
357 def test_shadowed_dynamic(self):
358 class ESC[4;38;5;81mMySuper:
359 msg = "super super"
360
361 class ESC[4;38;5;81mC:
362 def method(self):
363 return super().msg
364
365 with patch(f"{__name__}.super", MySuper) as m:
366 self.assertEqual(C().method(), "super super")
367
368 def test_shadowed_dynamic_two_arg(self):
369 call_args = []
370 class ESC[4;38;5;81mMySuper:
371 def __init__(self, *args):
372 call_args.append(args)
373 msg = "super super"
374
375 class ESC[4;38;5;81mC:
376 def method(self):
377 return super(1, 2).msg
378
379 with patch(f"{__name__}.super", MySuper) as m:
380 self.assertEqual(C().method(), "super super")
381 self.assertEqual(call_args, [(1, 2)])
382
383 def test_attribute_error(self):
384 class ESC[4;38;5;81mC:
385 def method(self):
386 return super().msg
387
388 with self.assertRaisesRegex(AttributeError, "'super' object has no attribute 'msg'"):
389 C().method()
390
391 def test_bad_first_arg(self):
392 class ESC[4;38;5;81mC:
393 def method(self):
394 return super(1, self).method()
395
396 with self.assertRaisesRegex(TypeError, "argument 1 must be a type"):
397 C().method()
398
399 def test_super___class__(self):
400 class ESC[4;38;5;81mC:
401 def method(self):
402 return super().__class__
403
404 self.assertEqual(C().method(), super)
405
406 def test_super_subclass___class__(self):
407 class ESC[4;38;5;81mmysuper(ESC[4;38;5;149msuper):
408 pass
409
410 class ESC[4;38;5;81mC:
411 def method(self):
412 return mysuper(C, self).__class__
413
414 self.assertEqual(C().method(), mysuper)
415
416 def test_unusual_getattro(self):
417 class ESC[4;38;5;81mMyType(ESC[4;38;5;149mtype):
418 pass
419
420 def test(name):
421 mytype = MyType(name, (MyType,), {})
422 super(MyType, type(mytype)).__setattr__(mytype, "bar", 1)
423 self.assertEqual(mytype.bar, 1)
424
425 for _ in range(ADAPTIVE_WARMUP_DELAY):
426 test("foo1")
427
428 def test_reassigned_new(self):
429 class ESC[4;38;5;81mA:
430 def __new__(cls):
431 pass
432
433 def __init_subclass__(cls):
434 if "__new__" not in cls.__dict__:
435 cls.__new__ = cls.__new__
436
437 class ESC[4;38;5;81mB(ESC[4;38;5;149mA):
438 pass
439
440 class ESC[4;38;5;81mC(ESC[4;38;5;149mB):
441 def __new__(cls):
442 return super().__new__(cls)
443
444 for _ in range(ADAPTIVE_WARMUP_DELAY):
445 C()
446
447 def test_mixed_staticmethod_hierarchy(self):
448 # This test is just a desugared version of `test_reassigned_new`
449 class ESC[4;38;5;81mA:
450 @staticmethod
451 def some(cls, *args, **kwargs):
452 self.assertFalse(args)
453 self.assertFalse(kwargs)
454
455 class ESC[4;38;5;81mB(ESC[4;38;5;149mA):
456 def some(cls, *args, **kwargs):
457 return super().some(cls, *args, **kwargs)
458
459 class ESC[4;38;5;81mC(ESC[4;38;5;149mB):
460 @staticmethod
461 def some(cls):
462 return super().some(cls)
463
464 for _ in range(ADAPTIVE_WARMUP_DELAY):
465 C.some(C)
466
467
468 if __name__ == "__main__":
469 unittest.main()