Beispiel #1
0
def test_return_none(capture):
    n_inst = ConstructorStats.detail_reg_inst()
    with capture:
        p = m.Parent()
    assert capture == "Allocating parent."
    with capture:
        p.returnNullChildKeepAliveChild()
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
    assert capture == ""
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == "Releasing parent."

    with capture:
        p = m.Parent()
    assert capture == "Allocating parent."
    with capture:
        p.returnNullChildKeepAliveParent()
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
    assert capture == ""
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == "Releasing parent."
Beispiel #2
0
def test_keep_alive_return_value(capture):
    from pybind11_tests import Parent, ConstructorStats

    n_inst = ConstructorStats.detail_reg_inst()
    with capture:
        p = Parent()
    assert capture == "Allocating parent."
    with capture:
        p.returnChild()
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
    assert capture == """
        Allocating child.
        Releasing child.
    """
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == "Releasing parent."

    with capture:
        p = Parent()
    assert capture == "Allocating parent."
    with capture:
        p.returnChildKeepAlive()
        assert ConstructorStats.detail_reg_inst() == n_inst + 2
    assert capture == "Allocating child."
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
def test_keep_alive_return_value(capture):
    n_inst = ConstructorStats.detail_reg_inst()
    with capture:
        p = m.Parent()
    assert capture == "Allocating parent."
    with capture:
        p.returnChild()
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
    assert (capture == """
        Allocating child.
        Releasing child.
    """)
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == "Releasing parent."

    with capture:
        p = m.Parent()
    assert capture == "Allocating parent."
    with capture:
        p.returnChildKeepAlive()
        assert ConstructorStats.detail_reg_inst() == n_inst + 2
    assert capture == "Allocating child."
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert (capture == """
        Releasing parent.
        Releasing child.
    """)
def test_keep_alive_return_value(capture):
    from pybind11_tests import Parent, ConstructorStats

    n_inst = ConstructorStats.detail_reg_inst()
    with capture:
        p = Parent()
    assert capture == "Allocating parent."
    with capture:
        p.returnChild()
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
    assert capture == """
        Allocating child.
        Releasing child.
    """
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == "Releasing parent."

    with capture:
        p = Parent()
    assert capture == "Allocating parent."
    with capture:
        p.returnChildKeepAlive()
        assert ConstructorStats.detail_reg_inst() == n_inst + 2
    assert capture == "Allocating child."
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
def test_mi_unaligned_base():
    """Returning an offset (non-first MI) base class pointer should recognize the instance"""
    from pybind11_tests import I801C, I801D, i801b1_c, i801b2_c, i801b1_d, i801b2_d

    n_inst = ConstructorStats.detail_reg_inst()

    c = I801C()
    d = I801D()
    # + 4 below because we have the two instances, and each instance has offset base I801B2
    assert ConstructorStats.detail_reg_inst() == n_inst + 4
    b1c = i801b1_c(c)
    assert b1c is c
    b2c = i801b2_c(c)
    assert b2c is c
    b1d = i801b1_d(d)
    assert b1d is d
    b2d = i801b2_d(d)
    assert b2d is d

    assert ConstructorStats.detail_reg_inst(
    ) == n_inst + 4  # no extra instances
    del c, b1c, b2c
    assert ConstructorStats.detail_reg_inst() == n_inst + 2
    del d, b1d, b2d
    assert ConstructorStats.detail_reg_inst() == n_inst
