github.com/kaydxh/golang@v0.0.131/pkg/gocv/cgo/third_path/pybind11/tests/test_callbacks.cpp (about) 1 /* 2 tests/test_callbacks.cpp -- callbacks 3 4 Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> 5 6 All rights reserved. Use of this source code is governed by a 7 BSD-style license that can be found in the LICENSE file. 8 */ 9 10 #include <pybind11/functional.h> 11 12 #include "constructor_stats.h" 13 #include "pybind11_tests.h" 14 15 #include <thread> 16 17 int dummy_function(int i) { return i + 1; } 18 19 TEST_SUBMODULE(callbacks, m) { 20 // test_callbacks, test_function_signatures 21 m.def("test_callback1", [](const py::object &func) { return func(); }); 22 m.def("test_callback2", [](const py::object &func) { return func("Hello", 'x', true, 5); }); 23 m.def("test_callback3", [](const std::function<int(int)> &func) { 24 return "func(43) = " + std::to_string(func(43)); 25 }); 26 m.def("test_callback4", 27 []() -> std::function<int(int)> { return [](int i) { return i + 1; }; }); 28 m.def("test_callback5", 29 []() { return py::cpp_function([](int i) { return i + 1; }, py::arg("number")); }); 30 31 // test_keyword_args_and_generalized_unpacking 32 m.def("test_tuple_unpacking", [](const py::function &f) { 33 auto t1 = py::make_tuple(2, 3); 34 auto t2 = py::make_tuple(5, 6); 35 return f("positional", 1, *t1, 4, *t2); 36 }); 37 38 m.def("test_dict_unpacking", [](const py::function &f) { 39 auto d1 = py::dict("key"_a = "value", "a"_a = 1); 40 auto d2 = py::dict(); 41 auto d3 = py::dict("b"_a = 2); 42 return f("positional", 1, **d1, **d2, **d3); 43 }); 44 45 m.def("test_keyword_args", [](const py::function &f) { return f("x"_a = 10, "y"_a = 20); }); 46 47 m.def("test_unpacking_and_keywords1", [](const py::function &f) { 48 auto args = py::make_tuple(2); 49 auto kwargs = py::dict("d"_a = 4); 50 return f(1, *args, "c"_a = 3, **kwargs); 51 }); 52 53 m.def("test_unpacking_and_keywords2", [](const py::function &f) { 54 auto kwargs1 = py::dict("a"_a = 1); 55 auto kwargs2 = py::dict("c"_a = 3, "d"_a = 4); 56 return f("positional", 57 *py::make_tuple(1), 58 2, 59 *py::make_tuple(3, 4), 60 5, 61 "key"_a = "value", 62 **kwargs1, 63 "b"_a = 2, 64 **kwargs2, 65 "e"_a = 5); 66 }); 67 68 m.def("test_unpacking_error1", [](const py::function &f) { 69 auto kwargs = py::dict("x"_a = 3); 70 return f("x"_a = 1, "y"_a = 2, **kwargs); // duplicate ** after keyword 71 }); 72 73 m.def("test_unpacking_error2", [](const py::function &f) { 74 auto kwargs = py::dict("x"_a = 3); 75 return f(**kwargs, "x"_a = 1); // duplicate keyword after ** 76 }); 77 78 m.def("test_arg_conversion_error1", 79 [](const py::function &f) { f(234, UnregisteredType(), "kw"_a = 567); }); 80 81 m.def("test_arg_conversion_error2", [](const py::function &f) { 82 f(234, "expected_name"_a = UnregisteredType(), "kw"_a = 567); 83 }); 84 85 // test_lambda_closure_cleanup 86 struct Payload { 87 Payload() { print_default_created(this); } 88 ~Payload() { print_destroyed(this); } 89 Payload(const Payload &) { print_copy_created(this); } 90 Payload(Payload &&) noexcept { print_move_created(this); } 91 }; 92 // Export the payload constructor statistics for testing purposes: 93 m.def("payload_cstats", &ConstructorStats::get<Payload>); 94 m.def("test_lambda_closure_cleanup", []() -> std::function<void()> { 95 Payload p; 96 97 // In this situation, `Func` in the implementation of 98 // `cpp_function::initialize` is NOT trivially destructible. 99 return [p]() { 100 /* p should be cleaned up when the returned function is garbage collected */ 101 (void) p; 102 }; 103 }); 104 105 class CppCallable { 106 public: 107 CppCallable() { track_default_created(this); } 108 ~CppCallable() { track_destroyed(this); } 109 CppCallable(const CppCallable &) { track_copy_created(this); } 110 CppCallable(CppCallable &&) noexcept { track_move_created(this); } 111 void operator()() {} 112 }; 113 114 m.def("test_cpp_callable_cleanup", []() { 115 // Related issue: https://github.com/pybind/pybind11/issues/3228 116 // Related PR: https://github.com/pybind/pybind11/pull/3229 117 py::list alive_counts; 118 ConstructorStats &stat = ConstructorStats::get<CppCallable>(); 119 alive_counts.append(stat.alive()); 120 { 121 CppCallable cpp_callable; 122 alive_counts.append(stat.alive()); 123 { 124 // In this situation, `Func` in the implementation of 125 // `cpp_function::initialize` IS trivially destructible, 126 // only `capture` is not. 127 py::cpp_function py_func(cpp_callable); 128 py::detail::silence_unused_warnings(py_func); 129 alive_counts.append(stat.alive()); 130 } 131 alive_counts.append(stat.alive()); 132 { 133 py::cpp_function py_func(std::move(cpp_callable)); 134 py::detail::silence_unused_warnings(py_func); 135 alive_counts.append(stat.alive()); 136 } 137 alive_counts.append(stat.alive()); 138 } 139 alive_counts.append(stat.alive()); 140 return alive_counts; 141 }); 142 143 // test_cpp_function_roundtrip 144 /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */ 145 m.def("dummy_function", &dummy_function); 146 m.def("dummy_function_overloaded", [](int i, int j) { return i + j; }); 147 m.def("dummy_function_overloaded", &dummy_function); 148 m.def("dummy_function2", [](int i, int j) { return i + j; }); 149 m.def( 150 "roundtrip", 151 [](std::function<int(int)> f, bool expect_none = false) { 152 if (expect_none && f) { 153 throw std::runtime_error("Expected None to be converted to empty std::function"); 154 } 155 return f; 156 }, 157 py::arg("f"), 158 py::arg("expect_none") = false); 159 m.def("test_dummy_function", [](const std::function<int(int)> &f) -> std::string { 160 using fn_type = int (*)(int); 161 const auto *result = f.target<fn_type>(); 162 if (!result) { 163 auto r = f(1); 164 return "can't convert to function pointer: eval(1) = " + std::to_string(r); 165 } 166 if (*result == dummy_function) { 167 auto r = (*result)(1); 168 return "matches dummy_function: eval(1) = " + std::to_string(r); 169 } 170 return "argument does NOT match dummy_function. This should never happen!"; 171 }); 172 173 class AbstractBase { 174 public: 175 // [workaround(intel)] = default does not work here 176 // Defaulting this destructor results in linking errors with the Intel compiler 177 // (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827) 178 virtual ~AbstractBase() {} // NOLINT(modernize-use-equals-default) 179 virtual unsigned int func() = 0; 180 }; 181 m.def("func_accepting_func_accepting_base", 182 [](const std::function<double(AbstractBase &)> &) {}); 183 184 struct MovableObject { 185 bool valid = true; 186 187 MovableObject() = default; 188 MovableObject(const MovableObject &) = default; 189 MovableObject &operator=(const MovableObject &) = default; 190 MovableObject(MovableObject &&o) noexcept : valid(o.valid) { o.valid = false; } 191 MovableObject &operator=(MovableObject &&o) noexcept { 192 valid = o.valid; 193 o.valid = false; 194 return *this; 195 } 196 }; 197 py::class_<MovableObject>(m, "MovableObject"); 198 199 // test_movable_object 200 m.def("callback_with_movable", [](const std::function<void(MovableObject &)> &f) { 201 auto x = MovableObject(); 202 f(x); // lvalue reference shouldn't move out object 203 return x.valid; // must still return `true` 204 }); 205 206 // test_bound_method_callback 207 struct CppBoundMethodTest {}; 208 py::class_<CppBoundMethodTest>(m, "CppBoundMethodTest") 209 .def(py::init<>()) 210 .def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; }); 211 212 // This checks that builtin functions can be passed as callbacks 213 // rather than throwing RuntimeError due to trying to extract as capsule 214 m.def("test_sum_builtin", 215 [](const std::function<double(py::iterable)> &sum_builtin, const py::iterable &i) { 216 return sum_builtin(i); 217 }); 218 219 // test async Python callbacks 220 using callback_f = std::function<void(int)>; 221 m.def("test_async_callback", [](const callback_f &f, const py::list &work) { 222 // make detached thread that calls `f` with piece of work after a little delay 223 auto start_f = [f](int j) { 224 auto invoke_f = [f, j] { 225 std::this_thread::sleep_for(std::chrono::milliseconds(50)); 226 f(j); 227 }; 228 auto t = std::thread(std::move(invoke_f)); 229 t.detach(); 230 }; 231 232 // spawn worker threads 233 for (auto i : work) { 234 start_f(py::cast<int>(i)); 235 } 236 }); 237 238 m.def("callback_num_times", [](const py::function &f, std::size_t num) { 239 for (std::size_t i = 0; i < num; i++) { 240 f(); 241 } 242 }); 243 244 auto *custom_def = []() { 245 static PyMethodDef def; 246 def.ml_name = "example_name"; 247 def.ml_doc = "Example doc"; 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); 257 return result.release().ptr(); 258 }; 259 def.ml_flags = METH_VARARGS; 260 return &def; 261 }(); 262 263 // rec_capsule with name that has the same value (but not pointer) as our internal one 264 // This capsule should be detected by our code as foreign and not inspected as the pointers 265 // shouldn't match 266 constexpr const char *rec_capsule_name 267 = pybind11::detail::internals_function_record_capsule_name; 268 py::capsule rec_capsule(std::malloc(1), [](void *data) { std::free(data); }); 269 rec_capsule.set_name(rec_capsule_name); 270 m.add_object("custom_function", PyCFunction_New(custom_def, rec_capsule.ptr())); 271 272 // This test requires a new ABI version to pass 273 #if PYBIND11_INTERNALS_VERSION > 4 274 // rec_capsule with nullptr name 275 py::capsule rec_capsule2(std::malloc(1), [](void *data) { std::free(data); }); 276 m.add_object("custom_function2", PyCFunction_New(custom_def, rec_capsule2.ptr())); 277 #else 278 m.add_object("custom_function2", py::none()); 279 #endif 280 }