@@ -53,9 +53,15 @@ exceptions:
53
53
| | a Python exception back to Python. |
54
54
+--------------------------------------+--------------------------------------+
55
55
56
- When a Python function invoked from C++ throws an exception, it is converted
57
- into a C++ exception of type :class: `error_already_set ` whose string payload
58
- contains a textual summary.
56
+ When a Python function invoked from C++ throws an exception, pybind11 will convert
57
+ it into a C++ exception of type :class: `error_already_set ` whose string payload
58
+ contains a textual summary. If you call the Python C-API directly, and it
59
+ returns an error, you should ``throw py::error_already_set(); ``, which allows
60
+ pybind11 to deal with the exception and pass it back to the Python interpreter.
61
+ (Another option is to call ``PyErr_Clear `` in the
62
+ `Python C-API <https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Clear >`_
63
+ to clear the error. The Python error must be thrown or cleared, or Python/pybind11
64
+ will be left in an invalid state.)
59
65
60
66
There is also a special exception :class: `cast_error ` that is thrown by
61
67
:func: `handle::call ` when the input arguments cannot be converted to Python
@@ -142,3 +148,43 @@ section.
142
148
Exceptions that you do not plan to handle should simply not be caught, or
143
149
may be explicitly (re-)thrown to delegate it to the other,
144
150
previously-declared existing exception translators.
151
+
152
+ .. _unraisable_exceptions :
153
+
154
+ Handling unraisable exceptions
155
+ ==============================
156
+
157
+ If a Python function invoked from a C++ destructor or any function marked
158
+ ``noexcept(true) `` (collectively, "noexcept functions") throws an exception, there
159
+ is no way to propagate the exception, as such functions may not throw at
160
+ run-time.
161
+
162
+ Neither Python nor C++ allow exceptions raised in a noexcept function to propagate. In
163
+ Python, an exception raised in a class's ``__del__ `` method is logged as an
164
+ unraisable error. In Python 3.8+, a system hook is triggered and an auditing
165
+ event is logged. In C++, ``std::terminate() `` is called to abort immediately.
166
+
167
+ Any noexcept function should have a try-catch block that traps
168
+ class:`error_already_set ` (or any other exception that can occur). Note that pybind11
169
+ wrappers around Python exceptions such as :class: `pybind11::value_error ` are *not *
170
+ Python exceptions; they are C++ exceptions that pybind11 catches and converts to
171
+ Python exceptions. Noexcept functions cannot propagate these exceptions either.
172
+ You can convert them to Python exceptions and then discard as unraisable.
173
+
174
+ .. code-block :: cpp
175
+
176
+ void nonthrowing_func() noexcept(true) {
177
+ try {
178
+ // ...
179
+ } catch (py::error_already_set &eas) {
180
+ // Discard the Python error using Python APIs, using the C++ magic
181
+ // variable __func__. Python already knows the type and value and of the
182
+ // exception object.
183
+ eas.discard_as_unraisable(__func__);
184
+ } catch (const std::exception &e) {
185
+ // Log and discard C++ exceptions.
186
+ // (We cannot use discard_as_unraisable, since we have a generic C++
187
+ // exception, not an exception that originated from Python.)
188
+ third_party::log(e);
189
+ }
190
+ }
0 commit comments