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

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 inspect
Nick Coghlan 2016/12/04 13:39:05 This isn't actually needed (I added it when I was
4 import sys 3 import sys
5 import unittest 4 import unittest
6 import warnings 5 import warnings
7 from test.support import check_warnings 6 from test.support import check_warnings
8 7
9 8
10 class A: 9 class A:
11 def f(self): 10 def f(self):
12 return 'A' 11 return 'A'
13 @classmethod 12 @classmethod
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 def test___class___delayed(self): 167 def test___class___delayed(self):
169 # See issue #23722 168 # See issue #23722
170 test_namespace = None 169 test_namespace = None
171 170
172 class Meta(type): 171 class Meta(type):
173 def __new__(cls, name, bases, namespace): 172 def __new__(cls, name, bases, namespace):
174 nonlocal test_namespace 173 nonlocal test_namespace
175 test_namespace = namespace 174 test_namespace = namespace
176 return None 175 return None
177 176
178 class A(metaclass=Meta): 177 # This case shouldn't trigger the __classcell__ deprecation warning
179 @staticmethod 178 with check_warnings() as w:
180 def f(): 179 warnings.simplefilter("always", DeprecationWarning)
181 return __class__ 180 class A(metaclass=Meta):
181 @staticmethod
182 def f():
183 return __class__
184 self.assertEqual(w.warnings, [])
182 185
183 self.assertIs(A, None) 186 self.assertIs(A, None)
184 187
185 B = type("B", (), test_namespace) 188 B = type("B", (), test_namespace)
186 self.assertIs(B.f(), B) 189 self.assertIs(B.f(), B)
187 190
188 def test___class___mro(self): 191 def test___class___mro(self):
189 # See issue #23722 192 # See issue #23722
190 test_class = None 193 test_class = None
191 194
192 class Meta(type): 195 class Meta(type):
193 def mro(self): 196 def mro(self):
194 # self.f() doesn't work yet... 197 # self.f() doesn't work yet...
195 self.__dict__["f"]() 198 self.__dict__["f"]()
196 return super().mro() 199 return super().mro()
197 200
198 class A(metaclass=Meta): 201 class A(metaclass=Meta):
199 def f(): 202 def f():
200 nonlocal test_class 203 nonlocal test_class
201 test_class = __class__ 204 test_class = __class__
202 205
203 self.assertIs(test_class, A) 206 self.assertIs(test_class, A)
204 207
205 def test___classcell___expected_behaviour(self): 208 def test___classcell___expected_behaviour(self):
206 # See issue #23722 209 # See issue #23722
207 namespace_snapshot = None
208 class Meta(type): 210 class Meta(type):
209 def __new__(cls, name, bases, namespace): 211 def __new__(cls, name, bases, namespace):
210 nonlocal namespace_snapshot 212 nonlocal namespace_snapshot
211 namespace_snapshot = namespace.copy() 213 namespace_snapshot = namespace.copy()
212 return super().__new__(cls, name, bases, namespace) 214 return super().__new__(cls, name, bases, namespace)
213 215
214 # __classcell__ is injected into the class namespace by the compiler 216 # __classcell__ is injected into the class namespace by the compiler
215 # when at least one method needs it, and should be omitted otherwise 217 # when at least one method needs it, and should be omitted otherwise
218 namespace_snapshot = None
216 class WithoutClassRef(metaclass=Meta): 219 class WithoutClassRef(metaclass=Meta):
217 pass 220 pass
218 self.assertNotIn("__classcell__", namespace_snapshot) 221 self.assertNotIn("__classcell__", namespace_snapshot)
219 222
220 # With zero-arg super() or an explicit __class__ reference, 223 # With zero-arg super() or an explicit __class__ reference,
221 # __classcell__ is the exact cell reference to be populated by 224 # __classcell__ is the exact cell reference to be populated by
222 # type.__new__ 225 # type.__new__
226 namespace_snapshot = None
223 class WithClassRef(metaclass=Meta): 227 class WithClassRef(metaclass=Meta):
storchaka 2016/12/04 11:23:35 Shouldn't namespace_snapshot be reset?
Nick Coghlan 2016/12/04 13:39:05 It's not required, but there's no harm in doing so
224 def f(self): 228 def f(self):
225 return __class__ 229 return __class__
226 230
227 class_cell = namespace_snapshot["__classcell__"] 231 class_cell = namespace_snapshot["__classcell__"]
228 method_closure = WithClassRef.f.__closure__ 232 method_closure = WithClassRef.f.__closure__
229 self.assertEqual(len(method_closure), 1) 233 self.assertEqual(len(method_closure), 1)
230 self.assertIs(class_cell, method_closure[0]) 234 self.assertIs(class_cell, method_closure[0])
231 # Ensure the cell reference *doesn't* get turned into an attribute 235 # Ensure the cell reference *doesn't* get turned into an attribute
232 with self.assertRaises(AttributeError): 236 with self.assertRaises(AttributeError):
233 WithClassRef.__classcell__ 237 WithClassRef.__classcell__
234 238
235 def test___classcell___missing(self): 239 def test___classcell___missing(self):
236 # See issue #23722 240 # See issue #23722
237 # Some metaclasses may not pass the original namespace to type.__new__ 241 # Some metaclasses may not pass the original namespace to type.__new__
238 # We test that case here by forcibly deleting __classcell__ 242 # We test that case here by forcibly deleting __classcell__
239 class Meta(type): 243 class Meta(type):
240 def __new__(cls, name, bases, namespace): 244 def __new__(cls, name, bases, namespace):
241 namespace.pop('__classcell__', None) 245 namespace.pop('__classcell__', None)
242 return super().__new__(cls, name, bases, namespace) 246 return super().__new__(cls, name, bases, namespace)
243 247
244 # The default case should continue to work without any warnings 248 # The default case should continue to work without any warnings
245 with check_warnings() as w: 249 with check_warnings() as w:
storchaka 2016/12/04 11:23:35 Is it needed to add: warnings.simplefilter("a
Nick Coghlan 2016/12/04 13:39:05 Indeed it is, good catch.
250 warnings.simplefilter("always", DeprecationWarning)
246 class WithoutClassRef(metaclass=Meta): 251 class WithoutClassRef(metaclass=Meta):
247 pass 252 pass
248 self.assertEqual(len(w.warnings), 0) 253 self.assertEqual(w.warnings, [])
storchaka 2016/12/04 11:23:35 Better: self.assertEqual(w.warnings, []) Thi
Nick Coghlan 2016/12/04 13:39:05 Done.
249 254
250 # With zero-arg super() or an explicit __class__ reference, we expect 255 # With zero-arg super() or an explicit __class__ reference, we expect
251 # __build_class__ to emit a DeprecationWarning complaining that 256 # __build_class__ to emit a DeprecationWarning complaining that
252 # __class__ was not set, and asking if __classcell__ was propagated 257 # __class__ was not set, and asking if __classcell__ was propagated
253 # to type.__new__. 258 # to type.__new__.
254 # In Python 3.7, that warning will become a RuntimeError. 259 # In Python 3.7, that warning will become a RuntimeError.
255 expected_warning = ( 260 expected_warning = (
256 '__class__ not set.*__classcell__ propagated', 261 '__class__ not set.*__classcell__ propagated',
257 DeprecationWarning 262 DeprecationWarning
258 ) 263 )
259 with check_warnings(expected_warning): 264 with check_warnings(expected_warning):
storchaka 2016/12/04 11:23:35 Same as above.
265 warnings.simplefilter("always", DeprecationWarning)
260 class WithClassRef(metaclass=Meta): 266 class WithClassRef(metaclass=Meta):
261 def f(self): 267 def f(self):
262 return __class__ 268 return __class__
263 # Check __class__ still gets set despite the warning 269 # Check __class__ still gets set despite the warning
264 self.assertIs(WithClassRef().f(), WithClassRef) 270 self.assertIs(WithClassRef().f(), WithClassRef)
265 271
266 # Check the warning is turned into an error as expected 272 # Check the warning is turned into an error as expected
267 with warnings.catch_warnings(): 273 with warnings.catch_warnings():
storchaka 2016/12/04 11:23:35 Isn't simpler to use assertWarns()?
Nick Coghlan 2016/12/04 13:39:05 The main reason I didn't use that is because I did
268 warnings.simplefilter("error", DeprecationWarning) 274 warnings.simplefilter("error", DeprecationWarning)
269 with self.assertRaises(DeprecationWarning): 275 with self.assertRaises(DeprecationWarning):
270 class WithClassRef(metaclass=Meta): 276 class WithClassRef(metaclass=Meta):
271 def f(self): 277 def f(self):
272 return __class__ 278 return __class__
273 279
274 def test___classcell___overwrite(self): 280 def test___classcell___overwrite(self):
275 # See issue #23722 281 # See issue #23722
276 # Overwriting __classcell__ with nonsense is explicitly prohibited 282 # Overwriting __classcell__ with nonsense is explicitly prohibited
277 class Meta(type): 283 class Meta(type):
(...skipping 13 matching lines...) Expand all
291 class Meta(type): 297 class Meta(type):
292 def __new__(cls, name, bases, namespace): 298 def __new__(cls, name, bases, namespace):
293 cls = super().__new__(cls, name, bases, namespace) 299 cls = super().__new__(cls, name, bases, namespace)
294 B = type("B", (), namespace) 300 B = type("B", (), namespace)
295 return cls 301 return cls
296 302
297 with self.assertRaises(TypeError): 303 with self.assertRaises(TypeError):
298 class A(metaclass=Meta): 304 class A(metaclass=Meta):
299 def f(self): 305 def f(self):
300 return __class__ 306 return __class__
301 307
storchaka 2016/12/04 11:23:35 Is it needed a test for metaclass __new__ returnin
Nick Coghlan 2016/12/04 13:39:05 test__classcell__delayed covers that above, but sh
302 def test_obscure_super_errors(self): 308 def test_obscure_super_errors(self):
303 def f(): 309 def f():
304 super() 310 super()
305 self.assertRaises(RuntimeError, f) 311 self.assertRaises(RuntimeError, f)
306 def f(x): 312 def f(x):
307 del x 313 del x
308 super() 314 super()
309 self.assertRaises(RuntimeError, f, None) 315 self.assertRaises(RuntimeError, f, None)
310 class X: 316 class X:
311 def f(x): 317 def f(x):
(...skipping 20 matching lines...) Expand all
332 # This will be caught by regrtest.py -R if this leak. 338 # This will be caught by regrtest.py -R if this leak.
333 # 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__
334 # is not endorsed. 340 # is not endorsed.
335 sp = super(float, 1.0) 341 sp = super(float, 1.0)
336 for i in range(1000): 342 for i in range(1000):
337 super.__init__(sp, int, i) 343 super.__init__(sp, int, i)
338 344
339 345
340 if __name__ == "__main__": 346 if __name__ == "__main__":
341 unittest.main() 347 unittest.main()
LEFTRIGHT

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