1 import types
2 import unittest
3
4
5 class ESC[4;38;5;81mTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
6 def test_init_subclass(self):
7 class ESC[4;38;5;81mA:
8 initialized = False
9
10 def __init_subclass__(cls):
11 super().__init_subclass__()
12 cls.initialized = True
13
14 class ESC[4;38;5;81mB(ESC[4;38;5;149mA):
15 pass
16
17 self.assertFalse(A.initialized)
18 self.assertTrue(B.initialized)
19
20 def test_init_subclass_dict(self):
21 class ESC[4;38;5;81mA(ESC[4;38;5;149mdict):
22 initialized = False
23
24 def __init_subclass__(cls):
25 super().__init_subclass__()
26 cls.initialized = True
27
28 class ESC[4;38;5;81mB(ESC[4;38;5;149mA):
29 pass
30
31 self.assertFalse(A.initialized)
32 self.assertTrue(B.initialized)
33
34 def test_init_subclass_kwargs(self):
35 class ESC[4;38;5;81mA:
36 def __init_subclass__(cls, **kwargs):
37 cls.kwargs = kwargs
38
39 class ESC[4;38;5;81mB(ESC[4;38;5;149mA, x=3):
40 pass
41
42 self.assertEqual(B.kwargs, dict(x=3))
43
44 def test_init_subclass_error(self):
45 class ESC[4;38;5;81mA:
46 def __init_subclass__(cls):
47 raise RuntimeError
48
49 with self.assertRaises(RuntimeError):
50 class ESC[4;38;5;81mB(ESC[4;38;5;149mA):
51 pass
52
53 def test_init_subclass_wrong(self):
54 class ESC[4;38;5;81mA:
55 def __init_subclass__(cls, whatever):
56 pass
57
58 with self.assertRaises(TypeError):
59 class ESC[4;38;5;81mB(ESC[4;38;5;149mA):
60 pass
61
62 def test_init_subclass_skipped(self):
63 class ESC[4;38;5;81mBaseWithInit:
64 def __init_subclass__(cls, **kwargs):
65 super().__init_subclass__(**kwargs)
66 cls.initialized = cls
67
68 class ESC[4;38;5;81mBaseWithoutInit(ESC[4;38;5;149mBaseWithInit):
69 pass
70
71 class ESC[4;38;5;81mA(ESC[4;38;5;149mBaseWithoutInit):
72 pass
73
74 self.assertIs(A.initialized, A)
75 self.assertIs(BaseWithoutInit.initialized, BaseWithoutInit)
76
77 def test_init_subclass_diamond(self):
78 class ESC[4;38;5;81mBase:
79 def __init_subclass__(cls, **kwargs):
80 super().__init_subclass__(**kwargs)
81 cls.calls = []
82
83 class ESC[4;38;5;81mLeft(ESC[4;38;5;149mBase):
84 pass
85
86 class ESC[4;38;5;81mMiddle:
87 def __init_subclass__(cls, middle, **kwargs):
88 super().__init_subclass__(**kwargs)
89 cls.calls += [middle]
90
91 class ESC[4;38;5;81mRight(ESC[4;38;5;149mBase):
92 def __init_subclass__(cls, right="right", **kwargs):
93 super().__init_subclass__(**kwargs)
94 cls.calls += [right]
95
96 class ESC[4;38;5;81mA(ESC[4;38;5;149mLeft, ESC[4;38;5;149mMiddle, ESC[4;38;5;149mRight, middle="middle"):
97 pass
98
99 self.assertEqual(A.calls, ["right", "middle"])
100 self.assertEqual(Left.calls, [])
101 self.assertEqual(Right.calls, [])
102
103 def test_set_name(self):
104 class ESC[4;38;5;81mDescriptor:
105 def __set_name__(self, owner, name):
106 self.owner = owner
107 self.name = name
108
109 class ESC[4;38;5;81mA:
110 d = Descriptor()
111
112 self.assertEqual(A.d.name, "d")
113 self.assertIs(A.d.owner, A)
114
115 def test_set_name_metaclass(self):
116 class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
117 def __new__(cls, name, bases, ns):
118 ret = super().__new__(cls, name, bases, ns)
119 self.assertEqual(ret.d.name, "d")
120 self.assertIs(ret.d.owner, ret)
121 return 0
122
123 class ESC[4;38;5;81mDescriptor:
124 def __set_name__(self, owner, name):
125 self.owner = owner
126 self.name = name
127
128 class ESC[4;38;5;81mA(metaclass=ESC[4;38;5;149mMeta):
129 d = Descriptor()
130 self.assertEqual(A, 0)
131
132 def test_set_name_error(self):
133 class ESC[4;38;5;81mDescriptor:
134 def __set_name__(self, owner, name):
135 1/0
136
137 with self.assertRaises(ZeroDivisionError) as cm:
138 class ESC[4;38;5;81mNotGoingToWork:
139 attr = Descriptor()
140
141 notes = cm.exception.__notes__
142 self.assertRegex(str(notes), r'\bNotGoingToWork\b')
143 self.assertRegex(str(notes), r'\battr\b')
144 self.assertRegex(str(notes), r'\bDescriptor\b')
145
146 def test_set_name_wrong(self):
147 class ESC[4;38;5;81mDescriptor:
148 def __set_name__(self):
149 pass
150
151 with self.assertRaises(TypeError) as cm:
152 class ESC[4;38;5;81mNotGoingToWork:
153 attr = Descriptor()
154
155 notes = cm.exception.__notes__
156 self.assertRegex(str(notes), r'\bNotGoingToWork\b')
157 self.assertRegex(str(notes), r'\battr\b')
158 self.assertRegex(str(notes), r'\bDescriptor\b')
159
160 def test_set_name_lookup(self):
161 resolved = []
162 class ESC[4;38;5;81mNonDescriptor:
163 def __getattr__(self, name):
164 resolved.append(name)
165
166 class ESC[4;38;5;81mA:
167 d = NonDescriptor()
168
169 self.assertNotIn('__set_name__', resolved,
170 '__set_name__ is looked up in instance dict')
171
172 def test_set_name_init_subclass(self):
173 class ESC[4;38;5;81mDescriptor:
174 def __set_name__(self, owner, name):
175 self.owner = owner
176 self.name = name
177
178 class ESC[4;38;5;81mMeta(ESC[4;38;5;149mtype):
179 def __new__(cls, name, bases, ns):
180 self = super().__new__(cls, name, bases, ns)
181 self.meta_owner = self.owner
182 self.meta_name = self.name
183 return self
184
185 class ESC[4;38;5;81mA:
186 def __init_subclass__(cls):
187 cls.owner = cls.d.owner
188 cls.name = cls.d.name
189
190 class ESC[4;38;5;81mB(ESC[4;38;5;149mA, metaclass=ESC[4;38;5;149mMeta):
191 d = Descriptor()
192
193 self.assertIs(B.owner, B)
194 self.assertEqual(B.name, 'd')
195 self.assertIs(B.meta_owner, B)
196 self.assertEqual(B.name, 'd')
197
198 def test_set_name_modifying_dict(self):
199 notified = []
200 class ESC[4;38;5;81mDescriptor:
201 def __set_name__(self, owner, name):
202 setattr(owner, name + 'x', None)
203 notified.append(name)
204
205 class ESC[4;38;5;81mA:
206 a = Descriptor()
207 b = Descriptor()
208 c = Descriptor()
209 d = Descriptor()
210 e = Descriptor()
211
212 self.assertCountEqual(notified, ['a', 'b', 'c', 'd', 'e'])
213
214 def test_errors(self):
215 class ESC[4;38;5;81mMyMeta(ESC[4;38;5;149mtype):
216 pass
217
218 with self.assertRaises(TypeError):
219 class ESC[4;38;5;81mMyClass(metaclass=ESC[4;38;5;149mMyMeta, otherarg=1):
220 pass
221
222 with self.assertRaises(TypeError):
223 types.new_class("MyClass", (object,),
224 dict(metaclass=MyMeta, otherarg=1))
225 types.prepare_class("MyClass", (object,),
226 dict(metaclass=MyMeta, otherarg=1))
227
228 class ESC[4;38;5;81mMyMeta(ESC[4;38;5;149mtype):
229 def __init__(self, name, bases, namespace, otherarg):
230 super().__init__(name, bases, namespace)
231
232 with self.assertRaises(TypeError):
233 class ESC[4;38;5;81mMyClass(metaclass=ESC[4;38;5;149mMyMeta, otherarg=1):
234 pass
235
236 class ESC[4;38;5;81mMyMeta(ESC[4;38;5;149mtype):
237 def __new__(cls, name, bases, namespace, otherarg):
238 return super().__new__(cls, name, bases, namespace)
239
240 def __init__(self, name, bases, namespace, otherarg):
241 super().__init__(name, bases, namespace)
242 self.otherarg = otherarg
243
244 class ESC[4;38;5;81mMyClass(metaclass=ESC[4;38;5;149mMyMeta, otherarg=1):
245 pass
246
247 self.assertEqual(MyClass.otherarg, 1)
248
249 def test_errors_changed_pep487(self):
250 # These tests failed before Python 3.6, PEP 487
251 class ESC[4;38;5;81mMyMeta(ESC[4;38;5;149mtype):
252 def __new__(cls, name, bases, namespace):
253 return super().__new__(cls, name=name, bases=bases,
254 dict=namespace)
255
256 with self.assertRaises(TypeError):
257 class ESC[4;38;5;81mMyClass(metaclass=ESC[4;38;5;149mMyMeta):
258 pass
259
260 class ESC[4;38;5;81mMyMeta(ESC[4;38;5;149mtype):
261 def __new__(cls, name, bases, namespace, otherarg):
262 self = super().__new__(cls, name, bases, namespace)
263 self.otherarg = otherarg
264 return self
265
266 class ESC[4;38;5;81mMyClass(metaclass=ESC[4;38;5;149mMyMeta, otherarg=1):
267 pass
268
269 self.assertEqual(MyClass.otherarg, 1)
270
271 def test_type(self):
272 t = type('NewClass', (object,), {})
273 self.assertIsInstance(t, type)
274 self.assertEqual(t.__name__, 'NewClass')
275
276 with self.assertRaises(TypeError):
277 type(name='NewClass', bases=(object,), dict={})
278
279
280 if __name__ == "__main__":
281 unittest.main()