Beispiel #6
0
def test_keep_alive_argument(capture):
    n_inst = ConstructorStats.detail_reg_inst()
    with capture:
        p = m.Parent()
    assert capture == "Allocating parent."
    with capture:
        p.addChild(m.Child())
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
    assert capture == """
        Allocating child.
        Releasing child.
    """
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == "Releasing parent."

    with capture:
        p = m.Parent()
    assert capture == "Allocating parent."
    with capture:
        p.addChildKeepAlive(m.Child())
        assert ConstructorStats.detail_reg_inst() == n_inst + 2
    assert capture == "Allocating child."
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
Beispiel #7
0
def test_keep_alive_argument(capture):
    n_inst = ConstructorStats.detail_reg_inst()
    with capture:
        p = m.Parent()
    assert capture == "Allocating parent."
    with capture:
        p.addChild(m.Child())
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
    assert capture == """
        Allocating child.
        Releasing child.
    """
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == "Releasing parent."

    with capture:
        p = m.Parent()
    assert capture == "Allocating parent."
    with capture:
        p.addChildKeepAlive(m.Child())
        assert ConstructorStats.detail_reg_inst() == n_inst + 2
    assert capture == "Allocating child."
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
Beispiel #8
0
def test_return_none(capture):
    n_inst = ConstructorStats.detail_reg_inst()
    with capture:
        p = m.Parent()
    assert capture == "Allocating parent."
    with capture:
        p.returnNullChildKeepAliveChild()
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
    assert capture == ""
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == "Releasing parent."

    with capture:
        p = m.Parent()
    assert capture == "Allocating parent."
    with capture:
        p.returnNullChildKeepAliveParent()
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
    assert capture == ""
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == "Releasing parent."
Beispiel #9
0
def test_alive_gc(capture):
    n_inst = ConstructorStats.detail_reg_inst()
    p = m.ParentGC()
    p.addChildKeepAlive(m.Child())
    assert ConstructorStats.detail_reg_inst() == n_inst + 2
    lst = [p]
    lst.append(lst)   # creates a circular reference
    with capture:
        del p, lst
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
Beispiel #10
0
def test_alive_gc(capture):
    n_inst = ConstructorStats.detail_reg_inst()
    p = m.ParentGC()
    p.addChildKeepAlive(m.Child())
    assert ConstructorStats.detail_reg_inst() == n_inst + 2
    lst = [p]
    lst.append(lst)  # creates a circular reference
    with capture:
        del p, lst
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
def test_alive_gc(capture):
    from pybind11_tests import ParentGC, Child, ConstructorStats

    n_inst = ConstructorStats.detail_reg_inst()
    p = ParentGC()
    p.addChildKeepAlive(Child())
    assert ConstructorStats.detail_reg_inst() == n_inst + 2
    lst = [p]
    lst.append(lst)   # creates a circular reference
    with capture:
        del p, lst
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
Beispiel #12
0
def test_alive_gc(capture):
    from pybind11_tests import ParentGC, Child, ConstructorStats

    n_inst = ConstructorStats.detail_reg_inst()
    p = ParentGC()
    p.addChildKeepAlive(Child())
    assert ConstructorStats.detail_reg_inst() == n_inst + 2
    lst = [p]
    lst.append(lst)  # creates a circular reference
    with capture:
        del p, lst
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
Beispiel #13
0
def test_keep_alive_constructor(capture):
    n_inst = ConstructorStats.detail_reg_inst()

    with capture:
        p = m.Parent(m.Child())
        assert ConstructorStats.detail_reg_inst() == n_inst + 2
    assert capture == """
        Allocating child.
        Allocating parent.
    """
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
Beispiel #14
0
def test_keep_alive_constructor(capture):
    n_inst = ConstructorStats.detail_reg_inst()

    with capture:
        p = m.Parent(m.Child())
        assert ConstructorStats.detail_reg_inst() == n_inst + 2
    assert capture == """
        Allocating child.
        Allocating parent.
    """
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
def test_mi_base_return():
    """Tests returning an offset (non-first MI) base class pointer to a derived instance"""
    from pybind11_tests import (I801B2, I801C, I801D, i801c_b1, i801c_b2, i801d_b1, i801d_b2,
                                i801e_c, i801e_b2)

    n_inst = ConstructorStats.detail_reg_inst()

    c1 = i801c_b1()
    assert type(c1) is I801C
    assert c1.a == 1
    assert c1.b == 2

    d1 = i801d_b1()
    assert type(d1) is I801D
    assert d1.a == 1
    assert d1.b == 2

    assert ConstructorStats.detail_reg_inst() == n_inst + 4

    c2 = i801c_b2()
    assert type(c2) is I801C
    assert c2.a == 1
    assert c2.b == 2

    d2 = i801d_b2()
    assert type(d2) is I801D
    assert d2.a == 1
    assert d2.b == 2

    assert ConstructorStats.detail_reg_inst() == n_inst + 8

    del c2
    assert ConstructorStats.detail_reg_inst() == n_inst + 6
    del c1, d1, d2
    assert ConstructorStats.detail_reg_inst() == n_inst

    # Returning an unregistered derived type with a registered base; we won't
    # pick up the derived type, obviously, but should still work (as an object
    # of whatever type was returned).
    e1 = i801e_c()
    assert type(e1) is I801C
    assert e1.a == 1
    assert e1.b == 2

    e2 = i801e_b2()
    assert type(e2) is I801B2
    assert e2.b == 2
