Skip to content

Commit 460369f

Browse files
Clean up tests + remove ifdef guards
1 parent d9ae582 commit 460369f

File tree

3 files changed

+27
-17
lines changed

3 files changed

+27
-17
lines changed

include/pybind11/functional.h

+8-10
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,14 @@ struct type_caster<std::function<Return(Args...)>> {
3838

3939
auto func = reinterpret_borrow<function>(src);
4040

41-
/*
42-
When passing a C++ function as an argument to another C++
43-
function via Python, every function call would normally involve
44-
a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
45-
Here, we try to at least detect the case where the function is
46-
stateless (i.e. function pointer or lambda function without
47-
captured variables), in which case the roundtrip can be avoided.
48-
*/
49-
#ifndef BAD
41+
/*
42+
When passing a C++ function as an argument to another C++
43+
function via Python, every function call would normally involve
44+
a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
45+
Here, we try to at least detect the case where the function is
46+
stateless (i.e. function pointer or lambda function without
47+
captured variables), in which case the roundtrip can be avoided.
48+
*/
5049
if (auto cfunc = func.cpp_function()) {
5150
auto *cfunc_self = PyCFunction_GET_SELF(cfunc.ptr());
5251
if (cfunc_self == nullptr) {
@@ -80,7 +79,6 @@ struct type_caster<std::function<Return(Args...)>> {
8079
// Raising an fail exception here works to prevent the segfault, but only on gcc.
8180
// See PR #1413 for full details
8281
}
83-
#endif
8482

8583
// ensure GIL is held during functor destruction
8684
struct func_handle {

tests/test_callbacks.cpp

+14-4
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,15 @@ TEST_SUBMODULE(callbacks, m) {
245245

246246
def.ml_name = "example_name";
247247
def.ml_doc = "Example doc";
248-
def.ml_meth = [](PyObject *, PyObject *) -> PyObject * {
249-
auto result = py::cast(20);
248+
def.ml_meth = [](PyObject *, PyObject *args) -> PyObject * {
249+
if (PyTuple_Size(args) != 1) {
250+
throw std::runtime_error("Invalid number of arguments for example_name");
251+
}
252+
PyObject *first = PyTuple_GetItem(args, 0);
253+
if (!PyLong_Check(first)) {
254+
throw std::runtime_error("Invalid argument to example_name");
255+
}
256+
auto result = py::cast(PyLong_AsLong(first) * 9);
250257
return result.release().ptr();
251258
};
252259
def.ml_flags = METH_VARARGS;
@@ -255,6 +262,9 @@ TEST_SUBMODULE(callbacks, m) {
255262
constexpr const char *rec_capsule_name = "CUSTOM_REC_CAPSULE";
256263
py::capsule rec_capsule(std::malloc(1), [](void *data) { std::free(data); });
257264
rec_capsule.set_name(rec_capsule_name);
258-
py::handle m_ptr = PyCFunction_New(&def, rec_capsule.ptr());
259-
m.add_object("custom_function", m_ptr);
265+
m.add_object("custom_function", PyCFunction_New(&def, rec_capsule.ptr()));
266+
267+
// rec_capsule with nullptr name
268+
py::capsule rec_capsule2(std::malloc(1), [](void *data) { std::free(data); });
269+
m.add_object("custom_function2", PyCFunction_New(&def, rec_capsule2.ptr()));
260270
}

tests/test_callbacks.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ def test_callback_num_times():
196196

197197

198198
def test_custom_func():
199-
func = m.custom_function
200-
assert func() == 20
201-
_ = m.roundtrip(func)
199+
assert m.custom_function(4) == 36
200+
assert m.roundtrip(m.custom_function)(4) == 36
201+
202+
assert m.custom_function2(3) == 27
203+
assert m.roundtrip(m.custom_function2)(3) == 27

0 commit comments

Comments
 (0)