Merge branch 'master' into smart_holder

This commit is contained in:
Ralf W. Grosse-Kunstleve 2021-05-06 09:48:55 -07:00
commit 29e46381e4
3 changed files with 40 additions and 1 deletions

View File

@ -182,6 +182,9 @@ relies on the ability to create a *weak reference* to the nurse object. When
the nurse object is not a pybind11-registered type and does not support weak the nurse object is not a pybind11-registered type and does not support weak
references, an exception will be thrown. references, an exception will be thrown.
If you use an incorrect argument index, you will get a ``RuntimeError`` saying
``Could not activate keep_alive!``. You should review the indices you're using.
Consider the following example: here, the binding code for a list append Consider the following example: here, the binding code for a list append
operation ties the lifetime of the newly added element to the underlying operation ties the lifetime of the newly added element to the underlying
container: container:

View File

@ -51,6 +51,7 @@ TEST_SUBMODULE(call_policies, m) {
void addChild(Child *) { } void addChild(Child *) { }
Child *returnChild() { return new Child(); } Child *returnChild() { return new Child(); }
Child *returnNullChild() { return nullptr; } Child *returnNullChild() { return nullptr; }
static Child *staticFunction(Parent*) { return new Child(); }
}; };
py::class_<Parent>(m, "Parent") py::class_<Parent>(m, "Parent")
.def(py::init<>()) .def(py::init<>())
@ -60,7 +61,12 @@ TEST_SUBMODULE(call_policies, m) {
.def("returnChild", &Parent::returnChild) .def("returnChild", &Parent::returnChild)
.def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>()) .def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>())
.def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>()) .def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>())
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>()); .def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>())
.def_static(
"staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>());
m.def("free_function", [](Parent*, Child*) {}, py::keep_alive<1, 2>());
m.def("invalid_arg_index", []{}, py::keep_alive<0, 1>());
#if !defined(PYPY_VERSION) #if !defined(PYPY_VERSION)
// test_alive_gc // test_alive_gc

View File

@ -46,6 +46,19 @@ def test_keep_alive_argument(capture):
""" """
) )
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_keep_alive_return_value(capture): def test_keep_alive_return_value(capture):
n_inst = ConstructorStats.detail_reg_inst() n_inst = ConstructorStats.detail_reg_inst()
@ -85,6 +98,23 @@ def test_keep_alive_return_value(capture):
""" """
) )
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.
"""
)
# https://foss.heptapod.net/pypy/pypy/-/issues/2447 # https://foss.heptapod.net/pypy/pypy/-/issues/2447
@pytest.mark.xfail("env.PYPY", reason="_PyObject_GetDictPtr is unimplemented") @pytest.mark.xfail("env.PYPY", reason="_PyObject_GetDictPtr is unimplemented")