Skip to content

Commit 2fb3d7c

Browse files
authored
Trivial refactoring to make the capsule API more user friendly. (#4720)
* Trivial refactoring to make the capsule API more user friendly. * Use new API in production code. Thanks @lalaland for pointing this out.
1 parent e10da79 commit 2fb3d7c

File tree

4 files changed

+54
-21
lines changed

4 files changed

+54
-21
lines changed

include/pybind11/pybind11.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,8 @@ class cpp_function : public function {
508508
rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS;
509509

510510
capsule rec_capsule(unique_rec.release(),
511+
detail::get_function_record_capsule_name(),
511512
[](void *ptr) { destruct((detail::function_record *) ptr); });
512-
rec_capsule.set_name(detail::get_function_record_capsule_name());
513513
guarded_strdup.release();
514514

515515
object scope_module;

include/pybind11/pytypes.h

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,28 +1925,13 @@ class capsule : public object {
19251925
}
19261926
}
19271927

1928+
/// Capsule name is nullptr.
19281929
capsule(const void *value, void (*destructor)(void *)) {
1929-
m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) {
1930-
// guard if destructor called while err indicator is set
1931-
error_scope error_guard;
1932-
auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
1933-
if (destructor == nullptr && PyErr_Occurred()) {
1934-
throw error_already_set();
1935-
}
1936-
const char *name = get_name_in_error_scope(o);
1937-
void *ptr = PyCapsule_GetPointer(o, name);
1938-
if (ptr == nullptr) {
1939-
throw error_already_set();
1940-
}
1941-
1942-
if (destructor != nullptr) {
1943-
destructor(ptr);
1944-
}
1945-
});
1930+
initialize_with_void_ptr_destructor(value, nullptr, destructor);
1931+
}
19461932

1947-
if (!m_ptr || PyCapsule_SetContext(m_ptr, reinterpret_cast<void *>(destructor)) != 0) {
1948-
throw error_already_set();
1949-
}
1933+
capsule(const void *value, const char *name, void (*destructor)(void *)) {
1934+
initialize_with_void_ptr_destructor(value, name, destructor);
19501935
}
19511936

19521937
explicit capsule(void (*destructor)()) {
@@ -2014,6 +1999,32 @@ class capsule : public object {
20141999

20152000
return name;
20162001
}
2002+
2003+
void initialize_with_void_ptr_destructor(const void *value,
2004+
const char *name,
2005+
void (*destructor)(void *)) {
2006+
m_ptr = PyCapsule_New(const_cast<void *>(value), name, [](PyObject *o) {
2007+
// guard if destructor called while err indicator is set
2008+
error_scope error_guard;
2009+
auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
2010+
if (destructor == nullptr && PyErr_Occurred()) {
2011+
throw error_already_set();
2012+
}
2013+
const char *name = get_name_in_error_scope(o);
2014+
void *ptr = PyCapsule_GetPointer(o, name);
2015+
if (ptr == nullptr) {
2016+
throw error_already_set();
2017+
}
2018+
2019+
if (destructor != nullptr) {
2020+
destructor(ptr);
2021+
}
2022+
});
2023+
2024+
if (!m_ptr || PyCapsule_SetContext(m_ptr, reinterpret_cast<void *>(destructor)) != 0) {
2025+
throw error_already_set();
2026+
}
2027+
}
20172028
};
20182029

20192030
class tuple : public object {

tests/test_pytypes.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,15 @@ TEST_SUBMODULE(pytypes, m) {
260260
});
261261
});
262262

263+
m.def("return_capsule_with_destructor_3", []() {
264+
py::print("creating capsule");
265+
auto cap = py::capsule((void *) 1233, "oname", [](void *ptr) {
266+
py::print("destructing capsule: {}"_s.format((size_t) ptr));
267+
});
268+
py::print("original name: {}"_s.format(cap.name()));
269+
return cap;
270+
});
271+
263272
m.def("return_renamed_capsule_with_destructor_2", []() {
264273
py::print("creating capsule");
265274
auto cap = py::capsule((void *) 1234, [](void *ptr) {

tests/test_pytypes.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,19 @@ def test_capsule(capture):
319319
"""
320320
)
321321

322+
with capture:
323+
a = m.return_capsule_with_destructor_3()
324+
del a
325+
pytest.gc_collect()
326+
assert (
327+
capture.unordered
328+
== """
329+
creating capsule
330+
destructing capsule: 1233
331+
original name: oname
332+
"""
333+
)
334+
322335
with capture:
323336
a = m.return_renamed_capsule_with_destructor_2()
324337
del a

0 commit comments

Comments
 (0)