blob: 32ea69955e5e2846a0a1a7df4849abace840e58f [file] [log] [blame]
Dean Moldovan67b52d82016-10-16 19:12:43 +02001Exceptions
2##########
3
jbarlow83b8863692020-08-22 15:11:09 -07004Built-in C++ to Python exception translation
5============================================
Dean Moldovan67b52d82016-10-16 19:12:43 +02006
jbarlow83b8863692020-08-22 15:11:09 -07007When Python calls C++ code through pybind11, pybind11 provides a C++ exception handler
8that will trap C++ exceptions, translate them to the corresponding Python exception,
9and raise them so that Python code can handle them.
10
11pybind11 defines translations for ``std::exception`` and its standard
12subclasses, and several special exception classes that translate to specific
13Python exceptions. Note that these are not actually Python exceptions, so they
14cannot be examined using the Python C API. Instead, they are pure C++ objects
15that pybind11 will translate the corresponding Python exception when they arrive
16at its exception handler.
Dean Moldovan67b52d82016-10-16 19:12:43 +020017
18.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}|
19
Antony Lee8fbb5592018-03-11 16:15:56 -070020+--------------------------------------+--------------------------------------+
jbarlow83b8863692020-08-22 15:11:09 -070021| Exception thrown by C++ | Translated to Python exception type |
Antony Lee8fbb5592018-03-11 16:15:56 -070022+======================================+======================================+
23| :class:`std::exception` | ``RuntimeError`` |
24+--------------------------------------+--------------------------------------+
25| :class:`std::bad_alloc` | ``MemoryError`` |
26+--------------------------------------+--------------------------------------+
27| :class:`std::domain_error` | ``ValueError`` |
28+--------------------------------------+--------------------------------------+
29| :class:`std::invalid_argument` | ``ValueError`` |
30+--------------------------------------+--------------------------------------+
31| :class:`std::length_error` | ``ValueError`` |
32+--------------------------------------+--------------------------------------+
Wenzel Jakob51ca6b02019-06-11 22:47:37 +020033| :class:`std::out_of_range` | ``IndexError`` |
Antony Lee8fbb5592018-03-11 16:15:56 -070034+--------------------------------------+--------------------------------------+
35| :class:`std::range_error` | ``ValueError`` |
36+--------------------------------------+--------------------------------------+
Francesco Biscanideb3cb22019-11-14 08:56:58 +010037| :class:`std::overflow_error` | ``OverflowError`` |
38+--------------------------------------+--------------------------------------+
Antony Lee8fbb5592018-03-11 16:15:56 -070039| :class:`pybind11::stop_iteration` | ``StopIteration`` (used to implement |
40| | custom iterators) |
41+--------------------------------------+--------------------------------------+
42| :class:`pybind11::index_error` | ``IndexError`` (used to indicate out |
43| | of bounds access in ``__getitem__``, |
44| | ``__setitem__``, etc.) |
45+--------------------------------------+--------------------------------------+
Antony Lee8fbb5592018-03-11 16:15:56 -070046| :class:`pybind11::key_error` | ``KeyError`` (used to indicate out |
47| | of bounds access in ``__getitem__``, |
48| | ``__setitem__`` in dict-like |
49| | objects, etc.) |
50+--------------------------------------+--------------------------------------+
Jean-Baptiste Lespiauaf8849f2020-11-19 16:11:55 +010051| :class:`pybind11::value_error` | ``ValueError`` (used to indicate |
52| | wrong value passed in |
53| | ``container.remove(...)``) |
54+--------------------------------------+--------------------------------------+
55| :class:`pybind11::type_error` | ``TypeError`` |
56+--------------------------------------+--------------------------------------+
57| :class:`pybind11::buffer_error` | ``BufferError`` |
58+--------------------------------------+--------------------------------------+
59| :class:`pybind11::import_error` | ``import_error`` |
60+--------------------------------------+--------------------------------------+
61| Any other exception | ``RuntimeError`` |
62+--------------------------------------+--------------------------------------+
Dean Moldovan67b52d82016-10-16 19:12:43 +020063
jbarlow83b8863692020-08-22 15:11:09 -070064Exception translation is not bidirectional. That is, *catching* the C++
65exceptions defined above above will not trap exceptions that originate from
66Python. For that, catch :class:`pybind11::error_already_set`. See :ref:`below
67<handling_python_exceptions_cpp>` for further details.
Dean Moldovan67b52d82016-10-16 19:12:43 +020068
69There is also a special exception :class:`cast_error` that is thrown by
70:func:`handle::call` when the input arguments cannot be converted to Python
71objects.
72
73Registering custom translators
74==============================
75
76If the default exception conversion policy described above is insufficient,
77pybind11 also provides support for registering custom exception translators.
78To register a simple exception conversion that translates a C++ exception into
79a new Python exception using the C++ exception's ``what()`` method, a helper
80function is available:
81
82.. code-block:: cpp
83
84 py::register_exception<CppExp>(module, "PyExp");
85
86This call creates a Python exception class with the name ``PyExp`` in the given
87module and automatically converts any encountered exceptions of type ``CppExp``
88into Python exceptions of type ``PyExp``.
89
michalsustr3bd0d7a2020-09-06 05:35:53 -060090It is possible to specify base class for the exception using the third
Yannick Jadoul16f199f2020-09-15 16:24:39 +020091parameter, a `handle`:
michalsustr3bd0d7a2020-09-06 05:35:53 -060092
93.. code-block:: cpp
94
95 py::register_exception<CppExp>(module, "PyExp", PyExc_RuntimeError);
96
97Then `PyExp` can be caught both as `PyExp` and `RuntimeError`.
98
99The class objects of the built-in Python exceptions are listed in the Python
100documentation on `Standard Exceptions <https://docs.python.org/3/c-api/exceptions.html#standard-exceptions>`_.
101The default base class is `PyExc_Exception`.
102
Dean Moldovan67b52d82016-10-16 19:12:43 +0200103When more advanced exception translation is needed, the function
104``py::register_exception_translator(translator)`` can be used to register
105functions that can translate arbitrary exception types (and which may include
106additional logic to do so). The function takes a stateless callable (e.g. a
107function pointer or a lambda function without captured variables) with the call
108signature ``void(std::exception_ptr)``.
109
110When a C++ exception is thrown, the registered exception translators are tried
111in reverse order of registration (i.e. the last registered translator gets the
112first shot at handling the exception).
113
114Inside the translator, ``std::rethrow_exception`` should be used within
115a try block to re-throw the exception. One or more catch clauses to catch
116the appropriate exceptions should then be used with each clause using
117``PyErr_SetString`` to set a Python exception or ``ex(string)`` to set
118the python exception to a custom exception type (see below).
119
120To declare a custom Python exception type, declare a ``py::exception`` variable
121and use this in the associated exception translator (note: it is often useful
122to make this a static declaration when using it inside a lambda expression
123without requiring capturing).
124
Dean Moldovan67b52d82016-10-16 19:12:43 +0200125The following example demonstrates this for a hypothetical exception classes
126``MyCustomException`` and ``OtherException``: the first is translated to a
127custom python exception ``MyCustomError``, while the second is translated to a
128standard python RuntimeError:
129
130.. code-block:: cpp
131
132 static py::exception<MyCustomException> exc(m, "MyCustomError");
133 py::register_exception_translator([](std::exception_ptr p) {
134 try {
135 if (p) std::rethrow_exception(p);
136 } catch (const MyCustomException &e) {
137 exc(e.what());
138 } catch (const OtherException &e) {
139 PyErr_SetString(PyExc_RuntimeError, e.what());
140 }
141 });
142
143Multiple exceptions can be handled by a single translator, as shown in the
144example above. If the exception is not caught by the current translator, the
145previously registered one gets a chance.
146
147If none of the registered exception translators is able to handle the
148exception, it is handled by the default converter as described in the previous
149section.
150
151.. seealso::
152
153 The file :file:`tests/test_exceptions.cpp` contains examples
154 of various custom exception translators and custom exception types.
155
156.. note::
157
jbarlow83b8863692020-08-22 15:11:09 -0700158 Call either ``PyErr_SetString`` or a custom exception's call
Dean Moldovan67b52d82016-10-16 19:12:43 +0200159 operator (``exc(string)``) for every exception caught in a custom exception
160 translator. Failure to do so will cause Python to crash with ``SystemError:
161 error return without exception set``.
162
163 Exceptions that you do not plan to handle should simply not be caught, or
luz.paz28cb6762018-01-09 12:30:19 -0500164 may be explicitly (re-)thrown to delegate it to the other,
Dean Moldovan67b52d82016-10-16 19:12:43 +0200165 previously-declared existing exception translators.
James R. Barlow3618bea2020-08-08 03:07:14 -0700166
jbarlow83b8863692020-08-22 15:11:09 -0700167.. _handling_python_exceptions_cpp:
168
169Handling exceptions from Python in C++
170======================================
171
172When C++ calls Python functions, such as in a callback function or when
173manipulating Python objects, and Python raises an ``Exception``, pybind11
174converts the Python exception into a C++ exception of type
175:class:`pybind11::error_already_set` whose payload contains a C++ string textual
176summary and the actual Python exception. ``error_already_set`` is used to
177propagate Python exception back to Python (or possibly, handle them in C++).
178
179.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}|
180
181+--------------------------------------+--------------------------------------+
182| Exception raised in Python | Thrown as C++ exception type |
183+======================================+======================================+
184| Any Python ``Exception`` | :class:`pybind11::error_already_set` |
185+--------------------------------------+--------------------------------------+
186
187For example:
188
189.. code-block:: cpp
190
191 try {
192 // open("missing.txt", "r")
Henry Schreiner6bcd2202020-10-03 13:38:03 -0400193 auto file = py::module_::import("io").attr("open")("missing.txt", "r");
jbarlow83b8863692020-08-22 15:11:09 -0700194 auto text = file.attr("read")();
195 file.attr("close")();
196 } catch (py::error_already_set &e) {
197 if (e.matches(PyExc_FileNotFoundError)) {
198 py::print("missing.txt not found");
199 } else if (e.match(PyExc_PermissionError)) {
200 py::print("missing.txt found but not accessible");
201 } else {
202 throw;
203 }
204 }
205
206Note that C++ to Python exception translation does not apply here, since that is
207a method for translating C++ exceptions to Python, not vice versa. The error raised
208from Python is always ``error_already_set``.
209
210This example illustrates this behavior:
211
212.. code-block:: cpp
213
214 try {
215 py::eval("raise ValueError('The Ring')");
216 } catch (py::value_error &boromir) {
217 // Boromir never gets the ring
218 assert(false);
219 } catch (py::error_already_set &frodo) {
220 // Frodo gets the ring
221 py::print("I will take the ring");
222 }
223
224 try {
225 // py::value_error is a request for pybind11 to raise a Python exception
226 throw py::value_error("The ball");
227 } catch (py::error_already_set &cat) {
228 // cat won't catch the ball since
229 // py::value_error is not a Python exception
230 assert(false);
231 } catch (py::value_error &dog) {
232 // dog will catch the ball
233 py::print("Run Spot run");
234 throw; // Throw it again (pybind11 will raise ValueError)
235 }
236
237Handling errors from the Python C API
238=====================================
239
240Where possible, use :ref:`pybind11 wrappers <wrappers>` instead of calling
241the Python C API directly. When calling the Python C API directly, in
242addition to manually managing reference counts, one must follow the pybind11
243error protocol, which is outlined here.
244
245After calling the Python C API, if Python returns an error,
246``throw py::error_already_set();``, which allows pybind11 to deal with the
247exception and pass it back to the Python interpreter. This includes calls to
248the error setting functions such as ``PyErr_SetString``.
249
250.. code-block:: cpp
251
252 PyErr_SetString(PyExc_TypeError, "C API type error demo");
253 throw py::error_already_set();
254
255 // But it would be easier to simply...
256 throw py::type_error("pybind11 wrapper type error");
257
258Alternately, to ignore the error, call `PyErr_Clear
259<https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Clear>`_.
260
261Any Python error must be thrown or cleared, or Python/pybind11 will be left in
262an invalid state.
263
James R. Barlow3618bea2020-08-08 03:07:14 -0700264.. _unraisable_exceptions:
265
266Handling unraisable exceptions
267==============================
268
269If a Python function invoked from a C++ destructor or any function marked
270``noexcept(true)`` (collectively, "noexcept functions") throws an exception, there
jbarlow83b8863692020-08-22 15:11:09 -0700271is no way to propagate the exception, as such functions may not throw.
272Should they throw or fail to catch any exceptions in their call graph,
273the C++ runtime calls ``std::terminate()`` to abort immediately.
James R. Barlow3618bea2020-08-08 03:07:14 -0700274
jbarlow83b8863692020-08-22 15:11:09 -0700275Similarly, Python exceptions raised in a class's ``__del__`` method do not
276propagate, but are logged by Python as an unraisable error. In Python 3.8+, a
277`system hook is triggered
278<https://docs.python.org/3/library/sys.html#sys.unraisablehook>`_
279and an auditing event is logged.
James R. Barlow3618bea2020-08-08 03:07:14 -0700280
281Any noexcept function should have a try-catch block that traps
jbarlow83b8863692020-08-22 15:11:09 -0700282class:`error_already_set` (or any other exception that can occur). Note that
283pybind11 wrappers around Python exceptions such as
284:class:`pybind11::value_error` are *not* Python exceptions; they are C++
285exceptions that pybind11 catches and converts to Python exceptions. Noexcept
286functions cannot propagate these exceptions either. A useful approach is to
287convert them to Python exceptions and then ``discard_as_unraisable`` as shown
288below.
James R. Barlow3618bea2020-08-08 03:07:14 -0700289
290.. code-block:: cpp
291
292 void nonthrowing_func() noexcept(true) {
293 try {
294 // ...
295 } catch (py::error_already_set &eas) {
296 // Discard the Python error using Python APIs, using the C++ magic
297 // variable __func__. Python already knows the type and value and of the
298 // exception object.
299 eas.discard_as_unraisable(__func__);
300 } catch (const std::exception &e) {
301 // Log and discard C++ exceptions.
James R. Barlow3618bea2020-08-08 03:07:14 -0700302 third_party::log(e);
303 }
304 }
Henry Schreinera6887b62020-08-19 14:53:59 -0400305
306.. versionadded:: 2.6