cython

Форк
0
/
test_subclassinit.py 
313 строк · 9.3 Кб
1
# mode: run
2
# tag: pure3.6
3
# cython: language_level=3str
4

5
import re
6
import sys
7
import types
8
import unittest
9

10
ZERO = 0
11

12

13
class Test(unittest.TestCase):
14
    if not hasattr(unittest.TestCase, 'assertRegex'):
15
        def assertRegex(self, value, regex):
16
            self.assertTrue(re.search(regex, str(value)),
17
                            "'%s' did not match '%s'" % (value, regex))
18

19
    if not hasattr(unittest.TestCase, 'assertCountEqual'):
20
        def assertCountEqual(self, first, second):
21
            self.assertEqual(set(first), set(second))
22
            self.assertEqual(len(first), len(second))
23

24
    def test_init_subclass(self):
25
        class A:
26
            initialized = False
27

28
            def __init_subclass__(cls):
29
                super().__init_subclass__()
30
                cls.initialized = True
31

32
        class B(A):
33
            pass
34

35
        self.assertFalse(A.initialized)
36
        self.assertTrue(B.initialized)
37

38
    def test_init_subclass_dict(self):
39
        class A(dict):
40
            initialized = False
41

42
            def __init_subclass__(cls):
43
                super().__init_subclass__()
44
                cls.initialized = True
45

46
        class B(A):
47
            pass
48

49
        self.assertFalse(A.initialized)
50
        self.assertTrue(B.initialized)
51

52
    def test_init_subclass_kwargs(self):
53
        class A:
54
            def __init_subclass__(cls, **kwargs):
55
                cls.kwargs = kwargs
56

57
        class B(A, x=3):
58
            pass
59

60
        self.assertEqual(B.kwargs, dict(x=3))
61

62
    def test_init_subclass_error(self):
63
        class A:
64
            def __init_subclass__(cls):
65
                raise RuntimeError
66

67
        with self.assertRaises(RuntimeError):
68
            class B(A):
69
                pass
70

71
    def test_init_subclass_wrong(self):
72
        class A:
73
            def __init_subclass__(cls, whatever):
74
                pass
75

76
        with self.assertRaises(TypeError):
77
            class B(A):
78
                pass
79

80
    def test_init_subclass_skipped(self):
81
        class BaseWithInit:
82
            def __init_subclass__(cls, **kwargs):
83
                super().__init_subclass__(**kwargs)
84
                cls.initialized = cls
85

86
        class BaseWithoutInit(BaseWithInit):
87
            pass
88

89
        class A(BaseWithoutInit):
90
            pass
91

92
        self.assertIs(A.initialized, A)
93
        self.assertIs(BaseWithoutInit.initialized, BaseWithoutInit)
94

95
    def test_init_subclass_diamond(self):
96
        class Base:
97
            def __init_subclass__(cls, **kwargs):
98
                super().__init_subclass__(**kwargs)
99
                cls.calls = []
100

101
        class Left(Base):
102
            pass
103

104
        class Middle:
105
            def __init_subclass__(cls, middle, **kwargs):
106
                super().__init_subclass__(**kwargs)
107
                cls.calls += [middle]
108

109
        class Right(Base):
110
            def __init_subclass__(cls, right="right", **kwargs):
111
                super().__init_subclass__(**kwargs)
112
                cls.calls += [right]
113

114
        class A(Left, Middle, Right, middle="middle"):
115
            pass
116

117
        self.assertEqual(A.calls, ["right", "middle"])
118
        self.assertEqual(Left.calls, [])
119
        self.assertEqual(Right.calls, [])
120

121
    def test_set_name(self):
122
        class Descriptor:
123
            def __set_name__(self, owner, name):
124
                self.owner = owner
125
                self.name = name
126

127
        class A:
128
            d = Descriptor()
129

130
        self.assertEqual(A.d.name, "d")
131
        self.assertIs(A.d.owner, A)
132

133
    def test_set_name_metaclass(self):
134
        class Meta(type):
135
            def __new__(cls, name, bases, ns):
136
                ret = super().__new__(cls, name, bases, ns)
137
                self.assertEqual(ret.d.name, "d")
138
                self.assertIs(ret.d.owner, ret)
139
                return 0
140

141
        class Descriptor:
142
            def __set_name__(self, owner, name):
143
                self.owner = owner
144
                self.name = name
145

146
        class A(metaclass=Meta):
147
            d = Descriptor()
148
        self.assertEqual(A, 0)
149

150
    def test_set_name_error(self):
151
        class Descriptor:
152
            def __set_name__(self, owner, name):
153
                1 / ZERO
154

155
        with self.assertRaises((RuntimeError, ZeroDivisionError)) as cm:
156
            class NotGoingToWork:
157
                attr = Descriptor()
158

159
        if sys.version_info >= (3, 12):
160
            notes = cm.exception.__notes__
161
            self.assertRegex(str(notes), r'\bNotGoingToWork\b')
162
            self.assertRegex(str(notes), r'\battr\b')
163
            self.assertRegex(str(notes), r'\bDescriptor\b')
164
        else:
165
            exc = cm.exception
166
            self.assertRegex(str(exc), r'\bNotGoingToWork\b')
