blob: 0267e417177536ee2ad038a1b1debd50f745059a [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):
136 raise RuntimeError
137
138 with self.assertRaises(RuntimeError):
Berker Peksag01d17192016-07-30 14:06:15 +0300139 class A:
Nick Coghland78448e2016-07-30 16:26:03 +1000140 d = Descriptor()
141
142 def test_set_name_wrong(self):
143 class Descriptor:
144 def __set_name__(self):
145 pass
146
147 with self.assertRaises(TypeError):
Berker Peksag01d17192016-07-30 14:06:15 +0300148 class A:
Nick Coghland78448e2016-07-30 16:26:03 +1000149 d = Descriptor()
150
Serhiy Storchakaafd02a42016-09-21 15:54:59 +0300151 def test_set_name_lookup(self):
152 resolved = []
153 class NonDescriptor:
154 def __getattr__(self, name):
155 resolved.append(name)
156
157 class A:
158 d = NonDescriptor()
159
160 self.assertNotIn('__set_name__', resolved,
161 '__set_name__ is looked up in instance dict')
162
Nick Coghland78448e2016-07-30 16:26:03 +1000163 def test_set_name_init_subclass(self):
164 class Descriptor:
165 def __set_name__(self, owner, name):
166 self.owner = owner
167 self.name = name
168
169 class Meta(type):
170 def __new__(cls, name, bases, ns):
171 self = super().__new__(cls, name, bases, ns)
172 self.meta_owner = self.owner
173 self.meta_name = self.name
174 return self
175
Berker Peksag01d17192016-07-30 14:06:15 +0300176 class A:
Nick Coghland78448e2016-07-30 16:26:03 +1000177 def __init_subclass__(cls):
178 cls.owner = cls.d.owner
179 cls.name = cls.d.name
180
181 class B(A, metaclass=Meta):
182 d = Descriptor()
183
184 self.assertIs(B.owner, B)
185 self.assertEqual(B.name, 'd')
186 self.assertIs(B.meta_owner, B)
187 self.assertEqual(B.name, 'd')
188
189 def test_errors(self):
190 class MyMeta(type):
191 pass
192
193 with self.assertRaises(TypeError):
Berker Peksag01d17192016-07-30 14:06:15 +0300194 class MyClass(metaclass=MyMeta, otherarg=1):
Nick Coghland78448e2016-07-30 16:26:03 +1000195 pass
196
197 with self.assertRaises(TypeError):
198 types.new_class("MyClass", (object,),
199 dict(metaclass=MyMeta, otherarg=1))
200 types.prepare_class("MyClass", (object,),
201 dict(metaclass=MyMeta, otherarg=1))
202
203 class MyMeta(type):
204 def __init__(self, name, bases, namespace, otherarg):
205 super().__init__(name, bases, namespace)
206
207 with self.assertRaises(TypeError):
Berker Peksag01d17192016-07-30 14:06:15 +0300208 class MyClass(metaclass=MyMeta, otherarg=1):
Nick Coghland78448e2016-07-30 16:26:03 +1000209 pass
210
211 class MyMeta(type):
212 def __new__(cls, name, bases, namespace, otherarg):
213 return super().__new__(cls, name, bases, namespace)
214
215 def __init__(self, name, bases, namespace, otherarg):
216 super().__init__(name, bases, namespace)
217 self.otherarg = otherarg
218
Berker Peksag01d17192016-07-30 14:06:15 +0300219 class MyClass(metaclass=MyMeta, otherarg=1):
Nick Coghland78448e2016-07-30 16:26:03 +1000220 pass
221
222 self.assertEqual(MyClass.otherarg, 1)
223
224 def test_errors_changed_pep487(self):
225 # These tests failed before Python 3.6, PEP 487
226 class MyMeta(type):
227 def __new__(cls, name, bases, namespace):
228 return super().__new__(cls, name=name, bases=bases,
229 dict=namespace)
230
231 with self.assertRaises(TypeError):
Berker Peksag01d17192016-07-30 14:06:15 +0300232 class MyClass(metaclass=MyMeta):
Nick Coghland78448e2016-07-30 16:26:03 +1000233 pass
234
235 class MyMeta(type):
236 def __new__(cls, name, bases, namespace, otherarg):
237 self = super().__new__(cls, name, bases, namespace)
238 self.otherarg = otherarg
239 return self
240
Berker Peksag01d17192016-07-30 14:06:15 +0300241 class MyClass(metaclass=MyMeta, otherarg=1):
Nick Coghland78448e2016-07-30 16:26:03 +1000242 pass
243
244 self.assertEqual(MyClass.otherarg, 1)
245
246 def test_type(self):
247 t = type('NewClass', (object,), {})
248 self.assertIsInstance(t, type)
249 self.assertEqual(t.__name__, 'NewClass')
250
251 with self.assertRaises(TypeError):
252 type(name='NewClass', bases=(object,), dict={})
253
254
255if __name__ == "__main__":
Berker Peksag01d17192016-07-30 14:06:15 +0300256 unittest.main()