Skip to content

Commit 13d8cd2

Browse files
phaustinjagerman
authored andcommitted
add the capsule name to the py::capsule constructor
This allows named capsules to be constructed with `py::capsule`.
1 parent 28f3df7 commit 13d8cd2

File tree

3 files changed

+32
-4
lines changed

3 files changed

+32
-4
lines changed

include/pybind11/pytypes.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,8 +1016,8 @@ class capsule : public object {
10161016
PYBIND11_DEPRECATED("Use reinterpret_borrow<capsule>() or reinterpret_steal<capsule>()")
10171017
capsule(PyObject *ptr, bool is_borrowed) : object(is_borrowed ? object(ptr, borrowed_t{}) : object(ptr, stolen_t{})) { }
10181018

1019-
explicit capsule(const void *value)
1020-
: object(PyCapsule_New(const_cast<void *>(value), nullptr, nullptr), stolen_t{}) {
1019+
explicit capsule(const void *value, const char *name = nullptr, void (*destructor)(PyObject *) = nullptr)
1020+
: object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {
10211021
if (!m_ptr)
10221022
pybind11_fail("Could not allocate capsule object!");
10231023
}
@@ -1054,10 +1054,13 @@ class capsule : public object {
10541054
}
10551055

10561056
template <typename T> operator T *() const {
1057-
T * result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, nullptr));
1057+
auto name = this->name();
1058+
T * result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name));
10581059
if (!result) pybind11_fail("Unable to extract capsule contents!");
10591060
return result;
10601061
}
1062+
1063+
const char *name() const { return PyCapsule_GetName(m_ptr); }
10611064
};
10621065

10631066
class tuple : public object {

tests/test_python_types.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,22 @@ test_initializer python_types([](py::module &m) {
573573
}
574574
);
575575

576+
m.def("return_capsule_with_name_and_destructor_3",
577+
[]() {
578+
py::print("creating capsule");
579+
auto capsule=py::capsule((void *) 1234, "pointer type description",
580+
[](PyObject *ptr) {
581+
if (ptr) {
582+
py::print("destructing capsule");
583+
}
584+
});
585+
auto name = capsule.name();
586+
void *contents = capsule;
587+
py::print("created capsule with name --{}-- and contents {}"_s.format(name,(size_t) contents));
588+
return capsule;
589+
}
590+
);
591+
576592
m.def("load_nullptr_t", [](std::nullptr_t) {}); // not useful, but it should still compile
577593
m.def("cast_nullptr_t", []() { return std::nullptr_t{}; });
578594

tests/test_python_types.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,10 +603,19 @@ def test_capsule_with_destructor(capture):
603603
destructing capsule: 1234
604604
"""
605605

606+
with capture:
607+
a = m.return_capsule_with_name_and_destructor_3()
608+
del a
609+
pytest.gc_collect()
610+
assert capture.unordered == """
611+
created capsule with name --pointer type description-- and contents 1234
612+
creating capsule
613+
destructing capsule
614+
"""
615+
606616

607617
def test_void_caster():
608618
import pybind11_tests as m
609-
610619
assert m.load_nullptr_t(None) is None
611620
assert m.cast_nullptr_t() is None
612621

0 commit comments

Comments
 (0)