Skip to content

Commit a30bbd0

Browse files
committed
fix build
1 parent e15da84 commit a30bbd0

21 files changed

+1706
-0
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: WASM
2+
3+
on:
4+
workflow_dispatch:
5+
pull_request:
6+
branches:
7+
- master
8+
- stable
9+
- v*
10+
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
build-wasm-emscripten:
17+
name: Pyodide wheel
18+
runs-on: ubuntu-22.04
19+
steps:
20+
- uses: actions/checkout@v4
21+
with:
22+
submodules: true
23+
fetch-depth: 0
24+
25+
- uses: pypa/[email protected]
26+
env:
27+
PYODIDE_BUILD_EXPORTS: whole_archive
28+
with:
29+
package-dir: tests
30+
only: cp312-pyodide_wasm32
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
Functional
2+
##########
3+
4+
The following features must be enabled by including :file:`pybind11/functional.h`.
5+
6+
7+
Callbacks and passing anonymous functions
8+
=========================================
9+
10+
The C++11 standard brought lambda functions and the generic polymorphic
11+
function wrapper ``std::function<>`` to the C++ programming language, which
12+
enable powerful new ways of working with functions. Lambda functions come in
13+
two flavors: stateless lambda function resemble classic function pointers that
14+
link to an anonymous piece of code, while stateful lambda functions
15+
additionally depend on captured variables that are stored in an anonymous
16+
*lambda closure object*.
17+
18+
Here is a simple example of a C++ function that takes an arbitrary function
19+
(stateful or stateless) with signature ``int -> int`` as an argument and runs
20+
it with the value 10.
21+
22+
.. code-block:: cpp
23+
24+
int func_arg(const std::function<int(int)> &f) {
25+
return f(10);
26+
}
27+
28+
The example below is more involved: it takes a function of signature ``int -> int``
29+
and returns another function of the same kind. The return value is a stateful
30+
lambda function, which stores the value ``f`` in the capture object and adds 1 to
31+
its return value upon execution.
32+
33+
.. code-block:: cpp
34+
35+
std::function<int(int)> func_ret(const std::function<int(int)> &f) {
36+
return [f](int i) {
37+
return f(i) + 1;
38+
};
39+
}
40+
41+
This example demonstrates using python named parameters in C++ callbacks which
42+
requires using ``py::cpp_function`` as a wrapper. Usage is similar to defining
43+
methods of classes:
44+
45+
.. code-block:: cpp
46+
47+
py::cpp_function func_cpp() {
48+
return py::cpp_function([](int i) { return i+1; },
49+
py::arg("number"));
50+
}
51+
52+
After including the extra header file :file:`pybind11/functional.h`, it is almost
53+
trivial to generate binding code for all of these functions.
54+
55+
.. code-block:: cpp
56+
57+
#include <pybind11/functional.h>
58+
59+
PYBIND11_MODULE(example, m) {
60+
m.def("func_arg", &func_arg);
61+
m.def("func_ret", &func_ret);
62+
m.def("func_cpp", &func_cpp);
63+
}
64+
65+
The following interactive session shows how to call them from Python.
66+
67+
.. code-block:: pycon
68+
69+
$ python
70+
>>> import example
71+
>>> def square(i):
72+
... return i * i
73+
...
74+
>>> example.func_arg(square)
75+
100L
76+
>>> square_plus_1 = example.func_ret(square)
77+
>>> square_plus_1(4)
78+
17L
79+
>>> plus_1 = func_cpp()
80+
>>> plus_1(number=43)
81+
44L
82+
83+
.. warning::
84+
85+
Keep in mind that passing a function from C++ to Python (or vice versa)
86+
will instantiate a piece of wrapper code that translates function
87+
invocations between the two languages. Naturally, this translation
88+
increases the computational cost of each function call somewhat. A
89+
problematic situation can arise when a function is copied back and forth
90+
between Python and C++ many times in a row, in which case the underlying
91+
wrappers will accumulate correspondingly. The resulting long sequence of
92+
C++ -> Python -> C++ -> ... roundtrips can significantly decrease
93+
performance.
94+
95+
There is one exception: pybind11 detects case where a stateless function
96+
(i.e. a function pointer or a lambda function without captured variables)
97+
is passed as an argument to another C++ function exposed in Python. In this
98+
case, there is no overhead. Pybind11 will extract the underlying C++
99+
function pointer from the wrapped function to sidestep a potential C++ ->
100+
Python -> C++ roundtrip. This is demonstrated in :file:`tests/test_callbacks.cpp`.
101+
102+
.. note::
103+
104+
This functionality is very useful when generating bindings for callbacks in
105+
C++ libraries (e.g. GUI libraries, asynchronous networking libraries, etc.).
106+
107+
The file :file:`tests/test_callbacks.cpp` contains a complete example
108+
that demonstrates how to work with callbacks and anonymous functions in
109+
more detail.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Python C++ interface
2+
####################
3+
4+
pybind11 exposes Python types and functions using thin C++ wrappers, which
5+
makes it possible to conveniently call Python code from C++ without resorting
6+
to Python's C API.
7+
8+
.. toctree::
9+
:maxdepth: 2
10+
11+
object
12+
numpy
13+
utilities
43.6 KB
Loading

examples/knxPython/pybind11/docs/pybind11_vs_boost_python1.svg

Lines changed: 427 additions & 0 deletions
Loading
40.2 KB
Loading

examples/knxPython/pybind11/docs/pybind11_vs_boost_python2.svg

