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