blob: 3c331bb98fc9368f7d95a1198102a1fd8b7c9b17 [file] [log] [blame]
Nick Coghland78448e2016-07-30 16:26:03 +10001import sys
2import types
Berker Peksag01d17192016-07-30 14:06:15 +03003import unittest
Nick Coghland78448e2016-07-30 16:26:03 +10004
5
Berker Peksag01d17192016-07-30 14:06:15 +03006class Test(unittest.TestCase):
Nick Coghland78448e2016-07-30 16:26:03 +10007 def test_init_subclass(self):
Berker Peksag01d17192016-07-30 14:06:15 +03008 class A:
Nick Coghland78448e2016-07-30 16:26:03 +10009 initialized = False
10
11 def __init_subclass__(cls):
12 super().__init_subclass__()
13 cls.initialized = True
14
15 class B(A):
16 pass
17
18 self.assertFalse(A.initialized)
19 self.assertTrue(B.initialized)
20
21 def test_init_subclass_dict(self):
Berker Peksag01d17192016-07-30 14:06:15 +030022 class A(dict):
Nick Coghland78448e2016-07-30 16:26:03 +100023 initialized = False
24
25 def __init_subclass__(cls):
26 super().__init_subclass__()
27 cls.initialized = True
28
29 class B(A):
30 pass
31
32 self.assertFalse(A.initialized)
33 self.assertTrue(B.initialized)
34
35 def test_init_subclass_kwargs(self):
Berker Peksag01d17192016-07-30 14:06:15 +030036 class A:
Nick Coghland78448e2016-07-30 16:26:03 +100037 def __init_subclass__(cls, **kwargs):
38 cls.kwargs = kwargs
39
40 class B(A, x=3):
41 pass
42
43 self.assertEqual(B.kwargs, dict(x=3))
44
45 def test_init_subclass_error(self):
Berker Peksag01d17192016-07-30 14:06:15 +030046 class A:
Nick Coghland78448e2016-07-30 16:26:03 +100047 def __init_subclass__(cls):
48 raise RuntimeError
49
50 with self.assertRaises(RuntimeError):
51 class B(A):
52 pass
53
54 def test_init_subclass_wrong(self):
Berker Peksag01d17192016-07-30 14:06:15 +030055 class A:
Nick Coghland78448e2016-07-30 16:26:03 +100056 def __init_subclass__(cls, whatever):
57 pass
58
59 with self.assertRaises(TypeError):
60 class B(A):
61 pass
62
63 def test_init_subclass_skipped(self):
Berker Peksag01d17192016-07-30 14:06:15 +030064 class BaseWithInit:
Nick Coghland78448e2016-07-30 16:26:03 +100065 def __init_subclass__(cls, **kwargs):
66 super().__init_subclass__(**kwargs)
67 cls.initialized = cls
68
69 class BaseWithoutInit(BaseWithInit):
70 pass
71
72 class A(BaseWithoutInit):
73 pass
74
75 self.assertIs(A.initialized, A)
76 self.assertIs(BaseWithoutInit.initialized, BaseWithoutInit)
77
78 def test_init_subclass_diamond(self):
Berker Peksag01d17192016-07-30 14:06:15 +030079 class Base:
Nick Coghland78448e2016-07-30 16:26:03 +100080 def __init_subclass__(cls, **kwargs):
81 super().__init_subclass__(**kwargs)
82 cls.calls = []
83
84 class Left(Base):
85 pass
86
Berker Peksag01d17192016-07-30 14:06:15 +030087 class Middle:
Nick Coghland78448e2016-07-30 16:26:03 +100088 def __init_subclass__(cls, middle, **kwargs):
89 super().__init_subclass__(**kwargs)
90 cls.calls += [middle]
91
92 class Right(Base):
93 def __init_subclass__(cls, right="right", **kwargs):
94 super().__init_subclass__(**kwargs)
95 cls.calls += [right]
96
97 class A(Left, Middle, Right, middle="middle"):
98 pass
99
100 self.assertEqual(A.calls, ["right", "middle"])
101 self.assertEqual(Left.calls, [])
102 self.assertEqual(Right.calls, [])
103
104 def test_set_name(self):
105 class Descriptor:
106 def __set_name__(self, owner, name):
107 self.owner = owner
108 self.name = name
109
Berker Peksag01d17192016-07-30 14:06:15 +0300110 class A:
Nick Coghland78448e2016-07-30 16:26:03 +1000111 d = Descriptor()
112
113 self.assertEqual(A.d.name, "d")
114 self.assertIs(A.d.owner, A)
115
116 def test_set_name_metaclass(self):
117 class Meta(type):
118 def __new__(cls, name, bases, ns):
119 ret = super().__new__(cls, name, bases, ns)
120 self.assertEqual(ret.d.name, "d")
121 self.assertIs(ret.d.owner, ret)
122 return 0
123
Berker Peksag01d17192016-07-30 14:06:15 +0300124 class Descriptor:
Nick Coghland78448e2016-07-30 16:26:03 +1000125 def __set_name__(self, owner, name):
126 self.owner = owner
127 self.name = name
128
Berker Peksag01d17192016-07-30 14:06:15 +0300129 class A(metaclass=Meta):
Nick Coghland78448e2016-07-30 16:26:03 +1000130 d = Descriptor()
131 self.assertEqual(A, 0)
132
133 def test_set_name_error(self):
134 class Descriptor:
135 def __set_name__(self, owner, name):
Serhiy Storchakad5d32d22016-10-21 17:13:31 +0300136 1/0
Nick Coghland78448e2016-07-30 16:26:03 +1000137
Serhiy Storchakad5d32d22016-10-21 17:13:31 +0300138 with self.assertRaises(RuntimeError) as cm:
139 class NotGoingToWork:
140 attr = Descriptor()
141
142 exc = cm.exception
143 self.assertRegex(str(exc), r'\bNotGoingToWork\b')
144 self.assertRegex(str(exc), r'\battr\b')
145 self.assertRegex(str(exc), r'\bDescriptor\b')
146 self.assertIsInstance(exc.__cause__, ZeroDivisionError)
Nick Coghland78448e2016-07-30 16:26:03 +1000147
148 def test_set_name_wrong(self):
149 class Descriptor:
150 def __set_name__(self):
151 pass
152
Serhiy Storchakad5d32d22016-10-21 17:13:31 +0300153 with self.assertRaises(RuntimeError) as cm:
154 class NotGoingToWork:
155 attr = Descriptor()
156
157 exc = cm.exception
158 self.assertRegex(str(exc), r'\bNotGoingToWork\b')
159 self.assertRegex(str(exc), r'\battr\b')
160 self.assertRegex(str(exc), r'\bDescriptor\b')
161 self.assertIsInstance(exc.__cause__, TypeError)
Nick Coghland78448e2016-07-30 16:26:03 +1000162
Serhiy Storchakaafd02a42016-09-21 15:54:59 +0300163 def test_set_name_lookup(self):
164 resolved = []
165 class NonDescriptor:
166 def __getattr__(self, name):
167 resolved.append(name)
168
169 class A:
170 d = NonDescriptor()
171
172 self.assertNotIn('__set_name__', resolved,
173 '__set_name__ is looked up in instance dict')
174
Nick Coghland78448e2016-07-30 16:26:03 +1000175 def test_set_name_init_subclass(self):
176 class Descriptor:
177 def __set_name__(self, owner, name):
178 self.owner = owner
179 self.name = name
180
181 class Meta(type):
182 def __new__(cls, name, bases, ns):
183 self = super().__new__(cls, name, bases, ns)
184 self.meta_owner = self.owner
185 self.meta_name = self.name
186 return self
187
Berker Peksag01d17192016-07-30 14:06:15 +0300188 class A:
Nick Coghland78448e2016-07-30 16:26:03 +1000189 def __init_subclass__(cls):
190 cls.owner = cls.d.owner
191 cls.name = cls.d.name
192
193 class B(A, metaclass=Meta):
194 d = Descriptor()
195
196 self.assertIs(B.owner, B)
197 self.assertEqual(B.name, 'd')
198 self.assertIs(B.meta_owner, B)
199 self.assertEqual(B.name, 'd')
200
Serhiy Storchaka9ec07722016-11-29 09:54:17 +0200201 def test_set_name_modifying_dict(self):
202 notified = []
203 class Descriptor:
204 def __set_name__(self, owner, name):
205 setattr(owner, name + 'x', None)
206 notified.append(name)
207
208 class A:
209 a = Descriptor()
210 b = Descriptor()
211 c = Descriptor()
212 d = Descriptor()
213 e = Descriptor()
214
215 self.assertCountEqual(notified, ['a', 'b', 'c', 'd', 'e'])
216
Nick Coghland78448e2016-07-30 16:26:03 +1000217 def test_errors(self):
218 class MyMeta(type):
219 pass
220
221 with self.assertRaises(TypeError):
Berker Peksag01d17192016-07-30 14:06:15 +0300222 class MyClass(metaclass=MyMeta, otherarg=1):
Nick Coghland78448e2016-07-30 16:26:03 +1000223 pass
224
225 with self.assertRaises(TypeError):
226 types.new_class("MyClass", (object,),
227 dict(metaclass=MyMeta, otherarg=1))
228 types.prepare_class("MyClass", (object,),
229 dict(metaclass=MyMeta, otherarg=1))
230
231 class MyMeta(type):
232 def __init__(self, name, bases, namespace, otherarg):
233 super().__init__(name, bases, namespace)
234
235 with self.assertRaises(TypeError):
Berker Peksag01d17192016-07-30 14:06:15 +0300236 class MyClass(metaclass=MyMeta, otherarg=1):
Nick Coghland78448e2016-07-30 16:26:03 +1000237 pass
238
239 class MyMeta(type):
240 def __new__(cls, name, bases, namespace, otherarg):
241 return super().__new__(cls, name, bases, namespace)
242
243 def __init__(self, name, bases, namespace, otherarg):
244 super().__init__(name, bases, namespace)
245 self.otherarg = otherarg
246
Berker Peksag01d17192016-07-30 14:06:15 +0300247 class MyClass(metaclass=MyMeta, otherarg=1):
Nick Coghland78448e2016-07-30 16:26:03 +1000248 pass
249
250 self.assertEqual(MyClass.otherarg, 1)
251
252 def test_errors_changed_pep487(self):
253 # These tests failed before Python 3.6, PEP 487
254 class MyMeta(type):
255 def __new__(cls, name, bases, namespace):
256 return super().__new__(cls, name=name, bases=bases,
257 dict=namespace)
258
259 with self.assertRaises(TypeError):
Berker Peksag01d17192016-07-30 14:06:15 +0300260 class MyClass(metaclass=MyMeta):
Nick Coghland78448e2016-07-30 16:26:03 +1000261 pass
262
263 class MyMeta(type):
264 def __new__(cls, name, bases, namespace, otherarg):
265 self = super().__new__(cls, name, bases, namespace)
266 self.otherarg = otherarg
267 return self
268
Berker Peksag01d17192016-07-30 14:06:15 +0300269 class MyClass(metaclass=MyMeta, otherarg=1):
Nick Coghland78448e2016-07-30 16:26:03 +1000270 pass
271
272 self.assertEqual(MyClass.otherarg, 1)
273
274 def test_type(self):
275 t = type('NewClass', (object,), {})
276 self.assertIsInstance(t, type)
277 self.assertEqual(t.__name__, 'NewClass')
278
279 with self.assertRaises(TypeError):
280 type(name='NewClass', bases=(object,), dict={})
281
282
283if __name__ == "__main__":
Berker Peksag01d17192016-07-30 14:06:15 +0300284 unittest.main()