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"