1 from __future__
import annotations
7 from pybind11_tests
import ConstructorStats
8 from pybind11_tests
import factory_constructors
as m
9 from pybind11_tests.factory_constructors
import tag
13 """Tests py::init_factory() wrapper around various ways of returning the object"""
17 for c
in [m.TestFactory1, m.TestFactory2, m.TestFactory3]
20 n_inst = ConstructorStats.detail_reg_inst()
22 x1 = m.TestFactory1(tag.unique_ptr, 3)
23 assert x1.value ==
"3"
24 y1 = m.TestFactory1(tag.pointer)
25 assert y1.value ==
"(empty)"
26 z1 = m.TestFactory1(
"hi!")
27 assert z1.value ==
"hi!"
29 assert ConstructorStats.detail_reg_inst() == n_inst + 3
31 x2 = m.TestFactory2(tag.move)
32 assert x2.value ==
"(empty2)"
33 y2 = m.TestFactory2(tag.pointer, 7)
34 assert y2.value ==
"7"
35 z2 = m.TestFactory2(tag.unique_ptr,
"hi again")
36 assert z2.value ==
"hi again"
38 assert ConstructorStats.detail_reg_inst() == n_inst + 6
40 x3 = m.TestFactory3(tag.shared_ptr)
41 assert x3.value ==
"(empty3)"
42 y3 = m.TestFactory3(tag.pointer, 42)
43 assert y3.value ==
"42"
44 z3 = m.TestFactory3(
"bye")
45 assert z3.value ==
"bye"
47 for null_ptr_kind
in [tag.null_ptr, tag.null_unique_ptr, tag.null_shared_ptr]:
48 with pytest.raises(TypeError)
as excinfo:
49 m.TestFactory3(null_ptr_kind)
51 str(excinfo.value) ==
"pybind11::init(): factory function returned nullptr"
54 assert [i.alive()
for i
in cstats] == [3, 3, 3]
55 assert ConstructorStats.detail_reg_inst() == n_inst + 9
58 assert [i.alive()
for i
in cstats] == [2, 2, 1]
59 assert ConstructorStats.detail_reg_inst() == n_inst + 5
60 del x2, x3, y1, z1, z2
61 assert [i.alive()
for i
in cstats] == [0, 0, 0]
62 assert ConstructorStats.detail_reg_inst() == n_inst
64 assert [i.values()
for i
in cstats] == [
69 assert [i.default_constructions
for i
in cstats] == [1, 1, 1]
73 with pytest.raises(TypeError)
as excinfo:
74 m.TestFactory1(
"invalid",
"constructor",
"arguments")
78 __init__(): incompatible constructor arguments. The following argument types are supported:
79 1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int)
80 2. m.factory_constructors.TestFactory1(arg0: str)
81 3. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.pointer_tag)
82 4. m.factory_constructors.TestFactory1(arg0: object, arg1: int, arg2: object)
84 Invoked with: 'invalid', 'constructor', 'arguments'
89 msg(m.TestFactory1.__init__.__doc__)
91 __init__(*args, **kwargs)
94 1. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) -> None
96 2. __init__(self: m.factory_constructors.TestFactory1, arg0: str) -> None
98 3. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.pointer_tag) -> None
100 4. __init__(self: m.factory_constructors.TestFactory1, arg0: object, arg1: int, arg2: object) -> None
106 """Tests py::init_factory() wrapper with various upcasting and downcasting returns"""
110 for c
in [m.TestFactory3, m.TestFactory4, m.TestFactory5]
113 n_inst = ConstructorStats.detail_reg_inst()
116 a = m.TestFactory3(tag.pointer, tag.TF4, 4)
117 assert a.value ==
"4"
118 b = m.TestFactory3(tag.shared_ptr, tag.TF4, 5)
119 assert b.value ==
"5"
120 c = m.TestFactory3(tag.pointer, tag.TF5, 6)
121 assert c.value ==
"6"
122 d = m.TestFactory3(tag.shared_ptr, tag.TF5, 7)
123 assert d.value ==
"7"
125 assert ConstructorStats.detail_reg_inst() == n_inst + 4
128 e = m.TestFactory4(tag.pointer, tag.TF4, 8)
129 assert e.value ==
"8"
131 assert ConstructorStats.detail_reg_inst() == n_inst + 5
132 assert [i.alive()
for i
in cstats] == [5, 3, 2]
135 assert [i.alive()
for i
in cstats] == [4, 2, 2]
136 assert ConstructorStats.detail_reg_inst() == n_inst + 4
139 assert [i.alive()
for i
in cstats] == [1, 0, 1]
140 assert ConstructorStats.detail_reg_inst() == n_inst + 1
143 assert [i.alive()
for i
in cstats] == [0, 0, 0]
144 assert ConstructorStats.detail_reg_inst() == n_inst
146 assert [i.values()
for i
in cstats] == [
147 [
"4",
"5",
"6",
"7",
"8"],
154 """Tests py::init_factory() wrapper with value conversions and alias types"""
156 cstats = [m.TestFactory6.get_cstats(), m.TestFactory6.get_alias_cstats()]
158 n_inst = ConstructorStats.detail_reg_inst()
160 a = m.TestFactory6(tag.base, 1)
162 assert not a.has_alias()
163 b = m.TestFactory6(tag.alias,
"hi there")
166 c = m.TestFactory6(tag.alias, 3)
169 d = m.TestFactory6(tag.alias, tag.pointer, 4)
172 e = m.TestFactory6(tag.base, tag.pointer, 5)
174 assert not e.has_alias()
175 f = m.TestFactory6(tag.base, tag.alias, tag.pointer, 6)
179 assert ConstructorStats.detail_reg_inst() == n_inst + 6
180 assert [i.alive()
for i
in cstats] == [6, 4]
183 assert [i.alive()
for i
in cstats] == [3, 3]
184 assert ConstructorStats.detail_reg_inst() == n_inst + 3
186 assert [i.alive()
for i
in cstats] == [0, 0]
187 assert ConstructorStats.detail_reg_inst() == n_inst
189 class MyTest(m.TestFactory6):
191 m.TestFactory6.__init__(self, *args)
194 return -5 + m.TestFactory6.get(self)
197 z = MyTest(tag.base, 123)
198 assert z.get() == 118
202 y = MyTest(tag.alias,
"why hello!")
207 x = MyTest(tag.base, tag.pointer, 47)
211 assert ConstructorStats.detail_reg_inst() == n_inst + 3
212 assert [i.alive()
for i
in cstats] == [3, 3]
214 assert [i.alive()
for i
in cstats] == [0, 0]
215 assert ConstructorStats.detail_reg_inst() == n_inst
217 assert [i.values()
for i
in cstats] == [
218 [
"1",
"8",
"3",
"4",
"5",
"6",
"123",
"10",
"47"],
219 [
"hi there",
"3",
"4",
"6",
"move",
"123",
"why hello!",
"move",
"47"],
224 """Tests init factory functions with dual main/alias factory functions"""
225 from pybind11_tests.factory_constructors
import TestFactory7
227 cstats = [TestFactory7.get_cstats(), TestFactory7.get_alias_cstats()]
229 n_inst = ConstructorStats.detail_reg_inst()
238 assert a2.get() == 102
239 assert not a1.has_alias()
240 assert a2.has_alias()
243 b2 = PythFactory7(tag.pointer, 4)
245 assert b2.get() == 104
246 assert not b1.has_alias()
247 assert b2.has_alias()
250 c2 = PythFactory7(tag.mixed, 6)
252 assert c2.get() == 106
253 assert not c1.has_alias()
254 assert c2.has_alias()
257 d2 = PythFactory7(tag.base, tag.pointer, 8)
259 assert d2.get() == 108
260 assert not d1.has_alias()
261 assert d2.has_alias()
265 e2 = PythFactory7(tag.alias, tag.pointer, 10)
267 assert e2.get() == 200
268 assert e1.has_alias()
269 assert e2.has_alias()
272 f2 = PythFactory7(tag.shared_ptr, tag.base, 12)
273 assert f1.get() == 11
274 assert f2.get() == 112
275 assert not f1.has_alias()
276 assert f2.has_alias()
279 assert g1.get() == 13
280 assert not g1.has_alias()
281 with pytest.raises(TypeError)
as excinfo:
282 PythFactory7(tag.shared_ptr, tag.invalid_base, 14)
285 ==
"pybind11::init(): construction failed: returned holder-wrapped instance is not an "
289 assert [i.alive()
for i
in cstats] == [13, 7]
290 assert ConstructorStats.detail_reg_inst() == n_inst + 13
292 del a1, a2, b1, d1, e1, e2
293 assert [i.alive()
for i
in cstats] == [7, 4]
294 assert ConstructorStats.detail_reg_inst() == n_inst + 7
295 del b2, c1, c2, d2, f1, f2, g1
296 assert [i.alive()
for i
in cstats] == [0, 0]
297 assert ConstructorStats.detail_reg_inst() == n_inst
299 assert [i.values()
for i
in cstats] == [
300 [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"100",
"11",
"12",
"13",
"14"],
301 [
"2",
"4",
"6",
"8",
"9",
"100",
"12"],
306 """Prior to 2.2, `py::init<...>` relied on the type supporting placement
307 new; this tests a class without placement new support."""
309 a = m.NoPlacementNew(123)
311 found = re.search(
r"^operator new called, returning (\d+)\n$",
str(capture))
317 assert capture ==
"operator delete called on " + found.group(1)
320 b = m.NoPlacementNew()
322 found = re.search(
r"^operator new called, returning (\d+)\n$",
str(capture))
328 assert capture ==
"operator delete called on " + found.group(1)
332 class MITest(m.TestFactory1, m.TestFactory2):
334 m.TestFactory1.__init__(self, tag.unique_ptr, 33)
335 m.TestFactory2.__init__(self, tag.move)
338 assert m.TestFactory1.value.fget(a) ==
"33"
339 assert m.TestFactory2.value.fget(a) ==
"(empty2)"
343 a = m.NoisyAlloc(*args)
350 return re.sub(
r"\s+#.*",
"", s)
354 """When the constructor is overloaded, previous overloads can require a preallocated value.
355 This test makes sure that such preallocated values only happen when they might be necessary,
356 and that they are deallocated properly."""
380 noisy new # allocation required to attempt first overload
381 noisy delete # have to dealloc before considering factory init overload
382 noisy new # pointer factory calling "new", part 1: allocation
383 NoisyAlloc(double 1.5) # ... part two, invoking constructor
385 ~NoisyAlloc() # Destructor
386 noisy delete # operator delete
396 noisy new # pointer factory calling "new", allocation
397 NoisyAlloc(int 2) # constructor
399 ~NoisyAlloc() # Destructor
400 noisy delete # operator delete
410 NoisyAlloc(double 2.5) # construction (local func variable: operator_new not called)
411 noisy new # return-by-value "new" part 1: allocation
412 ~NoisyAlloc() # moved-away local func variable destruction
414 ~NoisyAlloc() # Destructor
415 noisy delete # operator delete
425 noisy new # preallocation needed before invoking placement-new overload
426 noisy placement new # Placement new
427 NoisyAlloc(double 3.5) # construction
429 ~NoisyAlloc() # Destructor
430 noisy delete # operator delete
440 noisy new # preallocation needed before invoking placement-new overload
441 noisy delete # deallocation of preallocated storage
442 noisy new # Factory pointer allocation
443 NoisyAlloc(int 4) # factory pointer construction
445 ~NoisyAlloc() # Destructor
446 noisy delete # operator delete
456 noisy new # preallocation needed before invoking first placement new
457 noisy delete # delete before considering new-style constructor
458 noisy new # preallocation for second placement new
459 noisy placement new # Placement new in the second placement new overload
460 NoisyAlloc(int 5) # construction
462 ~NoisyAlloc() # Destructor
463 noisy delete # operator delete
469 """Tests invocation of the pybind-registered base class with an invalid `self` argument."""
471 class NotPybindDerived:
475 class BrokenTF1(m.TestFactory1):
478 a = m.TestFactory2(tag.pointer, 1)
479 m.TestFactory1.__init__(a, tag.pointer)
481 a = NotPybindDerived()
482 m.TestFactory1.__init__(a, tag.pointer)
485 class BrokenTF6(m.TestFactory6):
488 m.TestFactory6.__init__()
490 a = m.TestFactory2(tag.pointer, 1)
491 m.TestFactory6.__init__(a, tag.base, 1)
493 a = m.TestFactory2(tag.pointer, 1)
494 m.TestFactory6.__init__(a, tag.alias, 1)
496 m.TestFactory6.__init__(
497 NotPybindDerived.__new__(NotPybindDerived), tag.base, 1
500 m.TestFactory6.__init__(
501 NotPybindDerived.__new__(NotPybindDerived), tag.alias, 1
505 with pytest.raises(TypeError)
as excinfo:
509 ==
"__init__(self, ...) called with invalid or missing `self` argument"
512 for arg
in (0, 1, 2, 3, 4):
513 with pytest.raises(TypeError)
as excinfo:
517 ==
"__init__(self, ...) called with invalid or missing `self` argument"