Lines changed: 427 additions & 0 deletions
Loading
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "detail/common.h"
2+
#warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'."
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) 2024 The pybind Community.
2+
3+
#pragma once
4+
5+
#include <pybind11/pytypes.h>
6+
7+
#include "common.h"
8+
#include "internals.h"
9+
10+
#include <typeinfo>
11+
12+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
13+
PYBIND11_NAMESPACE_BEGIN(detail)
14+
15+
// Forward declaration needed here: Refactoring opportunity.
16+
extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *);
17+
18+
inline bool type_is_managed_by_our_internals(PyTypeObject *type_obj) {
19+
#if defined(PYPY_VERSION)
20+
auto &internals = get_internals();
21+
return bool(internals.registered_types_py.find(type_obj)
22+
!= internals.registered_types_py.end());
23+
#else
24+
return bool(type_obj->tp_new == pybind11_object_new);
25+
#endif
26+
}
27+
28+
inline bool is_instance_method_of_type(PyTypeObject *type_obj, PyObject *attr_name) {
29+
PyObject *descr = _PyType_Lookup(type_obj, attr_name);
30+
return bool((descr != nullptr) && PyInstanceMethod_Check(descr));
31+
}
32+
33+
inline object try_get_cpp_conduit_method(PyObject *obj) {
34+
if (PyType_Check(obj)) {
35+
return object();
36+
}
37+
PyTypeObject *type_obj = Py_TYPE(obj);
38+
str attr_name("_pybind11_conduit_v1_");
39+
bool assumed_to_be_callable = false;
40+
if (type_is_managed_by_our_internals(type_obj)) {
41+
if (!is_instance_method_of_type(type_obj, attr_name.ptr())) {
42+
return object();
43+
}
44+
assumed_to_be_callable = true;
45+
}
46+
PyObject *method = PyObject_GetAttr(obj, attr_name.ptr());
47+
if (method == nullptr) {
48+
PyErr_Clear();
49+
return object();
50+
}
51+
if (!assumed_to_be_callable && PyCallable_Check(method) == 0) {
52+
Py_DECREF(method);
53+
return object();
54+
}
55+
return reinterpret_steal<object>(method);
56+
}
57+
58+
inline void *try_raw_pointer_ephemeral_from_cpp_conduit(handle src,
59+
const std::type_info *cpp_type_info) {
60+
object method = try_get_cpp_conduit_method(src.ptr());
61+
if (method) {
62+
capsule cpp_type_info_capsule(const_cast<void *>(static_cast<const void *>(cpp_type_info)),
63+
typeid(std::type_info).name());
64+
object cpp_conduit = method(bytes(PYBIND11_PLATFORM_ABI_ID),
65+
cpp_type_info_capsule,
66+
bytes("raw_pointer_ephemeral"));
67+
if (isinstance<capsule>(cpp_conduit)) {
68+
return reinterpret_borrow<capsule>(cpp_conduit).get_pointer();
69+
}
70+
}
71+
return nullptr;
72+
}
73+
74+
#define PYBIND11_HAS_CPP_CONDUIT 1
75+
76+
PYBIND11_NAMESPACE_END(detail)
77+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
pybind11/detail/exception_translation.h: means to translate C++ exceptions to Python exceptions
3+
4+
Copyright (c) 2024 The Pybind Development Team.
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+
#pragma once
11+
12+
#include "common.h"
13+
#include "internals.h"
14+
15+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
16+
PYBIND11_NAMESPACE_BEGIN(detail)
17+
18+
// Apply all the extensions translators from a list
19+
// Return true if one of the translators completed without raising an exception
20+
// itself. Return of false indicates that if there are other translators
21+
// available, they should be tried.
22+
inline bool apply_exception_translators(std::forward_list<ExceptionTranslator> &translators) {
23+
auto last_exception = std::current_exception();
24+
25+
for (auto &translator : translators) {
26+
try {
27+
translator(last_exception);
28+
return true;
29+
} catch (...) {
30+
last_exception = std::current_exception();
31+
}
32+
}
33+
return false;
34+
}
35+
36+
inline void try_translate_exceptions() {
37+
/* When an exception is caught, give each registered exception
38+
translator a chance to translate it to a Python exception. First
39+
all module-local translators will be tried in reverse order of
40+
registration. If none of the module-locale translators handle
41+
the exception (or there are no module-locale translators) then
42+
the global translators will be tried, also in reverse order of
43+
registration.
44+
45+
A translator may choose to do one of the following:
46+
47+
- catch the exception and call py::set_error()
48+
to set a standard (or custom) Python exception, or
49+
- do nothing and let the exception fall through to the next translator, or
50+
- delegate translation to the next translator by throwing a new type of exception.
51+
*/
52+
53+
bool handled = with_internals([&](internals &internals) {
54+
auto &local_exception_translators = get_local_internals().registered_exception_translators;
55+
if (detail::apply_exception_translators(local_exception_translators)) {
56+
return true;
57+
}
58+
auto &exception_translators = internals.registered_exception_translators;
59+
if (detail::apply_exception_translators(exception_translators)) {
60+
return true;
61+
}
62+
return false;
63+
});
64+
65+
if (!handled) {
66+
set_error(PyExc_SystemError, "Exception escaped from default exception translator!");
67+
}
68+
}
69+
70+
PYBIND11_NAMESPACE_END(detail)
71+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

0 commit comments

Comments
 (0)