mirror of
				https://github.com/thelsing/knx.git
				synced 2025-10-26 10:26:25 +01:00 
			
		
		
		
	fix build
This commit is contained in:
		
							parent
							
								
									e15da8451b
								
							
						
					
					
						commit
						a30bbd0f0a
					
				
							
								
								
									
										30
									
								
								examples/knxPython/pybind11/.github/workflows/emscripten.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								examples/knxPython/pybind11/.github/workflows/emscripten.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | name: WASM | ||||||
|  | 
 | ||||||
|  | on: | ||||||
|  |   workflow_dispatch: | ||||||
|  |   pull_request: | ||||||
|  |     branches: | ||||||
|  |     - master | ||||||
|  |     - stable | ||||||
|  |     - v* | ||||||
|  | 
 | ||||||
|  | concurrency: | ||||||
|  |   group: ${{ github.workflow }}-${{ github.ref }} | ||||||
|  |   cancel-in-progress: true | ||||||
|  | 
 | ||||||
|  | jobs: | ||||||
|  |   build-wasm-emscripten: | ||||||
|  |     name: Pyodide wheel | ||||||
|  |     runs-on: ubuntu-22.04 | ||||||
|  |     steps: | ||||||
|  |     - uses: actions/checkout@v4 | ||||||
|  |       with: | ||||||
|  |         submodules: true | ||||||
|  |         fetch-depth: 0 | ||||||
|  | 
 | ||||||
|  |     - uses: pypa/cibuildwheel@v2.20 | ||||||
|  |       env: | ||||||
|  |         PYODIDE_BUILD_EXPORTS: whole_archive | ||||||
|  |       with: | ||||||
|  |         package-dir: tests | ||||||
|  |         only: cp312-pyodide_wasm32 | ||||||
							
								
								
									
										109
									
								
								examples/knxPython/pybind11/docs/advanced/cast/functional.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								examples/knxPython/pybind11/docs/advanced/cast/functional.rst
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,109 @@ | |||||||
|  | Functional | ||||||
|  | ########## | ||||||
|  | 
 | ||||||
|  | The following features must be enabled by including :file:`pybind11/functional.h`. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Callbacks and passing anonymous functions | ||||||
|  | ========================================= | ||||||
|  | 
 | ||||||
|  | The C++11 standard brought lambda functions and the generic polymorphic | ||||||
|  | function wrapper ``std::function<>`` to the C++ programming language, which | ||||||
|  | enable powerful new ways of working with functions. Lambda functions come in | ||||||
|  | two flavors: stateless lambda function resemble classic function pointers that | ||||||
|  | link to an anonymous piece of code, while stateful lambda functions | ||||||
|  | additionally depend on captured variables that are stored in an anonymous | ||||||
|  | *lambda closure object*. | ||||||
|  | 
 | ||||||
|  | Here is a simple example of a C++ function that takes an arbitrary function | ||||||
|  | (stateful or stateless) with signature ``int -> int`` as an argument and runs | ||||||
|  | it with the value 10. | ||||||
|  | 
 | ||||||
|  | .. code-block:: cpp | ||||||
|  | 
 | ||||||
