μHAL (v2.8.17)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
test_multiple_inheritance.py
Go to the documentation of this file.
1# -*- coding: utf-8 -*-
2import pytest
3
4import env # noqa: F401
5from pybind11_tests import ConstructorStats
6from pybind11_tests import multiple_inheritance as m
7
8
10 mt = m.MIType(3, 4)
11
12 assert mt.foo() == 3
13 assert mt.bar() == 4
14
15
16@pytest.mark.skipif("env.PYPY and env.PY2")
17@pytest.mark.xfail("env.PYPY and not env.PY2")
19 class Base1:
20 def __init__(self, i):
21 self.i = i
22
23 def foo(self):
24 return self.i
25
26 class MITypePy(Base1, m.Base2):
27 def __init__(self, i, j):
28 Base1.__init__(self, i)
29 m.Base2.__init__(self, j)
30
31 mt = MITypePy(3, 4)
32
33 assert mt.foo() == 3
34 assert mt.bar() == 4
35
36
38 class Base2:
39 def __init__(self, i):
40 self.i = i
41
42 def bar(self):
43 return self.i
44
45 class MITypePy(m.Base1, Base2):
46 def __init__(self, i, j):
47 m.Base1.__init__(self, i)
48 Base2.__init__(self, j)
49
50 mt = MITypePy(3, 4)
51
52 assert mt.foo() == 3
53 assert mt.bar() == 4
54
55
56@pytest.mark.skipif("env.PYPY and env.PY2")
57@pytest.mark.xfail("env.PYPY and not env.PY2")
59 class MI1(m.Base1, m.Base2):
60 def __init__(self, i, j):
61 m.Base1.__init__(self, i)
62 m.Base2.__init__(self, j)
63
64 class B1(object):
65 def v(self):
66 return 1
67
68 class MI2(B1, m.Base1, m.Base2):
69 def __init__(self, i, j):
70 B1.__init__(self)
71 m.Base1.__init__(self, i)
72 m.Base2.__init__(self, j)
73
74 class MI3(MI2):
75 def __init__(self, i, j):
76 MI2.__init__(self, i, j)
77
78 class MI4(MI3, m.Base2):
79 def __init__(self, i, j):
80 MI3.__init__(self, i, j)
81 # This should be ignored (Base2 is already initialized via MI2):
82 m.Base2.__init__(self, i + 100)
83
84 class MI5(m.Base2, B1, m.Base1):
85 def __init__(self, i, j):
86 B1.__init__(self)
87 m.Base1.__init__(self, i)
88 m.Base2.__init__(self, j)
89
90 class MI6(m.Base2, B1):
91 def __init__(self, i):
92 m.Base2.__init__(self, i)
93 B1.__init__(self)
94
95 class B2(B1):
96 def v(self):
97 return 2
98
99 class B3(object):
100 def v(self):
101 return 3
102
103 class B4(B3, B2):
104 def v(self):
105 return 4
106
107 class MI7(B4, MI6):
108 def __init__(self, i):
109 B4.__init__(self)
110 MI6.__init__(self, i)
111
112 class MI8(MI6, B3):
113 def __init__(self, i):
114 MI6.__init__(self, i)
115 B3.__init__(self)
116
117 class MI8b(B3, MI6):
118 def __init__(self, i):
119 B3.__init__(self)
120 MI6.__init__(self, i)
121
122 mi1 = MI1(1, 2)
123 assert mi1.foo() == 1
124 assert mi1.bar() == 2
125
126 mi2 = MI2(3, 4)
127 assert mi2.v() == 1
128 assert mi2.foo() == 3
129 assert mi2.bar() == 4
130
131 mi3 = MI3(5, 6)
132 assert mi3.v() == 1
133 assert mi3.foo() == 5
134 assert mi3.bar() == 6
135
136 mi4 = MI4(7, 8)
137 assert mi4.v() == 1
138 assert mi4.foo() == 7
139 assert mi4.bar() == 8
140
141 mi5 = MI5(10, 11)
142 assert mi5.v() == 1
143 assert mi5.foo() == 10
144 assert mi5.bar() == 11
145
146 mi6 = MI6(12)
147 assert mi6.v() == 1
148 assert mi6.bar() == 12
149
150 mi7 = MI7(13)
151 assert mi7.v() == 4
152 assert mi7.bar() == 13
153
154 mi8 = MI8(14)
155 assert mi8.v() == 1
156 assert mi8.bar() == 14
157
158 mi8b = MI8b(15)
159 assert mi8b.v() == 3
160 assert mi8b.bar() == 15
161
162
164 class MIMany14(m.BaseN1, m.BaseN2, m.BaseN3, m.BaseN4):
165 def __init__(self):
166 m.BaseN1.__init__(self, 1)
167 m.BaseN2.__init__(self, 2)
168 m.BaseN3.__init__(self, 3)
169 m.BaseN4.__init__(self, 4)
170
171 class MIMany58(m.BaseN5, m.BaseN6, m.BaseN7, m.BaseN8):
172 def __init__(self):
173 m.BaseN5.__init__(self, 5)
174 m.BaseN6.__init__(self, 6)
175 m.BaseN7.__init__(self, 7)
176 m.BaseN8.__init__(self, 8)
177
178 class MIMany916(
179 m.BaseN9,
180 m.BaseN10,
181 m.BaseN11,
182 m.BaseN12,
183 m.BaseN13,
184 m.BaseN14,
185 m.BaseN15,
186 m.BaseN16,
187 ):
188 def __init__(self):
189 m.BaseN9.__init__(self, 9)
190 m.BaseN10.__init__(self, 10)
191 m.BaseN11.__init__(self, 11)
192 m.BaseN12.__init__(self, 12)
193 m.BaseN13.__init__(self, 13)
194 m.BaseN14.__init__(self, 14)
195 m.BaseN15.__init__(self, 15)
196 m.BaseN16.__init__(self, 16)
197
198 class MIMany19(MIMany14, MIMany58, m.BaseN9):
199 def __init__(self):
200 MIMany14.__init__(self)
201 MIMany58.__init__(self)
202 m.BaseN9.__init__(self, 9)
203
204 class MIMany117(MIMany14, MIMany58, MIMany916, m.BaseN17):
205 def __init__(self):
206 MIMany14.__init__(self)
207 MIMany58.__init__(self)
208 MIMany916.__init__(self)
209 m.BaseN17.__init__(self, 17)
210
211 # Inherits from 4 registered C++ classes: can fit in one pointer on any modern arch:
212 a = MIMany14()
213 for i in range(1, 4):
214 assert getattr(a, "f" + str(i))() == 2 * i
215
216 # Inherits from 8: requires 1/2 pointers worth of holder flags on 32/64-bit arch:
217 b = MIMany916()
218 for i in range(9, 16):
219 assert getattr(b, "f" + str(i))() == 2 * i
220
221 # Inherits from 9: requires >= 2 pointers worth of holder flags
222 c = MIMany19()
223 for i in range(1, 9):
224 assert getattr(c, "f" + str(i))() == 2 * i
225
226 # Inherits from 17: requires >= 3 pointers worth of holder flags
227 d = MIMany117()
228 for i in range(1, 17):
229 assert getattr(d, "f" + str(i))() == 2 * i
230
231
233 class MITypePy(m.Base12a):
234 def __init__(self, i, j):
235 m.Base12a.__init__(self, i, j)
236
237 mt = MITypePy(3, 4)
238 assert mt.bar() == 4
239 assert m.bar_base2a(mt) == 4
240 assert m.bar_base2a_sharedptr(mt) == 4
241
242
244 """Mixing bases with and without static properties should be possible
245 and the result should be independent of base definition order"""
246
247 for d in (m.VanillaStaticMix1(), m.VanillaStaticMix2()):
248 assert d.vanilla() == "Vanilla"
249 assert d.static_func1() == "WithStatic1"
250 assert d.static_func2() == "WithStatic2"
251 assert d.static_func() == d.__class__.__name__
252
253 m.WithStatic1.static_value1 = 1
254 m.WithStatic2.static_value2 = 2
255 assert d.static_value1 == 1
256 assert d.static_value2 == 2
257 assert d.static_value == 12
258
259 d.static_value1 = 0
260 assert d.static_value1 == 0
261 d.static_value2 = 0
262 assert d.static_value2 == 0
263 d.static_value = 0
264 assert d.static_value == 0
265
266
267# Requires PyPy 6+
269 """Mixing bases with and without dynamic attribute support"""
270
271 for d in (m.VanillaDictMix1(), m.VanillaDictMix2()):
272 d.dynamic = 1
273 assert d.dynamic == 1
274
275
277 """Returning an offset (non-first MI) base class pointer should recognize the instance"""
278
279 n_inst = ConstructorStats.detail_reg_inst()
280
281 c = m.I801C()
282 d = m.I801D()
283 # + 4 below because we have the two instances, and each instance has offset base I801B2
284 assert ConstructorStats.detail_reg_inst() == n_inst + 4
285 b1c = m.i801b1_c(c)
286 assert b1c is c
287 b2c = m.i801b2_c(c)
288 assert b2c is c
289 b1d = m.i801b1_d(d)
290 assert b1d is d
291 b2d = m.i801b2_d(d)
292 assert b2d is d
293
294 assert ConstructorStats.detail_reg_inst() == n_inst + 4 # no extra instances
295 del c, b1c, b2c
296 assert ConstructorStats.detail_reg_inst() == n_inst + 2
297 del d, b1d, b2d
298 assert ConstructorStats.detail_reg_inst() == n_inst
299
300
302 """Tests returning an offset (non-first MI) base class pointer to a derived instance"""
303
304 n_inst = ConstructorStats.detail_reg_inst()
305
306 c1 = m.i801c_b1()
307 assert type(c1) is m.I801C
308 assert c1.a == 1
309 assert c1.b == 2
310
311 d1 = m.i801d_b1()
312 assert type(d1) is m.I801D
313 assert d1.a == 1
314 assert d1.b == 2
315
316 assert ConstructorStats.detail_reg_inst() == n_inst + 4
317
318 c2 = m.i801c_b2()
319 assert type(c2) is m.I801C
320 assert c2.a == 1
321 assert c2.b == 2
322
323 d2 = m.i801d_b2()
324 assert type(d2) is m.I801D
325 assert d2.a == 1
326 assert d2.b == 2
327
328 assert ConstructorStats.detail_reg_inst() == n_inst + 8
329
330 del c2
331 assert ConstructorStats.detail_reg_inst() == n_inst + 6
332 del c1, d1, d2
333 assert ConstructorStats.detail_reg_inst() == n_inst
334
335 # Returning an unregistered derived type with a registered base; we won't
336 # pick up the derived type, obviously, but should still work (as an object
337 # of whatever type was returned).
338 e1 = m.i801e_c()
339 assert type(e1) is m.I801C
340 assert e1.a == 1
341 assert e1.b == 2
342
343 e2 = m.i801e_b2()
344 assert type(e2) is m.I801B2
345 assert e2.b == 2
346
347
349 """Tests that diamond inheritance works as expected (issue #959)"""
350
351 # Issue #959: this shouldn't segfault:
352 d = m.D()
353
354 # Make sure all the various distinct pointers are all recognized as registered instances:
355 assert d is d.c0()
356 assert d is d.c1()
357 assert d is d.b()
358 assert d is d.c0().b()
359 assert d is d.c1().b()
360 assert d is d.c0().c1().b().c0().b()
361
362
364 o = m.MVB()
365 assert o.b == 1
366
367 assert o.get_b_b() == 1
368
369
371 o = m.MVC()
372 assert o.b == 1
373 assert o.c == 2
374
375 assert o.get_b_b() == 1
376 assert o.get_c_b() == 1
377
378 assert o.get_c_c() == 2
379
380
382 o = m.MVD0()
383 assert o.b == 1
384 assert o.c == 2
385 assert o.d0 == 3
386
387 assert o.get_b_b() == 1
388 assert o.get_c_b() == 1
389 assert o.get_d0_b() == 1
390
391 assert o.get_c_c() == 2
392 assert o.get_d0_c() == 2
393
394 assert o.get_d0_d0() == 3
395
396
398 o = m.MVD1()
399 assert o.b == 1
400 assert o.c == 2
401 assert o.d1 == 4
402
403 assert o.get_b_b() == 1
404 assert o.get_c_b() == 1
405 assert o.get_d1_b() == 1
406
407 assert o.get_c_c() == 2
408 assert o.get_d1_c() == 2
409
410 assert o.get_d1_d1() == 4
411
412
414 o = m.MVE()
415 assert o.b == 1
416 assert o.c == 2
417 assert o.d0 == 3
418 assert o.d1 == 4
419 assert o.e == 5
420
421 assert o.get_b_b() == 1
422 assert o.get_c_b() == 1
423 assert o.get_d0_b() == 1
424 assert o.get_d1_b() == 1
425 assert o.get_e_b() == 1
426
427 assert o.get_c_c() == 2
428 assert o.get_d0_c() == 2
429 assert o.get_d1_c() == 2
430 assert o.get_e_c() == 2
431
432 assert o.get_d0_d0() == 3
433 assert o.get_e_d0() == 3
434
435 assert o.get_d1_d1() == 4
436 assert o.get_e_d1() == 4
437
438 assert o.get_e_e() == 5
439
440
442 o = m.MVF()
443 assert o.b == 1
444 assert o.c == 2
445 assert o.d0 == 3
446 assert o.d1 == 4
447 assert o.e == 5
448 assert o.f == 6
449
450 assert o.get_b_b() == 1
451 assert o.get_c_b() == 1
452 assert o.get_d0_b() == 1
453 assert o.get_d1_b() == 1
454 assert o.get_e_b() == 1
455 assert o.get_f_b() == 1
456
457 assert o.get_c_c() == 2
458 assert o.get_d0_c() == 2
459 assert o.get_d1_c() == 2
460 assert o.get_e_c() == 2
461 assert o.get_f_c() == 2
462
463 assert o.get_d0_d0() == 3
464 assert o.get_e_d0() == 3
465 assert o.get_f_d0() == 3
466
467 assert o.get_d1_d1() == 4
468 assert o.get_e_d1() == 4
469 assert o.get_f_d1() == 4
470
471 assert o.get_e_e() == 5
472 assert o.get_f_e() == 5
473
474 assert o.get_f_f() == 6
475
476
478 """Tests extending a Python class from a single inheritor of a MI class"""
479
480 class PyMVF(m.MVF):
481 g = 7
482
483 def get_g_g(self):
484 return self.g
485
486 o = PyMVF()
487
488 assert o.b == 1
489 assert o.c == 2
490 assert o.d0 == 3
491 assert o.d1 == 4
492 assert o.e == 5
493 assert o.f == 6
494 assert o.g == 7
495
496 assert o.get_g_g() == 7
\rst Holds a reference to a Python object (with reference counting)
Definition: pytypes.h:259
Definition: pytypes.h:1200
Definition: pytypes.h:1167
object getattr(handle obj, handle name)
Definition: pytypes.h:537