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."
def test_pointers(msg): from pybind11_tests import (return_void_ptr, get_void_ptr_value, ExampleMandA, print_opaque_list, return_null_str, get_null_str_value, return_unique_ptr, ConstructorStats) living_before = ConstructorStats.get(ExampleMandA).alive() assert get_void_ptr_value(return_void_ptr()) == 0x1234 assert get_void_ptr_value(ExampleMandA()) # Should also work for other C++ types assert ConstructorStats.get(ExampleMandA).alive() == living_before with pytest.raises(TypeError) as excinfo: get_void_ptr_value([1, 2, 3]) # This should not work assert msg(excinfo.value) == """ get_void_ptr_value(): incompatible function arguments. The following argument types are supported: 1. (arg0: capsule) -> int Invoked with: [1, 2, 3] """ # noqa: E501 line too long assert return_null_str() is None assert get_null_str_value(return_null_str()) is not None ptr = return_unique_ptr() assert "StringList" in repr(ptr) assert print_opaque_list(ptr) == "Opaque list: [some value]"
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 == """
def test_reference_internal(): from pybind11_tests import ConstructorStats from pybind11_tests.submodule import A, B b = B() assert str(b.get_a1()) == "A[1]" assert str(b.a1) == "A[1]" assert str(b.get_a2()) == "A[2]" assert str(b.a2) == "A[2]" b.a1 = A(42) b.a2 = A(43) assert str(b.get_a1()) == "A[42]" assert str(b.a1) == "A[42]" assert str(b.get_a2()) == "A[43]" assert str(b.a2) == "A[43]" astats, bstats = ConstructorStats.get(A), ConstructorStats.get(B) assert astats.alive() == 2 assert bstats.alive() == 1 del b assert astats.alive() == 0 assert bstats.alive() == 0 assert astats.values() == ['1', '2', '42', '43'] assert bstats.values() == [] assert astats.default_constructions == 0 assert bstats.default_constructions == 1 assert astats.copy_constructions == 0 assert bstats.copy_constructions == 0 # assert astats.move_constructions >= 0 # Don't invoke any # assert bstats.move_constructions >= 0 # Don't invoke any assert astats.copy_assignments == 2 assert bstats.copy_assignments == 0 assert astats.move_assignments == 0 assert bstats.move_assignments == 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_unique_nodelete(): from pybind11_tests import MyObject4 o = MyObject4(23) assert o.value == 23 cstats = ConstructorStats.get(MyObject4) assert cstats.alive() == 1 del o cstats = ConstructorStats.get(MyObject4) assert cstats.alive() == 1 # Leak, but that's intentional
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 == """
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_stl_ownership(): cstats = ConstructorStats.get(m.Placeholder) assert cstats.alive() == 0 r = m.test_stl_ownership() assert len(r) == 1 del r assert cstats.alive() == 0
def test_to_python(): m = Matrix(5, 5) assert m[2, 3] == 0 m[2, 3] = 4 assert m[2, 3] == 4 m2 = np.array(m, copy=False) assert m2.shape == (5, 5) assert abs(m2).sum() == 4 assert m2[2, 3] == 4 m2[2, 3] = 5 assert m2[2, 3] == 5 cstats = ConstructorStats.get(Matrix) assert cstats.alive() == 1 del m pytest.gc_collect() assert cstats.alive() == 1 del m2 # holds an m reference pytest.gc_collect() assert cstats.alive() == 0 assert cstats.values() == ["5x5 matrix"] assert cstats.copy_constructions == 0 # assert cstats.move_constructions >= 0 # Don't invoke any assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0
def test_shared_ptr_and_references(): from pybind11_tests.smart_ptr import SharedPtrRef, A s = SharedPtrRef() stats = ConstructorStats.get(A) assert stats.alive() == 2 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false) assert stats.alive() == 2 assert s.set_ref(ref) with pytest.raises(RuntimeError) as excinfo: assert s.set_holder(ref) assert "Unable to cast from non-held to held instance" in str(excinfo.value) copy = s.copy # init_holder_helper(holder_ptr=false, owned=true) assert stats.alive() == 3 assert s.set_ref(copy) assert s.set_holder(copy) holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false) assert stats.alive() == 3 assert s.set_ref(holder_ref) assert s.set_holder(holder_ref) holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true) assert stats.alive() == 3 assert s.set_ref(holder_copy) assert s.set_holder(holder_copy) del ref, copy, holder_ref, holder_copy, s assert stats.alive() == 0
def test_unique_nodelete(): o = m.MyObject4(23) assert o.value == 23 cstats = ConstructorStats.get(m.MyObject4) assert cstats.alive() == 1 del o assert cstats.alive() == 1 # Leak, but that's intentional
def test_large_holder(): o = m.MyObject5(5) assert o.value == 5 cstats = ConstructorStats.get(m.MyObject5) assert cstats.alive() == 1 del o assert cstats.alive() == 0
def test_holder_with_addressof_operator(): # this test must not throw exception from c++ a = m.TypeForHolderWithAddressOf.make() a.print_object_1() a.print_object_2() a.print_object_3() a.print_object_4() stats = ConstructorStats.get(m.TypeForHolderWithAddressOf) assert stats.alive() == 1 np = m.TypeForHolderWithAddressOf.make() assert stats.alive() == 2 del a assert stats.alive() == 1 del np assert stats.alive() == 0 b = m.TypeForHolderWithAddressOf.make() c = b assert b.get() is c.get() assert stats.alive() == 1 del b assert stats.alive() == 1 del c assert stats.alive() == 0
def test_to_python(): mat = m.Matrix(5, 5) assert memoryview(mat).shape == (5, 5) assert mat[2, 3] == 0 mat[2, 3] = 4 assert mat[2, 3] == 4 mat2 = np.array(mat, copy=False) assert mat2.shape == (5, 5) assert abs(mat2).sum() == 4 assert mat2[2, 3] == 4 mat2[2, 3] = 5 assert mat2[2, 3] == 5 cstats = ConstructorStats.get(m.Matrix) assert cstats.alive() == 1 del mat pytest.gc_collect() assert cstats.alive() == 1 del mat2 # holds a mat reference pytest.gc_collect() assert cstats.alive() == 0 assert cstats.values() == ["5x5 matrix"] assert cstats.copy_constructions == 0 # assert cstats.move_constructions >= 0 # Don't invoke any assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0
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_methods_and_attributes(): instance1 = m.ExampleMandA() instance2 = m.ExampleMandA(32) instance1.add1(instance2) instance1.add2(instance2) instance1.add3(instance2) instance1.add4(instance2) instance1.add5(instance2) instance1.add6(32) instance1.add7(32) instance1.add8(32) instance1.add9(32) instance1.add10(32) assert str(instance1) == "ExampleMandA[value=320]" assert str(instance2) == "ExampleMandA[value=32]" assert str(instance1.self1()) == "ExampleMandA[value=320]" assert str(instance1.self2()) == "ExampleMandA[value=320]" assert str(instance1.self3()) == "ExampleMandA[value=320]" assert str(instance1.self4()) == "ExampleMandA[value=320]" assert str(instance1.self5()) == "ExampleMandA[value=320]" assert instance1.internal1() == 320 assert instance1.internal2() == 320 assert instance1.internal3() == 320 assert instance1.internal4() == 320 assert instance1.internal5() == 320 assert instance1.overloaded() == "()" assert instance1.overloaded(0) == "(int)" assert instance1.overloaded(1, 1.0) == "(int, float)" assert instance1.overloaded(2.0, 2) == "(float, int)" assert instance1.overloaded(3, 3) == "(int, int)" assert instance1.overloaded(4., 4.) == "(float, float)" assert instance1.overloaded_const(-3) == "(int) const" assert instance1.overloaded_const(5, 5.0) == "(int, float) const" assert instance1.overloaded_const(6.0, 6) == "(float, int) const" assert instance1.overloaded_const(7, 7) == "(int, int) const" assert instance1.overloaded_const(8., 8.) == "(float, float) const" assert instance1.overloaded_float(1, 1) == "(float, float)" assert instance1.overloaded_float(1, 1.) == "(float, float)" assert instance1.overloaded_float(1., 1) == "(float, float)" assert instance1.overloaded_float(1., 1.) == "(float, float)" assert instance1.value == 320 instance1.value = 100 assert str(instance1) == "ExampleMandA[value=100]" cstats = ConstructorStats.get(m.ExampleMandA) assert cstats.alive() == 2 del instance1, instance2 assert cstats.alive() == 0 assert cstats.values() == ["32"] assert cstats.default_constructions == 1 assert cstats.copy_constructions == 3 assert cstats.move_constructions >= 1 assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0
def test_large_holder(): from pybind11_tests import MyObject5 o = MyObject5(5) assert o.value == 5 cstats = ConstructorStats.get(MyObject5) assert cstats.alive() == 1 del o assert cstats.alive() == 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. """)
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 == """ Releasing parent. Releasing child. """)
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_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_move_only_holder(): from pybind11_tests.smart_ptr import TypeWithMoveOnlyHolder a = TypeWithMoveOnlyHolder.make() stats = ConstructorStats.get(TypeWithMoveOnlyHolder) assert stats.alive() == 1 del a assert stats.alive() == 0
def test_move_support(): from pybind11_tests import NCVirt, NonCopyable, Movable class NCVirtExt(NCVirt): def get_noncopyable(self, a, b): # Constructs and returns a new instance: nc = NonCopyable(a * a, b * b) return nc def get_movable(self, a, b): # Return a referenced copy self.movable = Movable(a, b) return self.movable class NCVirtExt2(NCVirt): def get_noncopyable(self, a, b): # Keep a reference: this is going to throw an exception self.nc = NonCopyable(a, b) return self.nc def get_movable(self, a, b): # Return a new instance without storing it return Movable(a, b) ncv1 = NCVirtExt() assert ncv1.print_nc(2, 3) == "36" assert ncv1.print_movable(4, 5) == "9" ncv2 = NCVirtExt2() assert ncv2.print_movable(7, 7) == "14" # Don't check the exception message here because it differs under debug/non-debug mode with pytest.raises(RuntimeError): ncv2.print_nc(9, 9) nc_stats = ConstructorStats.get(NonCopyable) mv_stats = ConstructorStats.get(Movable) assert nc_stats.alive() == 1 assert mv_stats.alive() == 1 del ncv1, ncv2 assert nc_stats.alive() == 0 assert mv_stats.alive() == 0 assert nc_stats.values() == ['4', '9', '9', '9'] assert mv_stats.values() == ['4', '5', '7', '7'] assert nc_stats.copy_constructions == 0 assert mv_stats.copy_constructions == 1 assert nc_stats.move_constructions >= 0 assert mv_stats.move_constructions >= 0
def test_mi_base_return(): """Tests returning an offset (non-first MI) base class pointer to a derived instance""" n_inst = ConstructorStats.detail_reg_inst() c1 = m.i801c_b1() assert type(c1) is m.I801C assert c1.a == 1 assert c1.b == 2 d1 = m.i801d_b1() assert type(d1) is m.I801D assert d1.a == 1 assert d1.b == 2 assert ConstructorStats.detail_reg_inst() == n_inst + 4 c2 = m.i801c_b2() assert type(c2) is m.I801C assert c2.a == 1 assert c2.b == 2 d2 = m.i801d_b2() assert type(d2) is m.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 = m.i801e_c() assert type(e1) is m.I801C assert e1.a == 1 assert e1.b == 2 e2 = m.i801e_b2() assert type(e2) is m.I801B2 assert e2.b == 2
def test_operator_overloading(): v1 = m.Vector2(1, 2) v2 = m.Vector(3, -1) assert str(v1) == "[1.000000, 2.000000]" assert str(v2) == "[3.000000, -1.000000]" assert str(-v2) == "[-3.000000, 1.000000]" assert str(v1 + v2) == "[4.000000, 1.000000]" assert str(v1 - v2) == "[-2.000000, 3.000000]" assert str(v1 - 8) == "[-7.000000, -6.000000]" assert str(v1 + 8) == "[9.000000, 10.000000]" assert str(v1 * 8) == "[8.000000, 16.000000]" assert str(v1 / 8) == "[0.125000, 0.250000]" assert str(8 - v1) == "[7.000000, 6.000000]" assert str(8 + v1) == "[9.000000, 10.000000]" assert str(8 * v1) == "[8.000000, 16.000000]" assert str(8 / v1) == "[8.000000, 4.000000]" assert str(v1 * v2) == "[3.000000, -2.000000]" assert str(v2 / v1) == "[3.000000, -0.500000]" v1 += 2 * v2 assert str(v1) == "[7.000000, 0.000000]" v1 -= v2 assert str(v1) == "[4.000000, 1.000000]" v1 *= 2 assert str(v1) == "[8.000000, 2.000000]" v1 /= 16 assert str(v1) == "[0.500000, 0.125000]" v1 *= v2 assert str(v1) == "[1.500000, -0.125000]" v2 /= v1 assert str(v2) == "[2.000000, 8.000000]" assert hash(v1) == 4 cstats = ConstructorStats.get(m.Vector2) assert cstats.alive() == 2 del v1 assert cstats.alive() == 1 del v2 assert cstats.alive() == 0 assert cstats.values() == [ '[1.000000, 2.000000]', '[3.000000, -1.000000]', '[-3.000000, 1.000000]', '[4.000000, 1.000000]', '[-2.000000, 3.000000]', '[-7.000000, -6.000000]', '[9.000000, 10.000000]', '[8.000000, 16.000000]', '[0.125000, 0.250000]', '[7.000000, 6.000000]', '[9.000000, 10.000000]', '[8.000000, 16.000000]', '[8.000000, 4.000000]', '[3.000000, -2.000000]', '[3.000000, -0.500000]', '[6.000000, -2.000000]' ] assert cstats.default_constructions == 0 assert cstats.copy_constructions == 0 assert cstats.move_constructions >= 10 assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0
def test_unique_nodelete4a(): o = m.MyObject4a(23) assert o.value == 23 cstats = ConstructorStats.get(m.MyObject4a) assert cstats.alive() == 1 del o assert cstats.alive() == 1 m.MyObject4a.cleanup_all_instances() assert cstats.alive() == 0
def test_move_only_holder(): a = m.TypeWithMoveOnlyHolder.make() b = m.TypeWithMoveOnlyHolder.make_as_object() stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder) assert stats.alive() == 2 del b assert stats.alive() == 1 del a assert stats.alive() == 0
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_methods_and_attributes(): instance1 = ExampleMandA() instance2 = ExampleMandA(32) instance1.add1(instance2) instance1.add2(instance2) instance1.add3(instance2) instance1.add4(instance2) instance1.add5(instance2) instance1.add6(32) instance1.add7(32) instance1.add8(32) instance1.add9(32) instance1.add10(32) assert str(instance1) == "ExampleMandA[value=320]" assert str(instance2) == "ExampleMandA[value=32]" assert str(instance1.self1()) == "ExampleMandA[value=320]" assert str(instance1.self2()) == "ExampleMandA[value=320]" assert str(instance1.self3()) == "ExampleMandA[value=320]" assert str(instance1.self4()) == "ExampleMandA[value=320]" assert str(instance1.self5()) == "ExampleMandA[value=320]" assert instance1.internal1() == 320 assert instance1.internal2() == 320 assert instance1.internal3() == 320 assert instance1.internal4() == 320 assert instance1.internal5() == 320 assert instance1.overloaded(1, 1.0) == "(int, float)" assert instance1.overloaded(2.0, 2) == "(float, int)" assert instance1.overloaded(3, 3) == "(int, int)" assert instance1.overloaded(4., 4.) == "(float, float)" assert instance1.overloaded_const(5, 5.0) == "(int, float) const" assert instance1.overloaded_const(6.0, 6) == "(float, int) const" assert instance1.overloaded_const(7, 7) == "(int, int) const" assert instance1.overloaded_const(8., 8.) == "(float, float) const" assert instance1.overloaded_float(1, 1) == "(float, float)" assert instance1.overloaded_float(1, 1.) == "(float, float)" assert instance1.overloaded_float(1., 1) == "(float, float)" assert instance1.overloaded_float(1., 1.) == "(float, float)" assert instance1.value == 320 instance1.value = 100 assert str(instance1) == "ExampleMandA[value=100]" cstats = ConstructorStats.get(ExampleMandA) assert cstats.alive() == 2 del instance1, instance2 assert cstats.alive() == 0 assert cstats.values() == ["32"] assert cstats.default_constructions == 1 assert cstats.copy_constructions == 3 assert cstats.move_constructions >= 1 assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0
def test_move_only_holder(): from pybind11_tests.smart_ptr import TypeWithMoveOnlyHolder a = TypeWithMoveOnlyHolder.make() stats = ConstructorStats.get(TypeWithMoveOnlyHolder) if stats.alive() != 1: raise AssertionError del a if stats.alive() != 0: raise AssertionError
def test_dynamic_attributes(): from pybind11_tests import DynamicClass, CppDerivedDynamicClass instance = DynamicClass() if hasattr(instance, "foo"): raise AssertionError if "foo" in dir(instance): raise AssertionError # Dynamically add attribute instance.foo = 42 if not hasattr(instance, "foo"): raise AssertionError if instance.foo != 42: raise AssertionError if "foo" not in dir(instance): raise AssertionError # __dict__ should be accessible and replaceable if "foo" not in instance.__dict__: raise AssertionError instance.__dict__ = {"bar": True} if hasattr(instance, "foo"): raise AssertionError if not hasattr(instance, "bar"): raise AssertionError with pytest.raises(TypeError) as excinfo: instance.__dict__ = [] if str(excinfo.value ) != "__dict__ must be set to a dictionary, not a 'list'": raise AssertionError cstats = ConstructorStats.get(DynamicClass) if cstats.alive() != 1: raise AssertionError del instance if cstats.alive() != 0: raise AssertionError # Derived classes should work as well class PythonDerivedDynamicClass(DynamicClass): pass for cls in CppDerivedDynamicClass, PythonDerivedDynamicClass: derived = cls() derived.foobar = 100 if derived.foobar != 100: raise AssertionError if cstats.alive() != 1: raise AssertionError del derived if cstats.alive() != 0: raise AssertionError
def test_sequence(): from pybind11_tests import ConstructorStats from pybind11_tests.sequences_and_iterators import Sequence cstats = ConstructorStats.get(Sequence) s = Sequence(5) assert cstats.values() == ['of size', '5'] assert "Sequence" in repr(s) assert len(s) == 5 assert s[0] == 0 and s[3] == 0 assert 12.34 not in s s[0], s[3] = 12.34, 56.78 assert 12.34 in s assert isclose(s[0], 12.34) and isclose(s[3], 56.78) rev = reversed(s) assert cstats.values() == ['of size', '5'] rev2 = s[::-1] assert cstats.values() == ['of size', '5'] it = iter(Sequence(0)) for _ in range(3): # __next__ must continue to raise StopIteration with pytest.raises(StopIteration): next(it) assert cstats.values() == ['of size', '0'] expected = [0, 56.78, 0, 0, 12.34] assert allclose(rev, expected) assert allclose(rev2, expected) assert rev == rev2 rev[0::2] = Sequence([2.0, 2.0, 2.0]) assert cstats.values() == ['of size', '3', 'from std::vector'] assert allclose(rev, [2, 56.78, 2, 0, 2]) assert cstats.alive() == 4 del it assert cstats.alive() == 3 del s assert cstats.alive() == 2 del rev assert cstats.alive() == 1 del rev2 assert cstats.alive() == 0 assert cstats.values() == [] assert cstats.default_constructions == 0 assert cstats.copy_constructions == 0 assert cstats.move_constructions >= 1 assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0
def test_shared_ptr_from_this_and_references(): from pybind11_tests.smart_ptr import SharedFromThisRef, B s = SharedFromThisRef() stats = ConstructorStats.get(B) if stats.alive() != 2: raise AssertionError ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false) if stats.alive() != 2: raise AssertionError if not s.set_ref(ref): raise AssertionError if not s.set_holder(ref): raise AssertionError bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true) if stats.alive() != 2: raise AssertionError if not s.set_ref(bad_wp): raise AssertionError with pytest.raises(RuntimeError) as excinfo: if not s.set_holder(bad_wp): raise AssertionError if "Unable to cast from non-held to held instance" not in str( excinfo.value): raise AssertionError copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false) if stats.alive() != 3: raise AssertionError if not s.set_ref(copy): raise AssertionError if not s.set_holder(copy): raise AssertionError holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false) if stats.alive() != 3: raise AssertionError if not s.set_ref(holder_ref): raise AssertionError if not s.set_holder(holder_ref): raise AssertionError holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false) if stats.alive() != 3: raise AssertionError if not s.set_ref(holder_copy): raise AssertionError if not s.set_holder(holder_copy): raise AssertionError del ref, bad_wp, copy, holder_ref, holder_copy, s if stats.alive() != 0: raise AssertionError
def test_enable_shared_from_this_with_reference_rvp(): """ Issue #471: shared pointer instance not dellocated """ from pybind11_tests import SharedParent, SharedChild parent = SharedParent() child = parent.get_child() cstats = ConstructorStats.get(SharedChild) assert cstats.alive() == 1 del child, parent assert cstats.alive() == 0
def test_instance(msg): with pytest.raises(TypeError) as excinfo: m.NoConstructor() assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!" instance = m.NoConstructor.new_instance() cstats = ConstructorStats.get(m.NoConstructor) assert cstats.alive() == 1 del instance assert cstats.alive() == 0
def test_move_only_holder_with_addressof_operator(): a = m.TypeForMoveOnlyHolderWithAddressOf.make() a.print_object() stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf) assert stats.alive() == 1 a.value = 42 assert a.value == 42 del a assert stats.alive() == 0
def test_operator_overloading(): from pybind11_tests import Vector2, Vector, ConstructorStats v1 = Vector2(1, 2) v2 = Vector(3, -1) assert str(v1) == "[1.000000, 2.000000]" assert str(v2) == "[3.000000, -1.000000]" assert str(v1 + v2) == "[4.000000, 1.000000]" assert str(v1 - v2) == "[-2.000000, 3.000000]" assert str(v1 - 8) == "[-7.000000, -6.000000]" assert str(v1 + 8) == "[9.000000, 10.000000]" assert str(v1 * 8) == "[8.000000, 16.000000]" assert str(v1 / 8) == "[0.125000, 0.250000]" assert str(8 - v1) == "[7.000000, 6.000000]" assert str(8 + v1) == "[9.000000, 10.000000]" assert str(8 * v1) == "[8.000000, 16.000000]" assert str(8 / v1) == "[8.000000, 4.000000]" assert str(v1 * v2) == "[3.000000, -2.000000]" assert str(v2 / v1) == "[3.000000, -0.500000]" v1 += 2 * v2 assert str(v1) == "[7.000000, 0.000000]" v1 -= v2 assert str(v1) == "[4.000000, 1.000000]" v1 *= 2 assert str(v1) == "[8.000000, 2.000000]" v1 /= 16 assert str(v1) == "[0.500000, 0.125000]" v1 *= v2 assert str(v1) == "[1.500000, -0.125000]" v2 /= v1 assert str(v2) == "[2.000000, 8.000000]" cstats = ConstructorStats.get(Vector2) assert cstats.alive() == 2 del v1 assert cstats.alive() == 1 del v2 assert cstats.alive() == 0 assert cstats.values() == ['[1.000000, 2.000000]', '[3.000000, -1.000000]', '[4.000000, 1.000000]', '[-2.000000, 3.000000]', '[-7.000000, -6.000000]', '[9.000000, 10.000000]', '[8.000000, 16.000000]', '[0.125000, 0.250000]', '[7.000000, 6.000000]', '[9.000000, 10.000000]', '[8.000000, 16.000000]', '[8.000000, 4.000000]', '[3.000000, -2.000000]', '[3.000000, -0.500000]', '[6.000000, -2.000000]'] assert cstats.default_constructions == 0 assert cstats.copy_constructions == 0 assert cstats.move_constructions >= 10 assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0
def test_sequence(): cstats = ConstructorStats.get(m.Sequence) s = m.Sequence(5) assert cstats.values() == ["of size", "5"] assert "Sequence" in repr(s) assert len(s) == 5 assert s[0] == 0 and s[3] == 0 assert 12.34 not in s s[0], s[3] = 12.34, 56.78 assert 12.34 in s assert s[0] == approx(12.34, rel=1e-05) assert s[3] == approx(56.78, rel=1e-05) rev = reversed(s) assert cstats.values() == ["of size", "5"] rev2 = s[::-1] assert cstats.values() == ["of size", "5"] it = iter(m.Sequence(0)) for _ in range(3): # __next__ must continue to raise StopIteration with pytest.raises(StopIteration): next(it) assert cstats.values() == ["of size", "0"] expected = [0, 56.78, 0, 0, 12.34] assert rev == approx(expected, rel=1e-05) assert rev2 == approx(expected, rel=1e-05) assert rev == rev2 rev[0::2] = m.Sequence([2.0, 2.0, 2.0]) assert cstats.values() == ["of size", "3", "from std::vector"] assert rev == approx([2, 56.78, 2, 0, 2], rel=1e-05) assert cstats.alive() == 4 del it assert cstats.alive() == 3 del s assert cstats.alive() == 2 del rev assert cstats.alive() == 1 del rev2 assert cstats.alive() == 0 assert cstats.values() == [] assert cstats.default_constructions == 0 assert cstats.copy_constructions == 0 assert cstats.move_constructions >= 1 assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0
def test_shared_from_this_copy(): s = m.SharedFromThisRef() stats = ConstructorStats.get(m.B) assert stats.alive() == 2 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false) # RuntimeError: Invalid return_value_policy for shared_ptr. assert stats.alive() == 3 assert s.set_ref(copy) assert s.set_holder(copy) del copy, s assert stats.alive() == 0
def test_override(capture, msg): from pybind11_tests import (ExampleVirt, runExampleVirt, runExampleVirtVirtual, runExampleVirtBool) class ExtendedExampleVirt(ExampleVirt): def __init__(self, state): super(ExtendedExampleVirt, self).__init__(state + 1) self.data = "Hello world" def run(self, value): print('ExtendedExampleVirt::run(%i), calling parent..' % value) return super(ExtendedExampleVirt, self).run(value + 1) def run_bool(self): print('ExtendedExampleVirt::run_bool()') return False def pure_virtual(self): print('ExtendedExampleVirt::pure_virtual(): %s' % self.data) ex12 = ExampleVirt(10) with capture: assert runExampleVirt(ex12, 20) == 30 assert capture == "Original implementation of ExampleVirt::run(state=10, value=20)" with pytest.raises(RuntimeError) as excinfo: runExampleVirtVirtual(ex12) assert msg( excinfo.value ) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"' ex12p = ExtendedExampleVirt(10) with capture: assert runExampleVirt(ex12p, 20) == 32 assert capture == """ ExtendedExampleVirt::run(20), calling parent.. Original implementation of ExampleVirt::run(state=11, value=21) """ with capture: assert runExampleVirtBool(ex12p) is False assert capture == "ExtendedExampleVirt::run_bool()" with capture: runExampleVirtVirtual(ex12p) assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world" cstats = ConstructorStats.get(ExampleVirt) assert cstats.alive() == 2 del ex12, ex12p assert cstats.alive() == 0 assert cstats.values() == ['10', '11'] assert cstats.copy_constructions == 0 assert cstats.move_constructions >= 0
def test_shared_from_this_ref(): s = m.SharedFromThisRef() stats = ConstructorStats.get(m.B) assert stats.alive() == 2 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false) assert stats.alive() == 2 assert s.set_ref(ref) assert s.set_holder( ref ) # std::enable_shared_from_this can create a holder from a reference del ref, s assert stats.alive() == 0
def test_shared_from_this_bad_wp(): s = m.SharedFromThisRef() stats = ConstructorStats.get(m.B) assert stats.alive() == 2 bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true) assert stats.alive() == 2 assert s.set_ref(bad_wp) with pytest.raises(RuntimeError) as excinfo: assert s.set_holder(bad_wp) assert str(excinfo.value) == "Non-owning holder (loaded_as_shared_ptr)." del bad_wp, s assert stats.alive() == 0
def assert_keeps_alive(cl, method, *args): cstats = ConstructorStats.get(cl) start_with = cstats.alive() a = cl() assert cstats.alive() == start_with + 1 z = method(a, *args) assert cstats.alive() == start_with + 1 del a # Here's the keep alive in action: assert cstats.alive() == start_with + 1 del z # Keep alive should have expired: assert cstats.alive() == start_with
def test_pointers(msg): living_before = ConstructorStats.get(UserType).alive() assert m.get_void_ptr_value(m.return_void_ptr()) == 0x1234 assert m.get_void_ptr_value( UserType()) # Should also work for other C++ types assert ConstructorStats.get(UserType).alive() == living_before with pytest.raises(TypeError) as excinfo: m.get_void_ptr_value([1, 2, 3]) # This should not work assert msg(excinfo.value) == """ get_void_ptr_value(): incompatible function arguments. The following argument types are supported: 1. (arg0: capsule) -> int Invoked with: [1, 2, 3] """ # noqa: E501 line too long assert m.return_null_str() is None assert m.get_null_str_value(m.return_null_str()) is not None ptr = m.return_unique_ptr() assert "StringList" in repr(ptr) assert m.print_opaque_list(ptr) == "Opaque list: [some value]"
def test_shared_from_this_holder_ref(): s = m.SharedFromThisRef() stats = ConstructorStats.get(m.B) assert stats.alive() == 2 holder_ref = ( s.holder_ref ) # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false) assert stats.alive() == 2 assert s.set_ref(holder_ref) assert s.set_holder(holder_ref) del holder_ref, s assert stats.alive() == 0
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
def test_shared_ptr_from_this_and_references(): s = m.SharedFromThisRef() stats = ConstructorStats.get(m.B) assert stats.alive() == 2 ref = (s.ref ) # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false) assert stats.alive() == 2 assert s.set_ref(ref) assert s.set_holder( ref ) # std::enable_shared_from_this can create a holder from a reference bad_wp = ( s.bad_wp ) # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true) assert stats.alive() == 2 assert s.set_ref(bad_wp) with pytest.raises(RuntimeError) as excinfo: assert s.set_holder(bad_wp) assert "Unable to cast from non-held to held instance" in str( excinfo.value) copy = (s.copy ) # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false) assert stats.alive() == 3 assert s.set_ref(copy) assert s.set_holder(copy) holder_ref = ( s.holder_ref ) # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false) assert stats.alive() == 3 assert s.set_ref(holder_ref) assert s.set_holder(holder_ref) holder_copy = ( s.holder_copy ) # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false) assert stats.alive() == 3 assert s.set_ref(holder_copy) assert s.set_holder(holder_copy) del ref, bad_wp, copy, holder_ref, holder_copy, s assert stats.alive() == 0 z = m.SharedFromThisVirt.get() y = m.SharedFromThisVirt.get() assert y is z
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. """) p = m.Parent() assert ConstructorStats.detail_reg_inst() == n_inst + 1 with capture: m.Parent.staticFunction(p) 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_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_sequence(): from pybind11_tests import Sequence, ConstructorStats cstats = ConstructorStats.get(Sequence) s = Sequence(5) assert cstats.values() == ['of size', '5'] assert "Sequence" in repr(s) assert len(s) == 5 assert s[0] == 0 and s[3] == 0 assert 12.34 not in s s[0], s[3] = 12.34, 56.78 assert 12.34 in s assert isclose(s[0], 12.34) and isclose(s[3], 56.78) rev = reversed(s) assert cstats.values() == ['of size', '5'] rev2 = s[::-1] assert cstats.values() == ['of size', '5'] expected = [0, 56.78, 0, 0, 12.34] assert allclose(rev, expected) assert allclose(rev2, expected) assert rev == rev2 rev[0::2] = Sequence([2.0, 2.0, 2.0]) assert cstats.values() == ['of size', '3', 'from std::vector'] assert allclose(rev, [2, 56.78, 2, 0, 2]) assert cstats.alive() == 3 del s assert cstats.alive() == 2 del rev assert cstats.alive() == 1 del rev2 assert cstats.alive() == 0 assert cstats.values() == [] assert cstats.default_constructions == 0 assert cstats.copy_constructions == 0 assert cstats.move_constructions >= 1 assert cstats.copy_assignments == 0 assert cstats.move_assignments == 0