167
            self.assertRegex(str(exc), r'\battr\b')
168
            self.assertRegex(str(exc), r'\bDescriptor\b')
169
            self.assertIsInstance(exc.__cause__, ZeroDivisionError)
170

171
    def test_set_name_wrong(self):
172
        class Descriptor:
173
            def __set_name__(self):
174
                pass
175

176
        with self.assertRaises((RuntimeError, TypeError)) as cm:
177
            class NotGoingToWork:
178
                attr = Descriptor()
179

180
        if sys.version_info >= (3, 12):
181
            notes = cm.exception.__notes__
182
            self.assertRegex(str(notes), r'\bNotGoingToWork\b')
183
            self.assertRegex(str(notes), r'\battr\b')
184
            self.assertRegex(str(notes), r'\bDescriptor\b')
185
        else:
186
            exc = cm.exception
187
            self.assertRegex(str(exc), r'\bNotGoingToWork\b')
188
            self.assertRegex(str(exc), r'\battr\b')
189
            self.assertRegex(str(exc), r'\bDescriptor\b')
190
            self.assertIsInstance(exc.__cause__, TypeError)
191

192
    def test_set_name_lookup(self):
193
        resolved = []
194
        class NonDescriptor:
195
            def __getattr__(self, name):
196
                resolved.append(name)
197

198
        class A:
199
            d = NonDescriptor()
200

201
        self.assertNotIn('__set_name__', resolved,
202
                         '__set_name__ is looked up in instance dict')
203

204
    def test_set_name_init_subclass(self):
205
        class Descriptor:
206
            def __set_name__(self, owner, name):
207
                self.owner = owner
208
                self.name = name
209

210
        class Meta(type):
211
            def __new__(cls, name, bases, ns):
212
                self = super().__new__(cls, name, bases, ns)
213
                self.meta_owner = self.owner
214
                self.meta_name = self.name
215
                return self
216

217
        class A:
218
            def __init_subclass__(cls):
219
                cls.owner = cls.d.owner
220
                cls.name = cls.d.name
221

222
        class B(A, metaclass=Meta):
223
            d = Descriptor()
224

225
        self.assertIs(B.owner, B)
226
        self.assertEqual(B.name, 'd')
227
        self.assertIs(B.meta_owner, B)
228
        self.assertEqual(B.name, 'd')
229

230
    def test_set_name_modifying_dict(self):
231
        notified = []
232
        class Descriptor:
233
            def __set_name__(self, owner, name):
234
                setattr(owner, name + 'x', None)
235
                notified.append(name)
236

237
        class A:
238
            a = Descriptor()
239
            b = Descriptor()
240
            c = Descriptor()
241
            d = Descriptor()
242
            e = Descriptor()
243

244
        self.assertCountEqual(notified, ['a', 'b', 'c', 'd', 'e'])
245

246
    def test_errors(self):
247
        class MyMeta(type):
248
            pass
249

250
        with self.assertRaises(TypeError):
251
            class MyClass(metaclass=MyMeta, otherarg=1):
252
                pass
253

254
        with self.assertRaises(TypeError):
255
            types.new_class("MyClass", (object,),
256
                            dict(metaclass=MyMeta, otherarg=1))
257
        types.prepare_class("MyClass", (object,),
258
                            dict(metaclass=MyMeta, otherarg=1))
259

260
        class MyMeta(type):
261
            def __init__(self, name, bases, namespace, otherarg):
262
                super().__init__(name, bases, namespace)
263

264
        with self.assertRaises(TypeError):
265
            class MyClass(metaclass=MyMeta, otherarg=1):
266
                pass
267

268
        class MyMeta(type):
269
            def __new__(cls, name, bases, namespace, otherarg):
270
                return super().__new__(cls, name, bases, namespace)
271

272
            def __init__(self, name, bases, namespace, otherarg):
273
                super().__init__(name, bases, namespace)
274
                self.otherarg = otherarg
275

276
        class MyClass(metaclass=MyMeta, otherarg=1):
277
            pass
278

279
        self.assertEqual(MyClass.otherarg, 1)
280

281
    def test_errors_changed_pep487(self):
282
        # These tests failed before Python 3.6, PEP 487
283
        class MyMeta(type):
284
            def __new__(cls, name, bases, namespace):
285
                return super().__new__(cls, name=name, bases=bases,
286
                                       dict=namespace)
287

288
        with self.assertRaises(TypeError):
289
            class MyClass(metaclass=MyMeta):
290
                pass
291

292
        class MyMeta(type):
293
            def __new__(cls, name, bases, namespace, otherarg):
294
                self = super().__new__(cls, name, bases, namespace)
295
                self.otherarg = otherarg
296
                return self
297

298
        class MyClass(metaclass=MyMeta, otherarg=1):
299
            pass
300

301
        self.assertEqual(MyClass.otherarg, 1)
302

303
    def test_type(self):
304
        t = type('NewClass', (object,), {})
305
        self.assertIsInstance(t, type)
306
        self.assertEqual(t.__name__, 'NewClass')
307

308
        with self.assertRaises(TypeError):
309
            type(name='NewClass', bases=(object,), dict={})
310

311

312
if __name__ == "__main__":
313
    unittest.main()
314

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.