1 """Unit tests for zero-argument super() & related machinery.""" 2 3 import unittest 4 import warnings 5 from test.support import check_warnings 6 7 8 class A: 9 def f(self): 10 return 'A' 11 @classmethod 12 def cm(cls): 13 return (cls, 'A') 14 15 class B(A): 16 def f(self): 17 return super().f() + 'B' 18 @classmethod 19 def cm(cls): 20 return (cls, super().cm(), 'B') 21 22 class C(A): 23 def f(self): 24 return super().f() + 'C' 25 @classmethod 26 def cm(cls): 27 return (cls, super().cm(), 'C') 28 29 class D(C, B): 30 def f(self): 31 return super().f() + 'D' 32 def cm(cls): 33 return (cls, super().cm(), 'D') 34 35 class E(D): 36 pass 37 38 class F(E): 39 f = E.f 40 41 class G(A): 42 pass 43 44 45 class TestSuper(unittest.TestCase): 46 47 def tearDown(self): 48 # This fixes the damage that test_various___class___pathologies does. 49 nonlocal __class__ 50 __class__ = TestSuper 51 52 def test_basics_working(self): 53 self.assertEqual(D().f(), 'ABCD') 54 55 def test_class_getattr_working(self): 56 self.assertEqual(D.f(D()), 'ABCD') 57 58 def test_subclass_no_override_working(self): 59 self.assertEqual(E().f(), 'ABCD') 60 self.assertEqual(E.f(E()), 'ABCD') 61 62 def test_unbound_method_transfer_working(self): 63 self.assertEqual(F().f(), 'ABCD') 64 self.assertEqual(F.f(F()), 'ABCD') 65 66 def test_class_methods_still_working(self): 67 self.assertEqual(A.cm(), (A, 'A')) 68 self.assertEqual(A().cm(), (A, 'A')) 69 self.assertEqual(G.cm(), (G, 'A')) 70 self.assertEqual(G().cm(), (G, 'A')) 71 72 def test_super_in_class_methods_working(self): 73 d = D() 74 self.assertEqual(d.cm(), (d, (D, (D, (D, 'A'), 'B'), 'C'), 'D')) 75 e = E() 76 self.assertEqual(e.cm(), (e, (E, (E, (E, 'A'), 'B'), 'C'), 'D')) 77 78 def test_super_with_closure(self): 79 # Issue4360: super() did not work in a function that 80 # contains a closure 81 class E(A): 82 def f(self): 83 def nested(): 84 self 85 return super().f() + 'E' 86 87 self.assertEqual(E().f(), 'AE') 88 89 def test_various___class___pathologies(self): 90 # See issue #12370 91 class X(A): 92 def f(self): 93 return super().f() 94 __class__ = 413 95 x = X() 96 self.assertEqual(x.f(), 'A') 97 self.assertEqual(x.__class__, 413) 98 class X: 99 x = __class__ 100 def f(): 101 __class__ 102 self.assertIs(X.x, type(self)) 103 with self.assertRaises(NameError) as e: 104 exec("""class X: 105 __class__ 106 def f(): 107 __class__""", globals(), {}) 108 self.assertIs(type(e.exception), NameError) # Not UnboundLocalError 109 class X: 110 global __class__ 111 __class__ = 42 112 def f(): 113 __class__ 114 self.assertEqual(globals()["__class__"], 42) 115 del globals()["__class__"] 116 self.assertNotIn("__class__", X.__dict__) 117 class X: 118 nonlocal __class__ 119 __class__ = 42 120 def f(): 121 __class__ 122 self.assertEqual(__class__, 42) 123 124 def test___class___instancemethod(self): 125 # See issue #14857 126 class X: 127 def f(self): 128 return __class__ 129 self.assertIs(X().f(), X) 130 131 def test___class___classmethod(self): 132 # See issue #14857 133 class X: 134 @classmethod 135 def f(cls): 136 return __class__ 137 self.assertIs(X.f(), X) 138 139 def test___class___staticmethod(self): 140 # See issue #14857 141 class X: 142 @staticmethod 143 def f(): 144 return __class__ 145 self.assertIs(X.f(), X) 146 147 def test___class___new(self): 148 # See issue #23722 149 # Ensure zero-arg super() works as soon as type.__new__() is completed 150 test_class = None 151 152 class Meta(type): 153 def __new__(cls, name, bases, namespace): 154 nonlocal test_class 155 self = super().__new__(cls, name, bases, namespace) 156 test_class = self.f() 157 return self 158 159 class A(metaclass=Meta): 160 @staticmethod 161 def f(): 162 return __class__ 163 164 self.assertIs(test_class, A) 165 166 def test___class___delayed(self): 167 # See issue #23722 168 test_namespace = None 169 170 class Meta(type): 171 def __new__(cls, name, bases, namespace): 172 nonlocal test_namespace 173 test_namespace = namespace 174 return None 175 176 # This case shouldn't trigger the __classcell__ deprecation warning 177 with check_warnings() as w: 178 warnings.simplefilter("always", DeprecationWarning) 179 class A(metaclass=Meta): 180 @staticmethod 181 def f(): 182 return __class__ 183 self.assertEqual(w.warnings, []) 184 185 self.assertIs(A, None) 186 187 B = type("B", (), test_namespace) 188 self.assertIs(B.f(), B) 189 190 def test___class___mro(self): 191 # See issue #23722 192 test_class = None 193 194 class Meta(type): 195 def mro(self): 196 # self.f() doesn't work yet... 197 self.__dict__["f"]() 198 return super().mro() 199 200 class A(metaclass=Meta): 201 def f(): 202 nonlocal test_class 203 test_class = __class__ 204 205 self.assertIs(test_class, A) 206 207 def test___classcell___expected_behaviour(self): 208 # See issue #23722 209 class Meta(type): 210 def __new__(cls, name, bases, namespace): 211 nonlocal namespace_snapshot 212 namespace_snapshot = namespace.copy() 213 return super().__new__(cls, name, bases, namespace) 214 215 # __classcell__ is injected into the class namespace by the compiler 216 # when at least one method needs it, and should be omitted otherwise 217 namespace_snapshot = None 218 class WithoutClassRef(metaclass=Meta): 219 pass 220 self.assertNotIn("__classcell__", namespace_snapshot) 221 222 # With zero-arg super() or an explicit __class__ reference, 223 # __classcell__ is the exact cell reference to be populated by 224 # type.__new__ 225 namespace_snapshot = None 226 class WithClassRef(metaclass=Meta): 227 def f(self): 228 return __class__ 229 230 class_cell = namespace_snapshot["__classcell__"] 231 method_closure = WithClassRef.f.__closure__ 232 self.assertEqual(len(method_closure), 1) 233 self.assertIs(class_cell, method_closure[0]) 234 # Ensure the cell reference *doesn't* get turned into an attribute 235 with self.assertRaises(AttributeError): 236 WithClassRef.__classcell__ 237 238 def test___classcell___missing(self): 239 # See issue #23722 240 # Some metaclasses may not pass the original namespace to type.__new__ 241 # We test that case here by forcibly deleting __classcell__ 242 class Meta(type): 243 def __new__(cls, name, bases, namespace): 244 namespace.pop('__classcell__', None) 245 return super().__new__(cls, name, bases, namespace) 246 247 # The default case should continue to work without any warnings 248 with check_warnings() as w: 249 warnings.simplefilter("always", DeprecationWarning) 250 class WithoutClassRef(metaclass=Meta): 251 pass 252 self.assertEqual(w.warnings, []) 253 254 # With zero-arg super() or an explicit __class__ reference, we expect 255 # __build_class__ to emit a DeprecationWarning complaining that 256 # __class__ was not set, and asking if __classcell__ was propagated 257 # to type.__new__. 258 # In Python 3.7, that warning will become a RuntimeError. 259 expected_warning = ( 260 '__class__ not set.*__classcell__ propagated', 261 DeprecationWarning 262 ) 263 with check_warnings(expected_warning): 264 warnings.simplefilter("always", DeprecationWarning) 265 class WithClassRef(metaclass=Meta): 266 def f(self): 267 return __class__ 268 # Check __class__ still gets set despite the warning 269 self.assertIs(WithClassRef().f(), WithClassRef) 270 271 # Check the warning is turned into an error as expected 272 with warnings.catch_warnings(): 273 warnings.simplefilter("error", DeprecationWarning) 274 with self.assertRaises(DeprecationWarning): 275 class WithClassRef(metaclass=Meta): 276 def f(self): 277 return __class__ 278 279 def test___classcell___overwrite(self): 280 # See issue #23722 281 # Overwriting __classcell__ with nonsense is explicitly prohibited 282 class Meta(type): 283 def __new__(cls, name, bases, namespace, cell): 284 namespace['__classcell__'] = cell 285 return super().__new__(cls, name, bases, namespace) 286 287 for bad_cell in (None, 0, "", object()): 288 with self.subTest(bad_cell=bad_cell): 289 with self.assertRaises(TypeError): 290 class A(metaclass=Meta, cell=bad_cell): 291 pass 292 293 def test___classcell___wrong_cell(self): 294 # See issue #23722 295 # Pointing the cell reference at the wrong class is also prohibited 296 class Meta(type): 297 def __new__(cls, name, bases, namespace): 298 cls = super().__new__(cls, name, bases, namespace) 299 B = type("B", (), namespace) 300 return cls 301 302 with self.assertRaises(TypeError): 303 class A(metaclass=Meta): 304 def f(self): 305 return __class__ 306 307 def test_obscure_super_errors(self): 308 def f(): 309 super() 310 self.assertRaises(RuntimeError, f) 311 def f(x): 312 del x 313 super() 314 self.assertRaises(RuntimeError, f, None) 315 class X: 316 def f(x): 317 nonlocal __class__ 318 del __class__ 319 super() 320 self.assertRaises(RuntimeError, X().f) 321 322 def test_cell_as_self(self): 323 class X: 324 def meth(self): 325 super() 326 327 def f(): 328 k = X() 329 def g(): 330 return k 331 return g 332 c = f().__closure__[0] 333 self.assertRaises(TypeError, X.meth, c) 334 335 def test_super_init_leaks(self): 336 # Issue #26718: super.__init__ leaked memory if called multiple times. 337 # This will be caught by regrtest.py -R if this leak. 338 # NOTE: Despite the use in the test a direct call of super.__init__ 339 # is not endorsed. 340 sp = super(float, 1.0) 341 for i in range(1000): 342 super.__init__(sp, int, i) 343 344 345 if __name__ == "__main__": 346 unittest.main() 347