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

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:
Right: Side by side diff | Download
LEFTRIGHT
(no file at all)
1 """Unit tests for new super() implementation.""" 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
6 from test.support import check_warnings
5 7
6 8
7 class A: 9 class A:
8 def f(self): 10 def f(self):
9 return 'A' 11 return 'A'
10 @classmethod 12 @classmethod
11 def cm(cls): 13 def cm(cls):
12 return (cls, 'A') 14 return (cls, 'A')
13 15
14 class B(A): 16 class B(A):
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 139
138 def test___class___staticmethod(self): 140 def test___class___staticmethod(self):
139 # See issue #14857 141 # See issue #14857
140 class X: 142 class X:
141 @staticmethod 143 @staticmethod
142 def f(): 144 def f():
143 return __class__ 145 return __class__
144 self.assertIs(X.f(), X) 146 self.assertIs(X.f(), X)
145 147
146 def test___class___new(self): 148 def test___class___new(self):
149 # See issue #23722
150 # Ensure zero-arg super() works as soon as type.__new__() is completed
147 test_class = None 151 test_class = None
148 152
149 class Meta(type): 153 class Meta(type):
150 def __new__(cls, name, bases, namespace): 154 def __new__(cls, name, bases, namespace):
151 nonlocal test_class 155 nonlocal test_class
152 self = super().__new__(cls, name, bases, namespace) 156 self = super().__new__(cls, name, bases, namespace)
153 test_class = self.f() 157 test_class = self.f()
154 return self 158 return self
155 159
156 class A(metaclass=Meta): 160 class A(metaclass=Meta):
157 @staticmethod 161 @staticmethod
158 def f(): 162 def f():
159 return __class__ 163 return __class__
160 164
161 self.assertIs(test_class, A) 165 self.assertIs(test_class, A)
162 166
163 def test___class___delayed(self): 167 def test___class___delayed(self):
168 # See issue #23722
164 test_namespace = None 169 test_namespace = None
165 170
166 class Meta(type): 171 class Meta(type):
167 def __new__(cls, name, bases, namespace): 172 def __new__(cls, name, bases, namespace):
168 nonlocal test_namespace 173 nonlocal test_namespace
169 test_namespace = namespace 174 test_namespace = namespace
170 return None 175 return None
171 176
172 class A(metaclass=Meta): 177 # This case shouldn't trigger the __classcell__ deprecation warning
173 @staticmethod 178 with check_warnings() as w:
174 def f(): 179 warnings.simplefilter("always", DeprecationWarning)
175 return __class__ 180 class A(metaclass=Meta):
181 @staticmethod
182 def f():
183 return __class__
184 self.assertEqual(w.warnings, [])
176 185
177 self.assertIs(A, None) 186 self.assertIs(A, None)
178 187
179 B = type("B", (), test_namespace) 188 B = type("B", (), test_namespace)
180 self.assertIs(B.f(), B) 189 self.assertIs(B.f(), B)
181 190
182 def test___class___mro(self): 191 def test___class___mro(self):
192 # See issue #23722
183 test_class = None 193 test_class = None
184 194
185 class Meta(type): 195 class Meta(type):
186 def mro(self): 196 def mro(self):
187 # self.f() doesn't work yet... 197 # self.f() doesn't work yet...
188 self.__dict__["f"]() 198 self.__dict__["f"]()
189 return super().mro() 199 return super().mro()
190 200
191 class A(metaclass=Meta): 201 class A(metaclass=Meta):
192 def f(): 202 def f():
193 nonlocal test_class 203 nonlocal test_class
194 test_class = __class__ 204 test_class = __class__
195 205
196 self.assertIs(test_class, A) 206 self.assertIs(test_class, A)
197 207
198 def test___classcell___deleted(self): 208 def test___classcell___expected_behaviour(self):
199 class Meta(type): 209 # See issue #23722
200 def __new__(cls, name, bases, namespace): 210 class Meta(type):
201 del namespace['__classcell__'] 211 def __new__(cls, name, bases, namespace):
212 nonlocal namespace_snapshot
213 namespace_snapshot = namespace.copy()
202 return super().__new__(cls, name, bases, namespace) 214 return super().__new__(cls, name, bases, namespace)
203 215
204 class A(metaclass=Meta): 216 # __classcell__ is injected into the class namespace by the compiler
205 @staticmethod 217 # when at least one method needs it, and should be omitted otherwise
206 def f(): 218 namespace_snapshot = None
207 __class__ 219 class WithoutClassRef(metaclass=Meta):
208 220 pass
209 with self.assertRaises(NameError): 221 self.assertNotIn("__classcell__", namespace_snapshot)
210 A.f() 222
211 223 # With zero-arg super() or an explicit __class__ reference,
212 def test___classcell___reset(self): 224 # __classcell__ is the exact cell reference to be populated by
213 class Meta(type): 225 # type.__new__
214 def __new__(cls, name, bases, namespace): 226 namespace_snapshot = None
215 namespace['__classcell__'] = 0 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)
216 return super().__new__(cls, name, bases, namespace) 246 return super().__new__(cls, name, bases, namespace)
217 247
218 class A(metaclass=Meta): 248 # The default case should continue to work without any warnings
219 @staticmethod 249 with check_warnings() as w:
220 def f(): 250 warnings.simplefilter("always", DeprecationWarning)
221 __class__ 251 class WithoutClassRef(metaclass=Meta):
222 252 pass
223 with self.assertRaises(NameError): 253 self.assertEqual(w.warnings, [])
224 A.f() 254
225 self.assertEqual(A.__classcell__, 0) 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__
226 307
227 def test_obscure_super_errors(self): 308 def test_obscure_super_errors(self):
228 def f(): 309 def f():
229 super() 310 super()
230 self.assertRaises(RuntimeError, f) 311 self.assertRaises(RuntimeError, f)
231 def f(x): 312 def f(x):
232 del x 313 del x
233 super() 314 super()
234 self.assertRaises(RuntimeError, f, None) 315 self.assertRaises(RuntimeError, f, None)
235 class X: 316 class X:
(...skipping 21 matching lines...) Expand all
257 # This will be caught by regrtest.py -R if this leak. 338 # This will be caught by regrtest.py -R if this leak.
258 # 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__
259 # is not endorsed. 340 # is not endorsed.
260 sp = super(float, 1.0) 341 sp = super(float, 1.0)
261 for i in range(1000): 342 for i in range(1000):
262 super.__init__(sp, int, i) 343 super.__init__(sp, int, i)
263 344
264 345
265 if __name__ == "__main__": 346 if __name__ == "__main__":
266 unittest.main() 347 unittest.main()
LEFTRIGHT

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