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

Side by Side Diff: Lib/test/test_super.py

Issue 23722: During metaclass.__init__, super() of the constructed class does not work
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:
View unified diff | Download patch
OLDNEW
1 """Unit tests for new super() implementation.""" 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
3 import sys 4 import sys
4 import unittest 5 import unittest
6 import warnings
7 from test.support import check_warnings
5 8
6 9
7 class A: 10 class A:
8 def f(self): 11 def f(self):
9 return 'A' 12 return 'A'
10 @classmethod 13 @classmethod
11 def cm(cls): 14 def cm(cls):
12 return (cls, 'A') 15 return (cls, 'A')
13 16
14 class B(A): 17 class B(A):
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 140
138 def test___class___staticmethod(self): 141 def test___class___staticmethod(self):
139 # See issue #14857 142 # See issue #14857
140 class X: 143 class X:
141 @staticmethod 144 @staticmethod
142 def f(): 145 def f():
143 return __class__ 146 return __class__
144 self.assertIs(X.f(), X) 147 self.assertIs(X.f(), X)
145 148
146 def test___class___new(self): 149 def test___class___new(self):
150 # See issue #23722
151 # Ensure zero-arg super() works as soon as type.__new__() is completed
147 test_class = None 152 test_class = None
148 153
149 class Meta(type): 154 class Meta(type):
150 def __new__(cls, name, bases, namespace): 155 def __new__(cls, name, bases, namespace):
151 nonlocal test_class 156 nonlocal test_class
152 self = super().__new__(cls, name, bases, namespace) 157 self = super().__new__(cls, name, bases, namespace)
153 test_class = self.f() 158 test_class = self.f()
154 return self 159 return self
155 160
156 class A(metaclass=Meta): 161 class A(metaclass=Meta):
157 @staticmethod 162 @staticmethod
158 def f(): 163 def f():
159 return __class__ 164 return __class__
160 165
161 self.assertIs(test_class, A) 166 self.assertIs(test_class, A)
162 167
163 def test___class___delayed(self): 168 def test___class___delayed(self):
169 # See issue #23722
164 test_namespace = None 170 test_namespace = None
165 171
166 class Meta(type): 172 class Meta(type):
167 def __new__(cls, name, bases, namespace): 173 def __new__(cls, name, bases, namespace):
168 nonlocal test_namespace 174 nonlocal test_namespace
169 test_namespace = namespace 175 test_namespace = namespace
170 return None 176 return None
171 177
172 class A(metaclass=Meta): 178 class A(metaclass=Meta):
173 @staticmethod 179 @staticmethod
174 def f(): 180 def f():
175 return __class__ 181 return __class__
176 182
177 self.assertIs(A, None) 183 self.assertIs(A, None)
178 184
179 B = type("B", (), test_namespace) 185 B = type("B", (), test_namespace)
180 self.assertIs(B.f(), B) 186 self.assertIs(B.f(), B)
181 187
182 def test___class___mro(self): 188 def test___class___mro(self):
189 # See issue #23722
183 test_class = None 190 test_class = None
184 191
185 class Meta(type): 192 class Meta(type):
186 def mro(self): 193 def mro(self):
187 # self.f() doesn't work yet... 194 # self.f() doesn't work yet...
188 self.__dict__["f"]() 195 self.__dict__["f"]()
189 return super().mro() 196 return super().mro()
190 197
191 class A(metaclass=Meta): 198 class A(metaclass=Meta):
192 def f(): 199 def f():
193 nonlocal test_class 200 nonlocal test_class
194 test_class = __class__ 201 test_class = __class__
195 202
196 self.assertIs(test_class, A) 203 self.assertIs(test_class, A)
197 204
198 def test___classcell___deleted(self): 205 def test___classcell___expected_behaviour(self):
206 # See issue #23722
207 namespace_snapshot = None
199 class Meta(type): 208 class Meta(type):
200 def __new__(cls, name, bases, namespace): 209 def __new__(cls, name, bases, namespace):
201 del namespace['__classcell__'] 210 nonlocal namespace_snapshot
211 namespace_snapshot = namespace.copy()
202 return super().__new__(cls, name, bases, namespace) 212 return super().__new__(cls, name, bases, namespace)
203 213
204 class A(metaclass=Meta): 214 # __classcell__ is injected into the class namespace by the compiler
205 @staticmethod 215 # when at least one method needs it, and should be omitted otherwise
206 def f(): 216 class WithoutClassRef(metaclass=Meta):
207 __class__ 217 pass
218 self.assertNotIn("__classcell__", namespace_snapshot)
208 219
209 with self.assertRaises(NameError): 220 # With zero-arg super() or an explicit __class__ reference,
210 A.f() 221 # __classcell__ is the exact cell reference to be populated by
222 # type.__new__
223 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):
225 return __class__
211 226
212 def test___classcell___reset(self): 227 class_cell = namespace_snapshot["__classcell__"]
228 method_closure = WithClassRef.f.__closure__
229 self.assertEqual(len(method_closure), 1)
230 self.assertIs(class_cell, method_closure[0])
231 # Ensure the cell reference *doesn't* get turned into an attribute
232 with self.assertRaises(AttributeError):
233 WithClassRef.__classcell__
234
235 def test___classcell___missing(self):
236 # See issue #23722
237 # Some metaclasses may not pass the original namespace to type.__new__
238 # We test that case here by forcibly deleting __classcell__
213 class Meta(type): 239 class Meta(type):
214 def __new__(cls, name, bases, namespace): 240 def __new__(cls, name, bases, namespace):
215 namespace['__classcell__'] = 0 241 namespace.pop('__classcell__', None)
216 return super().__new__(cls, name, bases, namespace) 242 return super().__new__(cls, name, bases, namespace)
217 243
218 class A(metaclass=Meta): 244 # The default case should continue to work without any warnings
219 @staticmethod 245 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.
220 def f(): 246 class WithoutClassRef(metaclass=Meta):
221 __class__ 247 pass
248 self.assertEqual(len(w.warnings), 0)
storchaka 2016/12/04 11:23:35 Better: self.assertEqual(w.warnings, []) Thi
Nick Coghlan 2016/12/04 13:39:05 Done.
222 249
223 with self.assertRaises(NameError): 250 # With zero-arg super() or an explicit __class__ reference, we expect
224 A.f() 251 # __build_class__ to emit a DeprecationWarning complaining that
225 self.assertEqual(A.__classcell__, 0) 252 # __class__ was not set, and asking if __classcell__ was propagated
253 # to type.__new__.
254 # In Python 3.7, that warning will become a RuntimeError.
255 expected_warning = (
256 '__class__ not set.*__classcell__ propagated',
257 DeprecationWarning
258 )
259 with check_warnings(expected_warning):
storchaka 2016/12/04 11:23:35 Same as above.
260 class WithClassRef(metaclass=Meta):
261 def f(self):
262 return __class__
263 # Check __class__ still gets set despite the warning
264 self.assertIs(WithClassRef().f(), WithClassRef)
265
266 # Check the warning is turned into an error as expected
267 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)
269 with self.assertRaises(DeprecationWarning):
270 class WithClassRef(metaclass=Meta):
271 def f(self):
272 return __class__
273
274 def test___classcell___overwrite(self):
275 # See issue #23722
276 # Overwriting __classcell__ with nonsense is explicitly prohibited
277 class Meta(type):
278 def __new__(cls, name, bases, namespace, cell):
279 namespace['__classcell__'] = cell
280 return super().__new__(cls, name, bases, namespace)
281
282 for bad_cell in (None, 0, "", object()):
283 with self.subTest(bad_cell=bad_cell):
284 with self.assertRaises(TypeError):
285 class A(metaclass=Meta, cell=bad_cell):
286 pass
287
288 def test___classcell___wrong_cell(self):
289 # See issue #23722
290 # Pointing the cell reference at the wrong class is also prohibited
291 class Meta(type):
292 def __new__(cls, name, bases, namespace):
293 cls = super().__new__(cls, name, bases, namespace)
294 B = type("B", (), namespace)
295 return cls
296
297 with self.assertRaises(TypeError):
298 class A(metaclass=Meta):
299 def f(self):
300 return __class__
226 301
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
227 def test_obscure_super_errors(self): 302 def test_obscure_super_errors(self):
228 def f(): 303 def f():
229 super() 304 super()
230 self.assertRaises(RuntimeError, f) 305 self.assertRaises(RuntimeError, f)
231 def f(x): 306 def f(x):
232 del x 307 del x
233 super() 308 super()
234 self.assertRaises(RuntimeError, f, None) 309 self.assertRaises(RuntimeError, f, None)
235 class X: 310 class X:
236 def f(x): 311 def f(x):
(...skipping 20 matching lines...) Expand all
257 # This will be caught by regrtest.py -R if this leak. 332 # 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__ 333 # NOTE: Despite the use in the test a direct call of super.__init__
259 # is not endorsed. 334 # is not endorsed.
260 sp = super(float, 1.0) 335 sp = super(float, 1.0)
261 for i in range(1000): 336 for i in range(1000):
262 super.__init__(sp, int, i) 337 super.__init__(sp, int, i)
263 338
264 339
265 if __name__ == "__main__": 340 if __name__ == "__main__":
266 unittest.main() 341 unittest.main()
OLDNEW
« no previous file with comments | « Lib/importlib/_bootstrap_external.py ('k') | Objects/typeobject.c » ('j') | Objects/typeobject.c » ('J')

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