|  |     int func_arg(const std::function<int(int)> &f) { | ||||||
|  |         return f(10); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | The example below is more involved: it takes a function of signature ``int -> int`` | ||||||
|  | and returns another function of the same kind. The return value is a stateful | ||||||
|  | lambda function, which stores the value ``f`` in the capture object and adds 1 to | ||||||
|  | its return value upon execution. | ||||||
|  | 
 | ||||||
|  | .. code-block:: cpp | ||||||
|  | 
 | ||||||
|  |     std::function<int(int)> func_ret(const std::function<int(int)> &f) { | ||||||
|  |         return [f](int i) { | ||||||
|  |             return f(i) + 1; | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | This example demonstrates using python named parameters in C++ callbacks which | ||||||
|  | requires using ``py::cpp_function`` as a wrapper. Usage is similar to defining | ||||||
|  | methods of classes: | ||||||
|  | 
 | ||||||
|  | .. code-block:: cpp | ||||||
|  | 
 | ||||||
|  |     py::cpp_function func_cpp() { | ||||||
|  |         return py::cpp_function([](int i) { return i+1; }, | ||||||
|  |            py::arg("number")); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | After including the extra header file :file:`pybind11/functional.h`, it is almost | ||||||
|  | trivial to generate binding code for all of these functions. | ||||||
|  | 
 | ||||||
|  | .. code-block:: cpp | ||||||
|  | 
 | ||||||
|  |     #include <pybind11/functional.h> | ||||||
|  | 
 | ||||||
|  |     PYBIND11_MODULE(example, m) { | ||||||
|  |         m.def("func_arg", &func_arg); | ||||||
|  |         m.def("func_ret", &func_ret); | ||||||
|  |         m.def("func_cpp", &func_cpp); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | The following interactive session shows how to call them from Python. | ||||||
|  | 
 | ||||||
|  | .. code-block:: pycon | ||||||
|  | 
 | ||||||
|  |     $ python | ||||||
|  |     >>> import example | ||||||
|  |     >>> def square(i): | ||||||
|  |     ...     return i * i | ||||||
|  |     ... | ||||||
|  |     >>> example.func_arg(square) | ||||||
|  |     100L | ||||||
|  |     >>> square_plus_1 = example.func_ret(square) | ||||||
|  |     >>> square_plus_1(4) | ||||||
|  |     17L | ||||||
|  |     >>> plus_1 = func_cpp() | ||||||
|  |     >>> plus_1(number=43) | ||||||
|  |     44L | ||||||
|  | 
 | ||||||
|  | .. warning:: | ||||||
|  | 
 | ||||||
|  |     Keep in mind that passing a function from C++ to Python (or vice versa) | ||||||
|  |     will instantiate a piece of wrapper code that translates function | ||||||
|  |     invocations between the two languages. Naturally, this translation | ||||||
|  |     increases the computational cost of each function call somewhat. A | ||||||
|  |     problematic situation can arise when a function is copied back and forth | ||||||
|  |     between Python and C++ many times in a row, in which case the underlying | ||||||
|  |     wrappers will accumulate correspondingly. The resulting long sequence of | ||||||
|  |     C++ -> Python -> C++ -> ... roundtrips can significantly decrease | ||||||
|  |     performance. | ||||||
|  | 
 | ||||||
|  |     There is one exception: pybind11 detects case where a stateless function | ||||||
|  |     (i.e. a function pointer or a lambda function without captured variables) | ||||||
|  |     is passed as an argument to another C++ function exposed in Python. In this | ||||||
|  |     case, there is no overhead. Pybind11 will extract the underlying C++ | ||||||
|  |     function pointer from the wrapped function to sidestep a potential C++ -> | ||||||
|  |     Python -> C++ roundtrip. This is demonstrated in :file:`tests/test_callbacks.cpp`. | ||||||
|  | 
 | ||||||
|  | .. note:: | ||||||
|  | 
 | ||||||
|  |     This functionality is very useful when generating bindings for callbacks in | ||||||
|  |     C++ libraries (e.g. GUI libraries, asynchronous networking libraries, etc.). | ||||||
|  | 
 | ||||||
|  |     The file :file:`tests/test_callbacks.cpp` contains a complete example | ||||||
|  |     that demonstrates how to work with callbacks and anonymous functions in | ||||||
|  |     more detail. | ||||||
							
								
								
									
										13
									
								
								examples/knxPython/pybind11/docs/advanced/pycpp/index.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								examples/knxPython/pybind11/docs/advanced/pycpp/index.rst
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | Python C++ interface | ||||||
|  | #################### | ||||||
|  | 
 | ||||||
|  | pybind11 exposes Python types and functions using thin C++ wrappers, which | ||||||
|  | makes it possible to conveniently call Python code from C++ without resorting | ||||||
|  | to Python's C API. | ||||||
|  | 
 | ||||||
|  | .. toctree:: | ||||||
|  |    :maxdepth: 2 | ||||||
|  | 
 | ||||||
|  |    object | ||||||
|  |    numpy | ||||||
|  |    utilities | ||||||
							
								
								
									
										
											BIN
										
									
								
								examples/knxPython/pybind11/docs/pybind11_vs_boost_python1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								examples/knxPython/pybind11/docs/pybind11_vs_boost_python1.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 44 KiB | 
							
								
								
									
										
											BIN
										
									
								
								examples/knxPython/pybind11/docs/pybind11_vs_boost_python1.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								examples/knxPython/pybind11/docs/pybind11_vs_boost_python1.svg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 86 KiB | 
							
								
								
									
										
											BIN
										
									
								
								examples/knxPython/pybind11/docs/pybind11_vs_boost_python2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								examples/knxPython/pybind11/docs/pybind11_vs_boost_python2.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 40 KiB | 
							
								
								
									
										
											BIN
										
									
								
								examples/knxPython/pybind11/docs/pybind11_vs_boost_python2.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								examples/knxPython/pybind11/docs/pybind11_vs_boost_python2.svg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 84 KiB | 
							
								
								
									
										2
									
								
								examples/knxPython/pybind11/include/pybind11/common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								examples/knxPython/pybind11/include/pybind11/common.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | #include "detail/common.h" | ||||||
|  | #warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'." | ||||||
| @ -0,0 +1,77 @@ | |||||||
|  | // Copyright (c) 2024 The pybind Community.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <pybind11/pytypes.h> | ||||||
|  | 
 | ||||||
|  | #include "common.h" | ||||||
|  | #include "internals.h" | ||||||
|  | 
 | ||||||
|  | #include <typeinfo> | ||||||
|  | 
 | ||||||
|  | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) | ||||||
|  | PYBIND11_NAMESPACE_BEGIN(detail) | ||||||
|  | 
 | ||||||
|  | // Forward declaration needed here: Refactoring opportunity.
 | ||||||
|  | extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *); | ||||||
|  | 
 | ||||||
|  | inline bool type_is_managed_by_our_internals(PyTypeObject *type_obj) { | ||||||
|  | #if defined(PYPY_VERSION) | ||||||
|  |     auto &internals = get_internals(); | ||||||
|  |     return bool(internals.registered_types_py.find(type_obj) | ||||||
|  |                 != internals.registered_types_py.end()); | ||||||
|  | #else | ||||||
|  |     return bool(type_obj->tp_new == pybind11_object_new); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline bool is_instance_method_of_type(PyTypeObject *type_obj, PyObject *attr_name) { | ||||||
|  |     PyObject *descr = _PyType_Lookup(type_obj, attr_name); | ||||||
|  |     return bool((descr != nullptr) && PyInstanceMethod_Check(descr)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline object try_get_cpp_conduit_method(PyObject *obj) { | ||||||
|  |     if (PyType_Check(obj)) { | ||||||
|  |         return object(); | ||||||
|  |     } | ||||||
|  |     PyTypeObject *type_obj = Py_TYPE(obj); | ||||||
|  |     str attr_name("_pybind11_conduit_v1_"); | ||||||
|  |     bool assumed_to_be_callable = false; | ||||||
|  |     if (type_is_managed_by_our_internals(type_obj)) { | ||||||
|  |         if (!is_instance_method_of_type(type_obj, attr_name.ptr())) { | ||||||
|  |             return object(); | ||||||
|  |         } | ||||||
|  |         assumed_to_be_callable = true; | ||||||
|  |     } | ||||||
|  |     PyObject *method = PyObject_GetAttr(obj, attr_name.ptr()); | ||||||
|  |     if (method == nullptr) { | ||||||
|  |         PyErr_Clear(); | ||||||
|  |         return object(); | ||||||
|  |     } | ||||||
|  |     if (!assumed_to_be_callable && PyCallable_Check(method) == 0) { | ||||||
|  |         Py_DECREF(method); | ||||||
|  |         return object(); | ||||||
|  |     } | ||||||
|  |     return reinterpret_steal<object>(method); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void *try_raw_pointer_ephemeral_from_cpp_conduit(handle src, | ||||||
|  |                                                         const std::type_info *cpp_type_info) { | ||||||
|  |     object method = try_get_cpp_conduit_method(src.ptr()); | ||||||
|  |     if (method) { | ||||||
|  |         capsule cpp_type_info_capsule(const_cast<void *>(static_cast<const void *>(cpp_type_info)), | ||||||
|  |                                       typeid(std::type_info).name()); | ||||||
|  |         object cpp_conduit = method(bytes(PYBIND11_PLATFORM_ABI_ID), | ||||||
|  |                                     cpp_type_info_capsule, | ||||||
|  |                                     bytes("raw_pointer_ephemeral")); | ||||||
|  |         if (isinstance<capsule>(cpp_conduit)) { | ||||||
|  |             return reinterpret_borrow<capsule>(cpp_conduit).get_pointer(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define PYBIND11_HAS_CPP_CONDUIT 1 | ||||||
|  | 
 | ||||||
|  | PYBIND11_NAMESPACE_END(detail) | ||||||
|  | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) | ||||||
| @ -0,0 +1,71 @@ | |||||||
|  | /*
 | ||||||
|  |     pybind11/detail/exception_translation.h: means to translate C++ exceptions to Python exceptions | ||||||
|  | 
 | ||||||
|  |     Copyright (c) 2024 The Pybind Development Team. | ||||||
|  | 
 | ||||||
|  |     All rights reserved. Use of this source code is governed by a | ||||||
|  |     BSD-style license that can be found in the LICENSE file. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "common.h" | ||||||
|  | #include "internals.h" | ||||||
|  | 
 | ||||||
|  | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) | ||||||
|  | PYBIND11_NAMESPACE_BEGIN(detail) | ||||||
|  | 
 | ||||||
|  | // Apply all the extensions translators from a list
 | ||||||
|  | // Return true if one of the translators completed without raising an exception
 | ||||||
|  | // itself. Return of false indicates that if there are other translators
 | ||||||
|  | // available, they should be tried.
 | ||||||
|  | inline bool apply_exception_translators(std::forward_list<ExceptionTranslator> &translators) { | ||||||
|  |     auto last_exception = std::current_exception(); | ||||||
|  | 
 | ||||||
|  |     for (auto &translator : translators) { | ||||||
|  |         try { | ||||||
|  |             translator(last_exception); | ||||||
|  |             return true; | ||||||
|  |         } catch (...) { | ||||||
|  |             last_exception = std::current_exception(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void try_translate_exceptions() { | ||||||
|  |     /* When an exception is caught, give each registered exception
 | ||||||
|  |         translator a chance to translate it to a Python exception. First | ||||||
|  |         all module-local translators will be tried in reverse order of | ||||||
|  |         registration. If none of the module-locale translators handle | ||||||
|  |         the exception (or there are no module-locale translators) then | ||||||
|  |         the global translators will be tried, also in reverse order of | ||||||
|  |         registration. | ||||||
|  | 
 | ||||||
|  |         A translator may choose to do one of the following: | ||||||
|  | 
 | ||||||
|  |         - catch the exception and call py::set_error() | ||||||
|  |             to set a standard (or custom) Python exception, or | ||||||
|  |         - do nothing and let the exception fall through to the next translator, or | ||||||
|  |         - delegate translation to the next translator by throwing a new type of exception. | ||||||
|  |         */ | ||||||
|  | 
 | ||||||
|  |     bool handled = with_internals([&](internals &internals) { | ||||||
|  |         auto &local_exception_translators = get_local_internals().registered_exception_translators; | ||||||
|  |         if (detail::apply_exception_translators(local_exception_translators)) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         auto &exception_translators = internals.registered_exception_translators; | ||||||
|  |         if (detail::apply_exception_translators(exception_translators)) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     if (!handled) { | ||||||
|  |         set_error(PyExc_SystemError, "Exception escaped from default exception translator!"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PYBIND11_NAMESPACE_END(detail) | ||||||
|  | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) | ||||||
| @ -0,0 +1,77 @@ | |||||||
|  | // Copyright (c) 2016-2024 The Pybind Development Team.
 | ||||||
|  | // All rights reserved. Use of this source code is governed by a
 | ||||||
|  | // BSD-style license that can be found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "common.h" | ||||||
|  | 
 | ||||||
|  | #include <cstddef> | ||||||
|  | #include <typeinfo> | ||||||
|  | 
 | ||||||
|  | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) | ||||||
|  | PYBIND11_NAMESPACE_BEGIN(detail) | ||||||
|  | 
 | ||||||
|  | struct value_and_holder { | ||||||
|  |     instance *inst = nullptr; | ||||||
|  |     size_t index = 0u; | ||||||
|  |     const detail::type_info *type = nullptr; | ||||||
|  |     void **vh = nullptr; | ||||||
|  | 
 | ||||||
|  |     // Main constructor for a found value/holder:
 | ||||||
|  |     value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) | ||||||
|  |         : inst{i}, index{index}, type{type}, | ||||||
|  |           vh{inst->simple_layout ? inst->simple_value_holder | ||||||
|  |                                  : &inst->nonsimple.values_and_holders[vpos]} {} | ||||||
|  | 
 | ||||||
|  |     // Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
 | ||||||
|  |     value_and_holder() = default; | ||||||
|  | 
 | ||||||
|  |     // Used for past-the-end iterator
 | ||||||
|  |     explicit value_and_holder(size_t index) : index{index} {} | ||||||
|  | 
 | ||||||
|  |     template <typename V = void> | ||||||
|  |     V *&value_ptr() const { | ||||||
|  |         return reinterpret_cast<V *&>(vh[0]); | ||||||
|  |     } | ||||||
|  |     // True if this `value_and_holder` has a non-null value pointer
 | ||||||
|  |     explicit operator bool() const { return value_ptr() != nullptr; } | ||||||
|  | 
 | ||||||
|  |     template <typename H> | ||||||
|  |     H &holder() const { | ||||||
|  |         return reinterpret_cast<H &>(vh[1]); | ||||||
|  |     } | ||||||
|  |     bool holder_constructed() const { | ||||||
|  |         return inst->simple_layout | ||||||
|  |                    ? inst->simple_holder_constructed | ||||||
|  |                    : (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u; | ||||||
|  |     } | ||||||
|  |     // NOLINTNEXTLINE(readability-make-member-function-const)
 | ||||||
|  |     void set_holder_constructed(bool v = true) { | ||||||
|  |         if (inst->simple_layout) { | ||||||
|  |             inst->simple_holder_constructed = v; | ||||||
|  |         } else if (v) { | ||||||
|  |             inst->nonsimple.status[index] |= instance::status_holder_constructed; | ||||||
|  |         } else { | ||||||
|  |             inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     bool instance_registered() const { | ||||||
|  |         return inst->simple_layout | ||||||
|  |                    ? inst->simple_instance_registered | ||||||
|  |                    : ((inst->nonsimple.status[index] & instance::status_instance_registered) != 0); | ||||||
|  |     } | ||||||
|  |     // NOLINTNEXTLINE(readability-make-member-function-const)
 | ||||||
|  |     void set_instance_registered(bool v = true) { | ||||||
|  |         if (inst->simple_layout) { | ||||||
|  |             inst->simple_instance_registered = v; | ||||||
|  |         } else if (v) { | ||||||
|  |             inst->nonsimple.status[index] |= instance::status_instance_registered; | ||||||
|  |         } else { | ||||||
|  |             inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | PYBIND11_NAMESPACE_END(detail) | ||||||
|  | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) | ||||||
							
								
								
									
										103
									
								
								examples/knxPython/pybind11/tests/exo_planet_c_api.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								examples/knxPython/pybind11/tests/exo_planet_c_api.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | |||||||
|  | // Copyright (c) 2024 The pybind Community.
 | ||||||
|  | 
 | ||||||
|  | // THIS MUST STAY AT THE TOP!
 | ||||||
|  | #include <pybind11/pybind11.h> // EXCLUSIVELY for PYBIND11_PLATFORM_ABI_ID
 | ||||||
|  | // Potential future direction to maximize reusability:
 | ||||||
|  | // (e.g. for use from SWIG, Cython, PyCLIF, nanobind):
 | ||||||
|  | //     #include <pybind11/compat/platform_abi_id.h>
 | ||||||
|  | // This would only depend on:
 | ||||||
|  | //     1. A C++ compiler, WITHOUT requiring -fexceptions.
 | ||||||
|  | //     2. Python.h
 | ||||||
|  | 
 | ||||||
|  | #include "test_cpp_conduit_traveler_types.h" | ||||||
|  | 
 | ||||||
|  | #include <Python.h> | ||||||
|  | #include <typeinfo> | ||||||
|  | 
 | ||||||
|  | namespace { | ||||||
|  | 
 | ||||||
|  | void *get_cpp_conduit_void_ptr(PyObject *py_obj, const std::type_info *cpp_type_info) { | ||||||
|  |     PyObject *cpp_type_info_capsule | ||||||
|  |         = PyCapsule_New(const_cast<void *>(static_cast<const void *>(cpp_type_info)), | ||||||
|  |                         typeid(std::type_info).name(), | ||||||
|  |                         nullptr); | ||||||
|  |     if (cpp_type_info_capsule == nullptr) { | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  |     PyObject *cpp_conduit = PyObject_CallMethod(py_obj, | ||||||
|  |                                                 "_pybind11_conduit_v1_", | ||||||
|  |                                                 "yOy", | ||||||
|  |                                                 PYBIND11_PLATFORM_ABI_ID, | ||||||
|  |                                                 cpp_type_info_capsule, | ||||||
|  |                                                 "raw_pointer_ephemeral"); | ||||||
|  |     Py_DECREF(cpp_type_info_capsule); | ||||||
|  |     if (cpp_conduit == nullptr) { | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  |     void *void_ptr = PyCapsule_GetPointer(cpp_conduit, cpp_type_info->name()); | ||||||
|  |     Py_DECREF(cpp_conduit); | ||||||
|  |     if (PyErr_Occurred()) { | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  |     return void_ptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | T *get_cpp_conduit_type_ptr(PyObject *py_obj) { | ||||||
|  |     void *void_ptr = get_cpp_conduit_void_ptr(py_obj, &typeid(T)); | ||||||
|  |     if (void_ptr == nullptr) { | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  |     return static_cast<T *>(void_ptr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extern "C" PyObject *wrapGetLuggage(PyObject * /*self*/, PyObject *traveler) { | ||||||
|  |     const auto *cpp_traveler | ||||||
|  |         = get_cpp_conduit_type_ptr<pybind11_tests::test_cpp_conduit::Traveler>(traveler); | ||||||
|  |     if (cpp_traveler == nullptr) { | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  |     return PyUnicode_FromString(cpp_traveler->luggage.c_str()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extern "C" PyObject *wrapGetPoints(PyObject * /*self*/, PyObject *premium_traveler) { | ||||||
|  |     const auto *cpp_premium_traveler | ||||||
|  |         = get_cpp_conduit_type_ptr<pybind11_tests::test_cpp_conduit::PremiumTraveler>( | ||||||
|  |             premium_traveler); | ||||||
|  |     if (cpp_premium_traveler == nullptr) { | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  |     return PyLong_FromLong(static_cast<long>(cpp_premium_traveler->points)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PyMethodDef ThisMethodDef[] = {{"GetLuggage", wrapGetLuggage, METH_O, nullptr}, | ||||||
|  |                                {"GetPoints", wrapGetPoints, METH_O, nullptr}, | ||||||
|  |                                {nullptr, nullptr, 0, nullptr}}; | ||||||
|  | 
 | ||||||
|  | struct PyModuleDef ThisModuleDef = { | ||||||
|  |     PyModuleDef_HEAD_INIT, // m_base
 | ||||||
|  |     "exo_planet_c_api",    // m_name
 | ||||||
|  |     nullptr,               // m_doc
 | ||||||
|  |     -1,                    // m_size
 | ||||||
|  |     ThisMethodDef,         // m_methods
 | ||||||
|  |     nullptr,               // m_slots
 | ||||||
|  |     nullptr,               // m_traverse
 | ||||||
|  |     nullptr,               // m_clear
 | ||||||
|  |     nullptr                // m_free
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace
 | ||||||
|  | 
 | ||||||
|  | #if defined(WIN32) || defined(_WIN32) | ||||||
|  | #    define EXO_PLANET_C_API_EXPORT __declspec(dllexport) | ||||||
|  | #else | ||||||
|  | #    define EXO_PLANET_C_API_EXPORT __attribute__((visibility("default"))) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | extern "C" EXO_PLANET_C_API_EXPORT PyObject *PyInit_exo_planet_c_api() { | ||||||
|  |     PyObject *m = PyModule_Create(&ThisModuleDef); | ||||||
|  |     if (m == nullptr) { | ||||||
|  |         return nullptr; | ||||||
|  |     } | ||||||
|  |     return m; | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								examples/knxPython/pybind11/tests/exo_planet_pybind11.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								examples/knxPython/pybind11/tests/exo_planet_pybind11.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | // Copyright (c) 2024 The pybind Community.
 | ||||||
|  | 
 | ||||||
|  | #if defined(PYBIND11_INTERNALS_VERSION) | ||||||
|  | #    undef PYBIND11_INTERNALS_VERSION | ||||||
|  | #endif | ||||||
|  | #define PYBIND11_INTERNALS_VERSION 900000001 | ||||||
|  | 
 | ||||||
|  | #include "test_cpp_conduit_traveler_bindings.h" | ||||||
|  | 
 | ||||||
|  | namespace pybind11_tests { | ||||||
|  | namespace test_cpp_conduit { | ||||||
|  | 
 | ||||||
|  | PYBIND11_MODULE(exo_planet_pybind11, m) { | ||||||
|  |     wrap_traveler(m); | ||||||
|  |     m.def("wrap_very_lonely_traveler", [m]() { wrap_very_lonely_traveler(m); }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace test_cpp_conduit
 | ||||||
|  | } // namespace pybind11_tests
 | ||||||
| @ -0,0 +1,13 @@ | |||||||
|  | // Copyright (c) 2024 The pybind Community.
 | ||||||
|  | 
 | ||||||
|  | #include "test_cpp_conduit_traveler_bindings.h" | ||||||
|  | 
 | ||||||
|  | namespace pybind11_tests { | ||||||
|  | namespace test_cpp_conduit { | ||||||
|  | 
 | ||||||
|  | PYBIND11_MODULE(home_planet_very_lonely_traveler, m) { | ||||||
|  |     m.def("wrap_very_lonely_traveler", [m]() { wrap_very_lonely_traveler(m); }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace test_cpp_conduit
 | ||||||
|  | } // namespace pybind11_tests
 | ||||||
							
								
								
									
										21
									
								
								examples/knxPython/pybind11/tests/pyproject.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								examples/knxPython/pybind11/tests/pyproject.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | # Warning: this is currently used for pyodide, and is not a general out-of-tree | ||||||
|  | # builder for the tests (yet). Specifically, wheels can't be built from SDists. | ||||||
|  | 
 | ||||||
|  | [build-system] | ||||||
|  | requires = ["scikit-build-core"] | ||||||
|  | build-backend = "scikit_build_core.build" | ||||||
|  | 
 | ||||||
|  | [project] | ||||||
|  | name = "pybind11_tests" | ||||||
|  | version = "0.0.1" | ||||||
|  | dependencies = ["pytest", "pytest-timeout", "numpy", "scipy"] | ||||||
|  | 
 | ||||||
|  | [tool.scikit-build] | ||||||
|  | # Hide a warning while we also support CMake < 3.15 | ||||||
|  | cmake.version = ">=3.15" | ||||||
|  | 
 | ||||||
|  | [tool.scikit-build.cmake.define] | ||||||
|  | PYBIND11_FINDPYTHON = true | ||||||
|  | 
 | ||||||
|  | [tool.cibuildwheel] | ||||||
|  | test-command = "pytest -o timeout=0 -p no:cacheprovider {project}/tests/test_*.py" | ||||||
							
								
								
									
										22
									
								
								examples/knxPython/pybind11/tests/test_cpp_conduit.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								examples/knxPython/pybind11/tests/test_cpp_conduit.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | // Copyright (c) 2024 The pybind Community.
 | ||||||
|  | 
 | ||||||
|  | #include "pybind11_tests.h" | ||||||
|  | #include "test_cpp_conduit_traveler_bindings.h" | ||||||
|  | 
 | ||||||
|  | #include <typeinfo> | ||||||
|  | 
 | ||||||
|  | namespace pybind11_tests { | ||||||
|  | namespace test_cpp_conduit { | ||||||
|  | 
 | ||||||
|  | TEST_SUBMODULE(cpp_conduit, m) { | ||||||
|  |     m.attr("PYBIND11_PLATFORM_ABI_ID") = py::bytes(PYBIND11_PLATFORM_ABI_ID); | ||||||
|  |     m.attr("cpp_type_info_capsule_Traveler") | ||||||
|  |         = py::capsule(&typeid(Traveler), typeid(std::type_info).name()); | ||||||
|  |     m.attr("cpp_type_info_capsule_int") = py::capsule(&typeid(int), typeid(std::type_info).name()); | ||||||
|  | 
 | ||||||
|  |     wrap_traveler(m); | ||||||
|  |     wrap_lonely_traveler(m); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace test_cpp_conduit
 | ||||||
|  | } // namespace pybind11_tests
 | ||||||
							
								
								
									
										162
									
								
								examples/knxPython/pybind11/tests/test_cpp_conduit.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								examples/knxPython/pybind11/tests/test_cpp_conduit.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,162 @@ | |||||||
|  | # Copyright (c) 2024 The pybind Community. | ||||||
|  | 
 | ||||||
|  | from __future__ import annotations | ||||||
|  | 
 | ||||||
|  | import exo_planet_c_api | ||||||
|  | import exo_planet_pybind11 | ||||||
|  | import home_planet_very_lonely_traveler | ||||||
|  | import pytest | ||||||
|  | 
 | ||||||
|  | from pybind11_tests import cpp_conduit as home_planet | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_traveler_getattr_actually_exists(): | ||||||
|  |     t_h = home_planet.Traveler("home") | ||||||
|  |     assert t_h.any_name == "Traveler GetAttr: any_name luggage: home" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_premium_traveler_getattr_actually_exists(): | ||||||
|  |     t_h = home_planet.PremiumTraveler("home", 7) | ||||||
|  |     assert t_h.secret_name == "PremiumTraveler GetAttr: secret_name points: 7" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_call_cpp_conduit_success(): | ||||||
|  |     t_h = home_planet.Traveler("home") | ||||||
|  |     cap = t_h._pybind11_conduit_v1_( | ||||||
|  |         home_planet.PYBIND11_PLATFORM_ABI_ID, | ||||||
|  |         home_planet.cpp_type_info_capsule_Traveler, | ||||||
|  |         b"raw_pointer_ephemeral", | ||||||
|  |     ) | ||||||
|  |     assert cap.__class__.__name__ == "PyCapsule" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_call_cpp_conduit_platform_abi_id_mismatch(): | ||||||
|  |     t_h = home_planet.Traveler("home") | ||||||
|  |     cap = t_h._pybind11_conduit_v1_( | ||||||
|  |         home_planet.PYBIND11_PLATFORM_ABI_ID + b"MISMATCH", | ||||||
|  |         home_planet.cpp_type_info_capsule_Traveler, | ||||||
|  |         b"raw_pointer_ephemeral", | ||||||
|  |     ) | ||||||
|  |     assert cap is None | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_call_cpp_conduit_cpp_type_info_capsule_mismatch(): | ||||||
|  |     t_h = home_planet.Traveler("home") | ||||||
|  |     cap = t_h._pybind11_conduit_v1_( | ||||||
|  |         home_planet.PYBIND11_PLATFORM_ABI_ID, | ||||||
|  |         home_planet.cpp_type_info_capsule_int, | ||||||
|  |         b"raw_pointer_ephemeral", | ||||||
|  |     ) | ||||||
|  |     assert cap is None | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_call_cpp_conduit_pointer_kind_invalid(): | ||||||
|  |     t_h = home_planet.Traveler("home") | ||||||
|  |     with pytest.raises( | ||||||
|  |         RuntimeError, match='^Invalid pointer_kind: "raw_pointer_ephemreal"$' | ||||||
|  |     ): | ||||||
|  |         t_h._pybind11_conduit_v1_( | ||||||
|  |             home_planet.PYBIND11_PLATFORM_ABI_ID, | ||||||
|  |             home_planet.cpp_type_info_capsule_Traveler, | ||||||
|  |             b"raw_pointer_ephemreal", | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_home_only_basic(): | ||||||
|  |     t_h = home_planet.Traveler("home") | ||||||
|  |     assert t_h.luggage == "home" | ||||||
|  |     assert home_planet.get_luggage(t_h) == "home" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_home_only_premium(): | ||||||
|  |     p_h = home_planet.PremiumTraveler("home", 2) | ||||||
|  |     assert p_h.luggage == "home" | ||||||
|  |     assert home_planet.get_luggage(p_h) == "home" | ||||||
|  |     assert home_planet.get_points(p_h) == 2 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_exo_only_basic(): | ||||||
|  |     t_e = exo_planet_pybind11.Traveler("exo") | ||||||
|  |     assert t_e.luggage == "exo" | ||||||
|  |     assert exo_planet_pybind11.get_luggage(t_e) == "exo" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_exo_only_premium(): | ||||||
|  |     p_e = exo_planet_pybind11.PremiumTraveler("exo", 3) | ||||||
|  |     assert p_e.luggage == "exo" | ||||||
|  |     assert exo_planet_pybind11.get_luggage(p_e) == "exo" | ||||||
|  |     assert exo_planet_pybind11.get_points(p_e) == 3 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_home_passed_to_exo_basic(): | ||||||
|  |     t_h = home_planet.Traveler("home") | ||||||
|  |     assert exo_planet_pybind11.get_luggage(t_h) == "home" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_exo_passed_to_home_basic(): | ||||||
|  |     t_e = exo_planet_pybind11.Traveler("exo") | ||||||
|  |     assert home_planet.get_luggage(t_e) == "exo" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_home_passed_to_exo_premium(): | ||||||
|  |     p_h = home_planet.PremiumTraveler("home", 2) | ||||||
|  |     assert exo_planet_pybind11.get_luggage(p_h) == "home" | ||||||
|  |     assert exo_planet_pybind11.get_points(p_h) == 2 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_exo_passed_to_home_premium(): | ||||||
|  |     p_e = exo_planet_pybind11.PremiumTraveler("exo", 3) | ||||||
|  |     assert home_planet.get_luggage(p_e) == "exo" | ||||||
|  |     assert home_planet.get_points(p_e) == 3 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.parametrize( | ||||||
|  |     "traveler_type", [home_planet.Traveler, exo_planet_pybind11.Traveler] | ||||||
|  | ) | ||||||
|  | def test_exo_planet_c_api_traveler(traveler_type): | ||||||
|  |     t = traveler_type("socks") | ||||||
|  |     assert exo_planet_c_api.GetLuggage(t) == "socks" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.mark.parametrize( | ||||||
|  |     "premium_traveler_type", | ||||||
|  |     [home_planet.PremiumTraveler, exo_planet_pybind11.PremiumTraveler], | ||||||
|  | ) | ||||||
|  | def test_exo_planet_c_api_premium_traveler(premium_traveler_type): | ||||||
|  |     pt = premium_traveler_type("gucci", 5) | ||||||
|  |     assert exo_planet_c_api.GetLuggage(pt) == "gucci" | ||||||
|  |     assert exo_planet_c_api.GetPoints(pt) == 5 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_home_planet_wrap_very_lonely_traveler(): | ||||||
|  |     # This does not exercise the cpp_conduit feature, but is here to | ||||||
|  |     # demonstrate that the cpp_conduit feature does not solve all | ||||||
|  |     # cross-extension interoperability issues. | ||||||
|  |     # Here is the proof that the following works for extensions with | ||||||
|  |     # matching `PYBIND11_INTERNALS_ID`s: | ||||||
|  |     #     test_cpp_conduit.cpp: | ||||||
|  |     #         py::class_<LonelyTraveler> | ||||||
|  |     #     home_planet_very_lonely_traveler.cpp: | ||||||
|  |     #         py::class_<VeryLonelyTraveler, LonelyTraveler> | ||||||
|  |     # See test_exo_planet_pybind11_wrap_very_lonely_traveler() for the negative | ||||||
|  |     # test. | ||||||
|  |     assert home_planet.LonelyTraveler is not None  # Verify that the base class exists. | ||||||
|  |     home_planet_very_lonely_traveler.wrap_very_lonely_traveler() | ||||||
|  |     # Ensure that the derived class exists. | ||||||
|  |     assert home_planet_very_lonely_traveler.VeryLonelyTraveler is not None | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_exo_planet_pybind11_wrap_very_lonely_traveler(): | ||||||
|  |     # See comment under test_home_planet_wrap_very_lonely_traveler() first. | ||||||
|  |     # Here the `PYBIND11_INTERNALS_ID`s don't match between: | ||||||
|  |     #     test_cpp_conduit.cpp: | ||||||
|  |     #         py::class_<LonelyTraveler> | ||||||
|  |     #     exo_planet_pybind11.cpp: | ||||||
|  |     #         py::class_<VeryLonelyTraveler, LonelyTraveler> | ||||||
|  |     assert home_planet.LonelyTraveler is not None  # Verify that the base class exists. | ||||||
|  |     with pytest.raises( | ||||||
|  |         RuntimeError, | ||||||
|  |         match='^generic_type: type "VeryLonelyTraveler" referenced unknown base type ' | ||||||
|  |         '"pybind11_tests::test_cpp_conduit::LonelyTraveler"$', | ||||||
|  |     ): | ||||||
|  |         exo_planet_pybind11.wrap_very_lonely_traveler() | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | // Copyright (c) 2024 The pybind Community.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <pybind11/pybind11.h> | ||||||
|  | 
 | ||||||
|  | #include "test_cpp_conduit_traveler_types.h" | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | namespace pybind11_tests { | ||||||
|  | namespace test_cpp_conduit { | ||||||
|  | 
 | ||||||
|  | namespace py = pybind11; | ||||||
|  | 
 | ||||||
|  | inline void wrap_traveler(py::module_ m) { | ||||||
|  |     py::class_<Traveler>(m, "Traveler") | ||||||
|  |         .def(py::init<std::string>()) | ||||||
|  |         .def_readwrite("luggage", &Traveler::luggage) | ||||||
|  |         // See issue #3788:
 | ||||||
|  |         .def("__getattr__", [](const Traveler &self, const std::string &key) { | ||||||
|  |             return "Traveler GetAttr: " + key + " luggage: " + self.luggage; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     m.def("get_luggage", [](const Traveler &person) { return person.luggage; }); | ||||||
|  | 
 | ||||||
|  |     py::class_<PremiumTraveler, Traveler>(m, "PremiumTraveler") | ||||||
|  |         .def(py::init<std::string, int>()) | ||||||
|  |         .def_readwrite("points", &PremiumTraveler::points) | ||||||
|  |         // See issue #3788:
 | ||||||
|  |         .def("__getattr__", [](const PremiumTraveler &self, const std::string &key) { | ||||||
|  |             return "PremiumTraveler GetAttr: " + key + " points: " + std::to_string(self.points); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     m.def("get_points", [](const PremiumTraveler &person) { return person.points; }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void wrap_lonely_traveler(py::module_ m) { | ||||||
|  |     py::class_<LonelyTraveler>(std::move(m), "LonelyTraveler"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void wrap_very_lonely_traveler(py::module_ m) { | ||||||
|  |     py::class_<VeryLonelyTraveler, LonelyTraveler>(std::move(m), "VeryLonelyTraveler"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace test_cpp_conduit
 | ||||||
|  | } // namespace pybind11_tests
 | ||||||
| @ -0,0 +1,25 @@ | |||||||
|  | // Copyright (c) 2024 The pybind Community.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | namespace pybind11_tests { | ||||||
|  | namespace test_cpp_conduit { | ||||||
|  | 
 | ||||||
|  | struct Traveler { | ||||||
|  |     explicit Traveler(const std::string &luggage) : luggage(luggage) {} | ||||||
|  |     std::string luggage; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct PremiumTraveler : Traveler { | ||||||
|  |     explicit PremiumTraveler(const std::string &luggage, int points) | ||||||
|  |         : Traveler(luggage), points(points) {} | ||||||
|  |     int points; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct LonelyTraveler {}; | ||||||
|  | struct VeryLonelyTraveler : LonelyTraveler {}; | ||||||
|  | 
 | ||||||
|  | } // namespace test_cpp_conduit
 | ||||||
|  | } // namespace pybind11_tests
 | ||||||
| @ -0,0 +1,46 @@ | |||||||
|  | #include <pybind11/functional.h> | ||||||
|  | #include <pybind11/pybind11.h> | ||||||
|  | 
 | ||||||
|  | #include "pybind11_tests.h" | ||||||
|  | 
 | ||||||
|  | namespace py = pybind11; | ||||||
|  | 
 | ||||||
|  | namespace { | ||||||
|  | 
 | ||||||
|  | struct SpecialReturn { | ||||||
|  |     int value = 99; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace
 | ||||||
|  | 
 | ||||||
|  | namespace pybind11 { | ||||||
|  | namespace detail { | ||||||
|  | namespace type_caster_std_function_specializations { | ||||||
|  | 
 | ||||||
|  | template <typename... Args> | ||||||
|  | struct func_wrapper<SpecialReturn, Args...> : func_wrapper_base { | ||||||
|  |     using func_wrapper_base::func_wrapper_base; | ||||||
|  |     SpecialReturn operator()(Args... args) const { | ||||||
|  |         gil_scoped_acquire acq; | ||||||
|  |         SpecialReturn result; | ||||||
|  |         try { | ||||||
|  |             result = hfunc.f(std::forward<Args>(args)...).template cast<SpecialReturn>(); | ||||||
|  |         } catch (error_already_set &) { | ||||||
|  |             result.value += 1; | ||||||
|  |         } | ||||||
|  |         result.value += 100; | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace type_caster_std_function_specializations
 | ||||||
|  | } // namespace detail
 | ||||||
|  | } // namespace pybind11
 | ||||||
|  | 
 | ||||||
|  | TEST_SUBMODULE(type_caster_std_function_specializations, m) { | ||||||
|  |     py::class_<SpecialReturn>(m, "SpecialReturn") | ||||||
|  |         .def(py::init<>()) | ||||||
|  |         .def_readwrite("value", &SpecialReturn::value); | ||||||
|  |     m.def("call_callback_with_special_return", | ||||||
|  |           [](const std::function<SpecialReturn()> &func) { return func(); }); | ||||||
|  | } | ||||||
| @ -0,0 +1,15 @@ | |||||||
|  | from __future__ import annotations | ||||||
|  | 
 | ||||||
|  | from pybind11_tests import type_caster_std_function_specializations as m | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_callback_with_special_return(): | ||||||
|  |     def return_special(): | ||||||
|  |         return m.SpecialReturn() | ||||||
|  | 
 | ||||||
|  |     def raise_exception(): | ||||||
|  |         raise ValueError("called raise_exception.") | ||||||
|  | 
 | ||||||
|  |     assert return_special().value == 99 | ||||||
|  |     assert m.call_callback_with_special_return(return_special).value == 199 | ||||||
|  |     assert m.call_callback_with_special_return(raise_exception).value == 200 | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user