Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(201893)

Delta Between Two Patch Sets: Lib/test/test_super.py

Issue 23722: During metaclass.__init__, super() of the constructed class does not work
Left Patch Set: Created 3 years ago
Right Patch Set: Created 3 years ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 """Unit tests for zero-argument super() & related machinery.""" 1 """Unit tests for zero-argument super() & related machinery."""
2 2
3 import sys 3 import sys
4 import unittest 4 import unittest
5 import warnings 5 import warnings
6 from test.support import check_warnings 6 from test.support import check_warnings
7 7
8 8
9 class A: 9 class A:
10 def f(self): 10 def f(self):
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 def test___class___delayed(self): 167 def test___class___delayed(self):
168 # See issue #23722 168 # See issue #23722
169 test_namespace = None 169 test_namespace = None
170 170
171 class Meta(type): 171 class Meta(type):
172 def __new__(cls, name, bases, namespace): 172 def __new__(cls, name, bases, namespace):
173 nonlocal test_namespace 173 nonlocal test_namespace
174 test_namespace = namespace 174 test_namespace = namespace
175 return None 175 return None
176 176
177 class A(metaclass=Meta): 177 # This case shouldn't trigger the __classcell__ deprecation warning
178 @staticmethod 178 with check_warnings() as w:
179 def f(): 179 warnings.simplefilter("always", DeprecationWarning)
180 return __class__ 180 class A(metaclass=Meta):
181 @staticmethod
182 def f():
183 return __class__
184 self.assertEqual(w.warnings, [])
181 185
182 self.assertIs(A, None) 186 self.assertIs(A, None)
183 187
184 B = type("B", (), test_namespace) 188 B = type("B", (), test_namespace)
185 self.assertIs(B.f(), B) 189 self.assertIs(B.f(), B)
186 190
187 def test___class___mro(self): 191 def test___class___mro(self):
188 # See issue #23722 192 # See issue #23722
189 test_class = None 193 test_class = None
190 194
191 class Meta(type): 195 class Meta(type):
192 def mro(self): 196 def mro(self):
193 # self.f() doesn't work yet... 197 # self.f() doesn't work yet...
194 self.__dict__["f"]() 198 self.__dict__["f"]()
195 return super().mro() 199 return super().mro()
196 200
197 class A(metaclass=Meta): 201 class A(metaclass=Meta):
198 def f(): 202 def f():
199 nonlocal test_class 203 nonlocal test_class
200 test_class = __class__ 204 test_class = __class__
201 205
202 self.assertIs(test_class, A) 206 self.assertIs(test_class, A)
203 207
204 def test___classcell___expected_behaviour(self): 208 def test___classcell___expected_behaviour(self):
205 # See issue #23722 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
206 # __classcell__ is injected into the class namespace by the compiler 216 # __classcell__ is injected into the class namespace by the compiler
207 # The injected reference is None by default 217 # when at least one method needs it, and should be omitted otherwise
208 class_cell = object() 218 namespace_snapshot = None
209 class Meta(type): 219 class WithoutClassRef(metaclass=Meta):
210 def __new__(cls, name, bases, namespace): 220 pass
211 nonlocal class_cell 221 self.assertNotIn("__classcell__", namespace_snapshot)
212 class_cell = namespace["__classcell__"] 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)
213 return super().__new__(cls, name, bases, namespace) 246 return super().__new__(cls, name, bases, namespace)
214 247
215 class A(metaclass=Meta): 248 # The default case should continue to work without any warnings
216 pass 249 with check_warnings() as w:
217 250 warnings.simplefilter("always", DeprecationWarning)
218 with self.assertRaises(AttributeError): 251 class WithoutClassRef(metaclass=Meta):
219 A.__classcell__ 252 pass
220 self.assertIsNone(class_cell) 253 self.assertEqual(w.warnings, [])
221 254
222 # With zero-arg super() or an explicit __class__ reference, 255 # With zero-arg super() or an explicit __class__ reference, we expect
223 # __classcell__ is an actual cell reference that gets populated by 256 # __build_class__ to emit a DeprecationWarning complaining that
224 # type.__new__ 257 # __class__ was not set, and asking if __classcell__ was propagated
225 class B(metaclass=Meta): 258 # to type.__new__.
226 @staticmethod 259 # In Python 3.7, that warning will become a RuntimeError.
227 def f(): 260 expected_warning = (
228 __class__ 261 '__class__ not set.*__classcell__ propagated',
229 262 DeprecationWarning
230 with self.assertRaises(AttributeError):
231 B.__classcell__
232 self.assertIsNotNone(class_cell)
233
234 def test___classcell___missing(self):
235 # See issue #23722
236 # Some classes may not pass the original namespace up to type.__new__
237 # We test that case by deleting __classcell__, and check that it
238 # still works for now, but emits a RuntimeWarning & DeprecationWarning
239 # In Python 3.7, it will become a RuntimeError to leave it out.
240 class Meta(type):
241 def __new__(cls, name, bases, namespace):
242 del namespace['__classcell__']
243 return super().__new__(cls, name, bases, namespace)
244
245 # Check default behaviour is to emit warnings
246 expected_warnings = (
247 ('__classcell__ missing', RuntimeWarning),
248 ('__class__ not set', DeprecationWarning),
249 ) 263 )
250 with check_warnings(*expected_warnings): 264 with check_warnings(expected_warning):
251 class A(metaclass=Meta): 265 warnings.simplefilter("always", DeprecationWarning)
252 @staticmethod 266 class WithClassRef(metaclass=Meta):
253 def f(): 267 def f(self):
254 return __class__ 268 return __class__
255 # Check __class__ still gets set despite the warnings 269 # Check __class__ still gets set despite the warning
256 self.assertIs(A.f(), A) 270 self.assertIs(WithClassRef().f(), WithClassRef)
257 271
258 # Check the warnings are turned into errors as expected 272 # Check the warning is turned into an error as expected
259 with warnings.catch_warnings(): 273 with warnings.catch_warnings():
260 warnings.simplefilter("error", DeprecationWarning) 274 warnings.simplefilter("error", DeprecationWarning)
261 with self.assertRaises(DeprecationWarning): 275 with self.assertRaises(DeprecationWarning):
262 class B(metaclass=Meta): 276 class WithClassRef(metaclass=Meta):
263 pass 277 def f(self):
264 278 return __class__
265 warnings.simplefilter("error", RuntimeWarning) 279
266 with self.assertRaises(RuntimeWarning): 280 def test___classcell___overwrite(self):
267 class C(metaclass=Meta): 281 # See issue #23722
268 pass 282 # Overwriting __classcell__ with nonsense is explicitly prohibited
269 283 class Meta(type):
270 def test___classcell___reset(self): 284 def __new__(cls, name, bases, namespace, cell):
271 # See issue #23722 285 namespace['__classcell__'] = cell
272 # Setting __classcell__ to None will disable zero-argument super()
273 class Meta(type):
274 def __new__(cls, name, bases, namespace):
275 namespace['__classcell__'] = None
276 return super().__new__(cls, name, bases, namespace) 286 return super().__new__(cls, name, bases, namespace)
277 287
278 class A(metaclass=Meta): 288 for bad_cell in (None, 0, "", object()):
279 @staticmethod 289 with self.subTest(bad_cell=bad_cell):
280 def f(): 290 with self.assertRaises(TypeError):
281 __class__ 291 class A(metaclass=Meta, cell=bad_cell):
282 292 pass
283 with self.assertRaises(NameError): 293
284 A.f() 294 def test___classcell___wrong_cell(self):
285 295 # See issue #23722
286 def test___classcell___overwrite(self): 296 # Pointing the cell reference at the wrong class is also prohibited
287 # See issue #23722 297 class Meta(type):
288 # Overwriting __classcell__ with nonsense is just plain disallowed 298 def __new__(cls, name, bases, namespace):
289 class Meta(type): 299 cls = super().__new__(cls, name, bases, namespace)
290 def __new__(cls, name, bases, namespace): 300 B = type("B", (), namespace)
291 namespace['__classcell__'] = 0 301 return cls
292 return super().__new__(cls, name, bases, namespace)
293 302
294 with self.assertRaises(TypeError): 303 with self.assertRaises(TypeError):
295 class A(metaclass=Meta): 304 class A(metaclass=Meta):
296 pass 305 def f(self):
306 return __class__
297 307
298 def test_obscure_super_errors(self): 308 def test_obscure_super_errors(self):
299 def f(): 309 def f():
300 super() 310 super()
301 self.assertRaises(RuntimeError, f) 311 self.assertRaises(RuntimeError, f)
302 def f(x): 312 def f(x):
303 del x 313 del x
304 super() 314 super()
305 self.assertRaises(RuntimeError, f, None) 315 self.assertRaises(RuntimeError, f, None)
306 class X: 316 class X:
(...skipping 21 matching lines...) Expand all
328 # This will be caught by regrtest.py -R if this leak. 338 # This will be caught by regrtest.py -R if this leak.
329 # NOTE: Despite the use in the test a direct call of super.__init__ 339 # NOTE: Despite the use in the test a direct call of super.__init__
330 # is not endorsed. 340 # is not endorsed.
331 sp = super(float, 1.0) 341 sp = super(float, 1.0)
332 for i in range(1000): 342 for i in range(1000):
333 super.__init__(sp, int, i) 343 super.__init__(sp, int, i)
334 344
335 345
336 if __name__ == "__main__": 346 if __name__ == "__main__":
337 unittest.main() 347 unittest.main()
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+