def test_mi_base_return():
    """Tests returning an offset (non-first MI) base class pointer to a derived instance"""
    from pybind11_tests import (I801B2, I801C, I801D, i801c_b1, i801c_b2,
                                i801d_b1, i801d_b2, i801e_c, i801e_b2)

    n_inst = ConstructorStats.detail_reg_inst()

    c1 = i801c_b1()
    assert type(c1) is I801C
    assert c1.a == 1
    assert c1.b == 2

    d1 = i801d_b1()
    assert type(d1) is I801D
    assert d1.a == 1
    assert d1.b == 2

    assert ConstructorStats.detail_reg_inst() == n_inst + 4

    c2 = i801c_b2()
    assert type(c2) is I801C
    assert c2.a == 1
    assert c2.b == 2

    d2 = i801d_b2()
    assert type(d2) is I801D
    assert d2.a == 1
    assert d2.b == 2

    assert ConstructorStats.detail_reg_inst() == n_inst + 8

    del c2
    assert ConstructorStats.detail_reg_inst() == n_inst + 6
    del c1, d1, d2
    assert ConstructorStats.detail_reg_inst() == n_inst

    # Returning an unregistered derived type with a registered base; we won't
    # pick up the derived type, obviously, but should still work (as an object
    # of whatever type was returned).
    e1 = i801e_c()
    assert type(e1) is I801C
    assert e1.a == 1
    assert e1.b == 2

    e2 = i801e_b2()
    assert type(e2) is I801B2
    assert e2.b == 2
Beispiel #17
0
def test_alive_gc_multi_derived(capture):
    from pybind11_tests import Parent, Child, ConstructorStats

    class Derived(Parent, Child):
        pass

    n_inst = ConstructorStats.detail_reg_inst()
    p = Derived()
    p.addChildKeepAlive(Child())
    # +3 rather than +2 because Derived corresponds to two registered instances
    assert ConstructorStats.detail_reg_inst() == n_inst + 3
    lst = [p]
    lst.append(lst)  # creates a circular reference
    with capture:
        del p, lst
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
def test_alive_gc_multi_derived(capture):
    from pybind11_tests import Parent, Child, ConstructorStats

    class Derived(Parent, Child):
        pass

    n_inst = ConstructorStats.detail_reg_inst()
    p = Derived()
    p.addChildKeepAlive(Child())
    # +3 rather than +2 because Derived corresponds to two registered instances
    assert ConstructorStats.detail_reg_inst() == n_inst + 3
    lst = [p]
    lst.append(lst)   # creates a circular reference
    with capture:
        del p, lst
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
Beispiel #19
0
def test_operator_new_delete(capture):
    """Tests that class-specific operator new/delete functions are invoked"""
    class SubAliased(m.AliasedHasOpNewDelSize):
        pass

    with capture:
        a = m.HasOpNewDel()
        b = m.HasOpNewDelSize()
        d = m.HasOpNewDelBoth()
    assert capture == """
        A new 8
        A placement-new 8
        B new 4
        B placement-new 4
        D new 32
        D placement-new 32
    """
    sz_alias = str(m.AliasedHasOpNewDelSize.size_alias)
    sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias)
    with capture:
        c = m.AliasedHasOpNewDelSize()
        c2 = SubAliased()
    assert capture == ("C new " + sz_alias + "\nC placement-new " +
                       sz_noalias + "\n" + "C new " + sz_alias +
                       "\nC placement-new " + sz_alias + "\n")

    with capture:
        del a
        ConstructorStats.detail_reg_inst()
        del b
        ConstructorStats.detail_reg_inst()
        del d
        ConstructorStats.detail_reg_inst()
    assert capture == """
        A delete
        B delete 4
        D delete
    """

    with capture:
        del c
        ConstructorStats.detail_reg_inst()
        del c2
        ConstructorStats.detail_reg_inst()
    assert capture == ("C delete " + sz_noalias + "\n" + "C delete " +
                       sz_alias + "\n")
Beispiel #20
0
def test_alive_gc_derived(capture):
    class Derived(m.Parent):
        pass

    n_inst = ConstructorStats.detail_reg_inst()
    p = Derived()
    p.addChildKeepAlive(m.Child())
    assert ConstructorStats.detail_reg_inst() == n_inst + 2
    lst = [p]
    lst.append(lst)  # creates a circular reference
    with capture:
        del p, lst
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert (capture == """
        Releasing parent.
        Releasing child.
    """)
Beispiel #21
0
def test_alive_gc_multi_derived(capture):
    class Derived(m.Parent, m.Child):
        def __init__(self):
            m.Parent.__init__(self)
            m.Child.__init__(self)

    n_inst = ConstructorStats.detail_reg_inst()
    p = Derived()
    p.addChildKeepAlive(m.Child())
    # +3 rather than +2 because Derived corresponds to two registered instances
    assert ConstructorStats.detail_reg_inst() == n_inst + 3
    lst = [p]
    lst.append(lst)  # creates a circular reference
    with capture:
        del p, lst
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
Beispiel #22
0
def test_alive_gc_multi_derived(capture):
    class Derived(m.Parent, m.Child):
        def __init__(self):
            m.Parent.__init__(self)
            m.Child.__init__(self)

    n_inst = ConstructorStats.detail_reg_inst()
    p = Derived()
    p.addChildKeepAlive(m.Child())
    # +3 rather than +2 because Derived corresponds to two registered instances
    assert ConstructorStats.detail_reg_inst() == n_inst + 3
    lst = [p]
    lst.append(lst)   # creates a circular reference
    with capture:
        del p, lst
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == """
def test_init_factory_basic():
    """Tests py::init_factory() wrapper around various ways of returning the object"""

    cstats = [
        ConstructorStats.get(c)
        for c in [m.TestFactory1, m.TestFactory2, m.TestFactory3]
    ]
    cstats[0].alive()  # force gc
    n_inst = ConstructorStats.detail_reg_inst()

    x1 = m.TestFactory1(tag.unique_ptr, 3)
    assert x1.value == "3"
    y1 = m.TestFactory1(tag.pointer)
    assert y1.value == "(empty)"
    z1 = m.TestFactory1("hi!")
    assert z1.value == "hi!"

    assert ConstructorStats.detail_reg_inst() == n_inst + 3

    x2 = m.TestFactory2(tag.move)
    assert x2.value == "(empty2)"
    y2 = m.TestFactory2(tag.pointer, 7)
    assert y2.value == "7"
    z2 = m.TestFactory2(tag.unique_ptr, "hi again")
    assert z2.value == "hi again"

    assert ConstructorStats.detail_reg_inst() == n_inst + 6

    x3 = m.TestFactory3(tag.shared_ptr)
    assert x3.value == "(empty3)"
    y3 = m.TestFactory3(tag.pointer, 42)
    assert y3.value == "42"
    z3 = m.TestFactory3("bye")
    assert z3.value == "bye"

    for null_ptr_kind in [
            tag.null_ptr, tag.null_unique_ptr, tag.null_shared_ptr
    ]:
        with pytest.raises(TypeError) as excinfo:
            m.TestFactory3(null_ptr_kind)
        assert (str(excinfo.value) ==
                "pybind11::init(): factory function returned nullptr")

    assert [i.alive() for i in cstats] == [3, 3, 3]
    assert ConstructorStats.detail_reg_inst() == n_inst + 9

    del x1, y2, y3, z3
    assert [i.alive() for i in cstats] == [2, 2, 1]
    assert ConstructorStats.detail_reg_inst() == n_inst + 5
    del x2, x3, y1, z1, z2
    assert [i.alive() for i in cstats] == [0, 0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    assert [i.values() for i in cstats] == [
        ["3", "hi!"],
        ["7", "hi again"],
        ["42", "bye"],
    ]
    assert [i.default_constructions for i in cstats] == [1, 1, 1]
def test_mi_unaligned_base():
    """Returning an offset (non-first MI) base class pointer should recognize the instance"""

    n_inst = ConstructorStats.detail_reg_inst()

    c = m.I801C()
    d = m.I801D()
    # + 4 below because we have the two instances, and each instance has offset base I801B2
    assert ConstructorStats.detail_reg_inst() == n_inst + 4
    b1c = m.i801b1_c(c)
    assert b1c is c
    b2c = m.i801b2_c(c)
    assert b2c is c
    b1d = m.i801b1_d(d)
    assert b1d is d
    b2d = m.i801b2_d(d)
    assert b2d is d

    assert ConstructorStats.detail_reg_inst() == n_inst + 4  # no extra instances
    del c, b1c, b2c
    assert ConstructorStats.detail_reg_inst() == n_inst + 2
    del d, b1d, b2d
    assert ConstructorStats.detail_reg_inst() == n_inst
Beispiel #25
0
def test_keep_alive_argument(capture):
    n_inst = ConstructorStats.detail_reg_inst()
    with capture:
        p = m.Parent()
    assert capture == "Allocating parent."
    with capture:
        p.addChild(m.Child())
        assert ConstructorStats.detail_reg_inst() == n_inst + 1
    assert (capture == """
        Allocating child.
        Releasing child.
    """)
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert capture == "Releasing parent."

    with capture:
        p = m.Parent()
    assert capture == "Allocating parent."
    with capture:
        p.addChildKeepAlive(m.Child())
        assert ConstructorStats.detail_reg_inst() == n_inst + 2
    assert capture == "Allocating child."
    with capture:
        del p
        assert ConstructorStats.detail_reg_inst() == n_inst
    assert (capture == """
        Releasing parent.
        Releasing child.
    """)

    p = m.Parent()
    c = m.Child()
    assert ConstructorStats.detail_reg_inst() == n_inst + 2
    m.free_function(p, c)
    del c
    assert ConstructorStats.detail_reg_inst() == n_inst + 2
    del p
    assert ConstructorStats.detail_reg_inst() == n_inst

    with pytest.raises(RuntimeError) as excinfo:
        m.invalid_arg_index()
    assert str(excinfo.value) == "Could not activate keep_alive!"
def test_init_factory_basic():
    """Tests py::init_factory() wrapper around various ways of returning the object"""

    cstats = [ConstructorStats.get(c) for c in [m.TestFactory1, m.TestFactory2, m.TestFactory3]]
    cstats[0].alive()  # force gc
    n_inst = ConstructorStats.detail_reg_inst()

    x1 = m.TestFactory1(tag.unique_ptr, 3)
    assert x1.value == "3"
    y1 = m.TestFactory1(tag.pointer)
    assert y1.value == "(empty)"
    z1 = m.TestFactory1("hi!")
    assert z1.value == "hi!"

    assert ConstructorStats.detail_reg_inst() == n_inst + 3

    x2 = m.TestFactory2(tag.move)
    assert x2.value == "(empty2)"
    y2 = m.TestFactory2(tag.pointer, 7)
    assert y2.value == "7"
    z2 = m.TestFactory2(tag.unique_ptr, "hi again")
    assert z2.value == "hi again"

    assert ConstructorStats.detail_reg_inst() == n_inst + 6

    x3 = m.TestFactory3(tag.shared_ptr)
    assert x3.value == "(empty3)"
    y3 = m.TestFactory3(tag.pointer, 42)
    assert y3.value == "42"
    z3 = m.TestFactory3("bye")
    assert z3.value == "bye"

    with pytest.raises(TypeError) as excinfo:
        m.TestFactory3(tag.null_ptr)
    assert str(excinfo.value) == "pybind11::init(): factory function returned nullptr"

    assert [i.alive() for i in cstats] == [3, 3, 3]
    assert ConstructorStats.detail_reg_inst() == n_inst + 9

    del x1, y2, y3, z3
    assert [i.alive() for i in cstats] == [2, 2, 1]
    assert ConstructorStats.detail_reg_inst() == n_inst + 5
    del x2, x3, y1, z1, z2
    assert [i.alive() for i in cstats] == [0, 0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    assert [i.values() for i in cstats] == [
        ["3", "hi!"],
        ["7", "hi again"],
        ["42", "bye"]
    ]
    assert [i.default_constructions for i in cstats] == [1, 1, 1]
def test_init_factory_casting():
    """Tests py::init_factory() wrapper with various upcasting and downcasting returns"""

    cstats = [
        ConstructorStats.get(c)
        for c in [m.TestFactory3, m.TestFactory4, m.TestFactory5]
    ]
    cstats[0].alive()  # force gc
    n_inst = ConstructorStats.detail_reg_inst()

    # Construction from derived references:
    a = m.TestFactory3(tag.pointer, tag.TF4, 4)
    assert a.value == "4"
    b = m.TestFactory3(tag.shared_ptr, tag.TF4, 5)
    assert b.value == "5"
    c = m.TestFactory3(tag.pointer, tag.TF5, 6)
    assert c.value == "6"
    d = m.TestFactory3(tag.shared_ptr, tag.TF5, 7)
    assert d.value == "7"

    assert ConstructorStats.detail_reg_inst() == n_inst + 4

    # Shared a lambda with TF3:
    e = m.TestFactory4(tag.pointer, tag.TF4, 8)
    assert e.value == "8"

    assert ConstructorStats.detail_reg_inst() == n_inst + 5
    assert [i.alive() for i in cstats] == [5, 3, 2]

    del a
    assert [i.alive() for i in cstats] == [4, 2, 2]
    assert ConstructorStats.detail_reg_inst() == n_inst + 4

    del b, c, e
    assert [i.alive() for i in cstats] == [1, 0, 1]
    assert ConstructorStats.detail_reg_inst() == n_inst + 1

    del d
    assert [i.alive() for i in cstats] == [0, 0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    assert [i.values() for i in cstats] == [
        ["4", "5", "6", "7", "8"],
        ["4", "5", "8"],
        ["6", "7"],
    ]
def test_init_factory_casting():
    """Tests py::init_factory() wrapper with various upcasting and downcasting returns"""

    cstats = [ConstructorStats.get(c) for c in [m.TestFactory3, m.TestFactory4, m.TestFactory5]]
    cstats[0].alive()  # force gc
    n_inst = ConstructorStats.detail_reg_inst()

    # Construction from derived references:
    a = m.TestFactory3(tag.pointer, tag.TF4, 4)
    assert a.value == "4"
    b = m.TestFactory3(tag.shared_ptr, tag.TF4, 5)
    assert b.value == "5"
    c = m.TestFactory3(tag.pointer, tag.TF5, 6)
    assert c.value == "6"
    d = m.TestFactory3(tag.shared_ptr, tag.TF5, 7)
    assert d.value == "7"

    assert ConstructorStats.detail_reg_inst() == n_inst + 4

    # Shared a lambda with TF3:
    e = m.TestFactory4(tag.pointer, tag.TF4, 8)
    assert e.value == "8"

    assert ConstructorStats.detail_reg_inst() == n_inst + 5
    assert [i.alive() for i in cstats] == [5, 3, 2]

    del a
    assert [i.alive() for i in cstats] == [4, 2, 2]
    assert ConstructorStats.detail_reg_inst() == n_inst + 4

    del b, c, e
    assert [i.alive() for i in cstats] == [1, 0, 1]
    assert ConstructorStats.detail_reg_inst() == n_inst + 1

    del d
    assert [i.alive() for i in cstats] == [0, 0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    assert [i.values() for i in cstats] == [
        ["4", "5", "6", "7", "8"],
        ["4", "5", "8"],
        ["6", "7"]
    ]
def test_init_factory_alias():
    """Tests py::init_factory() wrapper with value conversions and alias types"""

    cstats = [m.TestFactory6.get_cstats(), m.TestFactory6.get_alias_cstats()]
    cstats[0].alive()  # force gc
    n_inst = ConstructorStats.detail_reg_inst()

    a = m.TestFactory6(tag.base, 1)
    assert a.get() == 1
    assert not a.has_alias()
    b = m.TestFactory6(tag.alias, "hi there")
    assert b.get() == 8
    assert b.has_alias()
    c = m.TestFactory6(tag.alias, 3)
    assert c.get() == 3
    assert c.has_alias()
    d = m.TestFactory6(tag.alias, tag.pointer, 4)
    assert d.get() == 4
    assert d.has_alias()
    e = m.TestFactory6(tag.base, tag.pointer, 5)
    assert e.get() == 5
    assert not e.has_alias()
    f = m.TestFactory6(tag.base, tag.alias, tag.pointer, 6)
    assert f.get() == 6
    assert f.has_alias()

    assert ConstructorStats.detail_reg_inst() == n_inst + 6
    assert [i.alive() for i in cstats] == [6, 4]

    del a, b, e
    assert [i.alive() for i in cstats] == [3, 3]
    assert ConstructorStats.detail_reg_inst() == n_inst + 3
    del f, c, d
    assert [i.alive() for i in cstats] == [0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    class MyTest(m.TestFactory6):
        def __init__(self, *args):
            m.TestFactory6.__init__(self, *args)

        def get(self):
            return -5 + m.TestFactory6.get(self)

    # Return Class by value, moved into new alias:
    z = MyTest(tag.base, 123)
    assert z.get() == 118
    assert z.has_alias()

    # Return alias by value, moved into new alias:
    y = MyTest(tag.alias, "why hello!")
    assert y.get() == 5
    assert y.has_alias()

    # Return Class by pointer, moved into new alias then original destroyed:
    x = MyTest(tag.base, tag.pointer, 47)
    assert x.get() == 42
    assert x.has_alias()

    assert ConstructorStats.detail_reg_inst() == n_inst + 3
    assert [i.alive() for i in cstats] == [3, 3]
    del x, y, z
    assert [i.alive() for i in cstats] == [0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    assert [i.values() for i in cstats] == [[
        "1", "8", "3", "4", "5", "6", "123", "10", "47"
    ], ["hi there", "3", "4", "6", "move", "123", "why hello!", "move", "47"]]
def test_init_factory_dual():
    """Tests init factory functions with dual main/alias factory functions"""
    from pybind11_tests.factory_constructors import TestFactory7

    cstats = [TestFactory7.get_cstats(), TestFactory7.get_alias_cstats()]
    cstats[0].alive()  # force gc
    n_inst = ConstructorStats.detail_reg_inst()

    class PythFactory7(TestFactory7):
        def get(self):
            return 100 + TestFactory7.get(self)

    a1 = TestFactory7(1)
    a2 = PythFactory7(2)
    assert a1.get() == 1
    assert a2.get() == 102
    assert not a1.has_alias()
    assert a2.has_alias()

    b1 = TestFactory7(tag.pointer, 3)
    b2 = PythFactory7(tag.pointer, 4)
    assert b1.get() == 3
    assert b2.get() == 104
    assert not b1.has_alias()
    assert b2.has_alias()

    c1 = TestFactory7(tag.mixed, 5)
    c2 = PythFactory7(tag.mixed, 6)
    assert c1.get() == 5
    assert c2.get() == 106
    assert not c1.has_alias()
    assert c2.has_alias()

    d1 = TestFactory7(tag.base, tag.pointer, 7)
    d2 = PythFactory7(tag.base, tag.pointer, 8)
    assert d1.get() == 7
    assert d2.get() == 108
    assert not d1.has_alias()
    assert d2.has_alias()

    # Both return an alias; the second multiplies the value by 10:
    e1 = TestFactory7(tag.alias, tag.pointer, 9)
    e2 = PythFactory7(tag.alias, tag.pointer, 10)
    assert e1.get() == 9
    assert e2.get() == 200
    assert e1.has_alias()
    assert e2.has_alias()

    f1 = TestFactory7(tag.shared_ptr, tag.base, 11)
    f2 = PythFactory7(tag.shared_ptr, tag.base, 12)
    assert f1.get() == 11
    assert f2.get() == 112
    assert not f1.has_alias()
    assert f2.has_alias()

    g1 = TestFactory7(tag.shared_ptr, tag.invalid_base, 13)
    assert g1.get() == 13
    assert not g1.has_alias()
    with pytest.raises(TypeError) as excinfo:
        PythFactory7(tag.shared_ptr, tag.invalid_base, 14)
    assert (str(excinfo.value) ==
            "pybind11::init(): construction failed: returned holder-wrapped instance is not an "
            "alias instance")

    assert [i.alive() for i in cstats] == [13, 7]
    assert ConstructorStats.detail_reg_inst() == n_inst + 13

    del a1, a2, b1, d1, e1, e2
    assert [i.alive() for i in cstats] == [7, 4]
    assert ConstructorStats.detail_reg_inst() == n_inst + 7
    del b2, c1, c2, d2, f1, f2, g1
    assert [i.alive() for i in cstats] == [0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    assert [i.values() for i in cstats] == [
        ["1", "2", "3", "4", "5", "6", "7", "8", "9", "100", "11", "12", "13", "14"],
        ["2", "4", "6", "8", "9", "100", "12"]
    ]
def test_init_factory_dual():
    """Tests init factory functions with dual main/alias factory functions"""
    from pybind11_tests.factory_constructors import TestFactory7

    cstats = [TestFactory7.get_cstats(), TestFactory7.get_alias_cstats()]
    cstats[0].alive()  # force gc
    n_inst = ConstructorStats.detail_reg_inst()

    class PythFactory7(TestFactory7):
        def get(self):
            return 100 + TestFactory7.get(self)

    a1 = TestFactory7(1)
    a2 = PythFactory7(2)
    assert a1.get() == 1
    assert a2.get() == 102
    assert not a1.has_alias()
    assert a2.has_alias()

    b1 = TestFactory7(tag.pointer, 3)
    b2 = PythFactory7(tag.pointer, 4)
    assert b1.get() == 3
    assert b2.get() == 104
    assert not b1.has_alias()
    assert b2.has_alias()

    c1 = TestFactory7(tag.mixed, 5)
    c2 = PythFactory7(tag.mixed, 6)
    assert c1.get() == 5
    assert c2.get() == 106
    assert not c1.has_alias()
    assert c2.has_alias()

    d1 = TestFactory7(tag.base, tag.pointer, 7)
    d2 = PythFactory7(tag.base, tag.pointer, 8)
    assert d1.get() == 7
    assert d2.get() == 108
    assert not d1.has_alias()
    assert d2.has_alias()

    # Both return an alias; the second multiplies the value by 10:
    e1 = TestFactory7(tag.alias, tag.pointer, 9)
    e2 = PythFactory7(tag.alias, tag.pointer, 10)
    assert e1.get() == 9
    assert e2.get() == 200
    assert e1.has_alias()
    assert e2.has_alias()

    f1 = TestFactory7(tag.shared_ptr, tag.base, 11)
    f2 = PythFactory7(tag.shared_ptr, tag.base, 12)
    assert f1.get() == 11
    assert f2.get() == 112
    assert not f1.has_alias()
    assert f2.has_alias()

    g1 = TestFactory7(tag.shared_ptr, tag.invalid_base, 13)
    assert g1.get() == 13
    assert not g1.has_alias()
    with pytest.raises(TypeError) as excinfo:
        PythFactory7(tag.shared_ptr, tag.invalid_base, 14)
    assert (
        str(excinfo.value) ==
        "pybind11::init(): construction failed: returned holder-wrapped instance is not an "
        "alias instance")

    assert [i.alive() for i in cstats] == [13, 7]
    assert ConstructorStats.detail_reg_inst() == n_inst + 13

    del a1, a2, b1, d1, e1, e2
    assert [i.alive() for i in cstats] == [7, 4]
    assert ConstructorStats.detail_reg_inst() == n_inst + 7
    del b2, c1, c2, d2, f1, f2, g1
    assert [i.alive() for i in cstats] == [0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    assert [i.values() for i in cstats] == [[
        "1", "2", "3", "4", "5", "6", "7", "8", "9", "100", "11", "12", "13",
        "14"
    ], ["2", "4", "6", "8", "9", "100", "12"]]
def test_init_factory_alias():
    """Tests py::init_factory() wrapper with value conversions and alias types"""

    cstats = [m.TestFactory6.get_cstats(), m.TestFactory6.get_alias_cstats()]
    cstats[0].alive()  # force gc
    n_inst = ConstructorStats.detail_reg_inst()

    a = m.TestFactory6(tag.base, 1)
    assert a.get() == 1
    assert not a.has_alias()
    b = m.TestFactory6(tag.alias, "hi there")
    assert b.get() == 8
    assert b.has_alias()
    c = m.TestFactory6(tag.alias, 3)
    assert c.get() == 3
    assert c.has_alias()
    d = m.TestFactory6(tag.alias, tag.pointer, 4)
    assert d.get() == 4
    assert d.has_alias()
    e = m.TestFactory6(tag.base, tag.pointer, 5)
    assert e.get() == 5
    assert not e.has_alias()
    f = m.TestFactory6(tag.base, tag.alias, tag.pointer, 6)
    assert f.get() == 6
    assert f.has_alias()

    assert ConstructorStats.detail_reg_inst() == n_inst + 6
    assert [i.alive() for i in cstats] == [6, 4]

    del a, b, e
    assert [i.alive() for i in cstats] == [3, 3]
    assert ConstructorStats.detail_reg_inst() == n_inst + 3
    del f, c, d
    assert [i.alive() for i in cstats] == [0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    class MyTest(m.TestFactory6):
        def __init__(self, *args):
            m.TestFactory6.__init__(self, *args)

        def get(self):
            return -5 + m.TestFactory6.get(self)

    # Return Class by value, moved into new alias:
    z = MyTest(tag.base, 123)
    assert z.get() == 118
    assert z.has_alias()

    # Return alias by value, moved into new alias:
    y = MyTest(tag.alias, "why hello!")
    assert y.get() == 5
    assert y.has_alias()

    # Return Class by pointer, moved into new alias then original destroyed:
    x = MyTest(tag.base, tag.pointer, 47)
    assert x.get() == 42
    assert x.has_alias()

    assert ConstructorStats.detail_reg_inst() == n_inst + 3
    assert [i.alive() for i in cstats] == [3, 3]
    del x, y, z
    assert [i.alive() for i in cstats] == [0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    assert [i.values() for i in cstats] == [
        ["1", "8", "3", "4", "5", "6", "123", "10", "47"],
        ["hi there", "3", "4", "6", "move", "123", "why hello!", "move", "47"]
    ]