blob: b7d36014a68239c7518d00364522fbdb03f183bc [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+--------------------------------------+--------------------------------------+
46| :class:`pybind11::value_error` | ``ValueError`` (used to indicate |
47| | wrong value passed in |
48| | ``container.remove(...)``) |
49+--------------------------------------+--------------------------------------+
50| :class:`pybind11::key_error` | ``KeyError`` (used to indicate out |
51| | of bounds access in ``__getitem__``, |
52| | ``__setitem__`` in dict-like |
53| | objects, etc.) |
54+--------------------------------------+--------------------------------------+
Dean Moldovan67b52d82016-10-16 19:12:43 +020055
jbarlow83b8863692020-08-22 15:11:09 -070056Exception translation is not bidirectional. That is, *catching* the C++
57exceptions defined above above will not trap exceptions that originate from
58Python. For that, catch :class:`pybind11::error_already_set`. See :ref:`below
59<handling_python_exceptions_cpp>` for further details.
Dean Moldovan67b52d82016-10-16 19:12:43 +020060
61There is also a special exception :class:`cast_error` that is thrown by
62:func:`handle::call` when the input arguments cannot be converted to Python
63objects.
64
65Registering custom translators
66==============================
67
68If the default exception conversion policy described above is insufficient,
69pybind11 also provides support for registering custom exception translators.
70To register a simple exception conversion that translates a C++ exception into
71a new Python exception using the C++ exception's ``what()`` method, a helper
72function is available:
73
74.. code-block:: cpp
75
76 py::register_exception<CppExp>(module, "PyExp");
77
78This call creates a Python exception class with the name ``PyExp`` in the given
79module and automatically converts any encountered exceptions of type ``CppExp``
80into Python exceptions of type ``PyExp``.
81
82When more advanced exception translation is needed, the function
83``py::register_exception_translator(translator)`` can be used to register
84functions that can translate arbitrary exception types (and which may include
85additional logic to do so). The function takes a stateless callable (e.g. a
86function pointer or a lambda function without captured variables) with the call
87signature ``void(std::exception_ptr)``.
88
89When a C++ exception is thrown, the registered exception translators are tried
90in reverse order of registration (i.e. the last registered translator gets the
91first shot at handling the exception).
92
93Inside the translator, ``std::rethrow_exception`` should be used within
94a try block to re-throw the exception. One or more catch clauses to catch
95the appropriate exceptions should then be used with each clause using
96``PyErr_SetString`` to set a Python exception or ``ex(string)`` to set
97the python exception to a custom exception type (see below).
98
99To declare a custom Python exception type, declare a ``py::exception`` variable
100and use this in the associated exception translator (note: it is often useful
101to make this a static declaration when using it inside a lambda expression
102without requiring capturing).
103
Dean Moldovan67b52d82016-10-16 19:12:43 +0200104The following example demonstrates this for a hypothetical exception classes
105``MyCustomException`` and ``OtherException``: the first is translated to a
106custom python exception ``MyCustomError``, while the second is translated to a
107standard python RuntimeError:
108
109.. code-block:: cpp
110
111 static py::exception<MyCustomException> exc(m, "MyCustomError");
112 py::register_exception_translator([](std::exception_ptr p) {
113 try {
114 if (p) std::rethrow_exception(p);
115 } catch (const MyCustomException &e) {
116 exc(e.what());
117 } catch (const OtherException &e) {
118 PyErr_SetString(PyExc_RuntimeError, e.what());
119 }
120 });
121
122Multiple exceptions can be handled by a single translator, as shown in the
123example above. If the exception is not caught by the current translator, the
124previously registered one gets a chance.
125
126If none of the registered exception translators is able to handle the
127exception, it is handled by the default converter as described in the previous
128section.
129
130.. seealso::
131
132 The file :file:`tests/test_exceptions.cpp` contains examples
133 of various custom exception translators and custom exception types.
134
135.. note::
136
jbarlow83b8863692020-08-22 15:11:09 -0700137 Call either ``PyErr_SetString`` or a custom exception's call
Dean Moldovan67b52d82016-10-16 19:12:43 +0200138 operator (``exc(string)``) for every exception caught in a custom exception
139 translator. Failure to do so will cause Python to crash with ``SystemError:
140 error return without exception set``.
141
142 Exceptions that you do not plan to handle should simply not be caught, or
luz.paz28cb6762018-01-09 12:30:19 -0500143 may be explicitly (re-)thrown to delegate it to the other,
Dean Moldovan67b52d82016-10-16 19:12:43 +0200144 previously-declared existing exception translators.
James R. Barlow3618bea2020-08-08 03:07:14 -0700145
jbarlow83b8863692020-08-22 15:11:09 -0700146.. _handling_python_exceptions_cpp:
147
148Handling exceptions from Python in C++
149======================================
150
151When C++ calls Python functions, such as in a callback function or when
152manipulating Python objects, and Python raises an ``Exception``, pybind11
153converts the Python exception into a C++ exception of type
154:class:`pybind11::error_already_set` whose payload contains a C++ string textual
155summary and the actual Python exception. ``error_already_set`` is used to
156propagate Python exception back to Python (or possibly, handle them in C++).
157
158.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}|
159
160+--------------------------------------+--------------------------------------+
161| Exception raised in Python | Thrown as C++ exception type |
162+======================================+======================================+
163| Any Python ``Exception`` | :class:`pybind11::error_already_set` |
164+--------------------------------------+--------------------------------------+
165
166For example:
167
168.. code-block:: cpp
169
170 try {
171 // open("missing.txt", "r")
172 auto file = py::module::import("io").attr("open")("missing.txt", "r");
173 auto text = file.attr("read")();
174 file.attr("close")();
175 } catch (py::error_already_set &e) {
176 if (e.matches(PyExc_FileNotFoundError)) {
177 py::print("missing.txt not found");
178 } else if (e.match(PyExc_PermissionError)) {
179 py::print("missing.txt found but not accessible");
180 } else {
181 throw;
182 }
183 }
184
185Note that C++ to Python exception translation does not apply here, since that is
186a method for translating C++ exceptions to Python, not vice versa. The error raised
187from Python is always ``error_already_set``.
188
189This example illustrates this behavior:
190
191.. code-block:: cpp
192
193 try {
194 py::eval("raise ValueError('The Ring')");
195 } catch (py::value_error &boromir) {
196 // Boromir never gets the ring
197 assert(false);
198 } catch (py::error_already_set &frodo) {
199 // Frodo gets the ring
200 py::print("I will take the ring");
201 }
202
203 try {
204 // py::value_error is a request for pybind11 to raise a Python exception
205 throw py::value_error("The ball");
206 } catch (py::error_already_set &cat) {
207 // cat won't catch the ball since
208 // py::value_error is not a Python exception
209 assert(false);
210 } catch (py::value_error &dog) {
211 // dog will catch the ball
212 py::print("Run Spot run");
213 throw; // Throw it again (pybind11 will raise ValueError)
214 }
215
216Handling errors from the Python C API
217=====================================
218
219Where possible, use :ref:`pybind11 wrappers <wrappers>` instead of calling
220the Python C API directly. When calling the Python C API directly, in
221addition to manually managing reference counts, one must follow the pybind11
222error protocol, which is outlined here.
223
224After calling the Python C API, if Python returns an error,
225``throw py::error_already_set();``, which allows pybind11 to deal with the
226exception and pass it back to the Python interpreter. This includes calls to
227the error setting functions such as ``PyErr_SetString``.
228
229.. code-block:: cpp
230
231 PyErr_SetString(PyExc_TypeError, "C API type error demo");
232 throw py::error_already_set();
233
234 // But it would be easier to simply...
235 throw py::type_error("pybind11 wrapper type error");
236
237Alternately, to ignore the error, call `PyErr_Clear
238<https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Clear>`_.
239
240Any Python error must be thrown or cleared, or Python/pybind11 will be left in
241an invalid state.
242
James R. Barlow3618bea2020-08-08 03:07:14 -0700243.. _unraisable_exceptions:
244
245Handling unraisable exceptions
246==============================
247
248If a Python function invoked from a C++ destructor or any function marked
249``noexcept(true)`` (collectively, "noexcept functions") throws an exception, there
jbarlow83b8863692020-08-22 15:11:09 -0700250is no way to propagate the exception, as such functions may not throw.
251Should they throw or fail to catch any exceptions in their call graph,
252the C++ runtime calls ``std::terminate()`` to abort immediately.
James R. Barlow3618bea2020-08-08 03:07:14 -0700253
jbarlow83b8863692020-08-22 15:11:09 -0700254Similarly, Python exceptions raised in a class's ``__del__`` method do not
255propagate, but are logged by Python as an unraisable error. In Python 3.8+, a
256`system hook is triggered
257<https://docs.python.org/3/library/sys.html#sys.unraisablehook>`_
258and an auditing event is logged.
James R. Barlow3618bea2020-08-08 03:07:14 -0700259
260Any noexcept function should have a try-catch block that traps
jbarlow83b8863692020-08-22 15:11:09 -0700261class:`error_already_set` (or any other exception that can occur). Note that
262pybind11 wrappers around Python exceptions such as
263:class:`pybind11::value_error` are *not* Python exceptions; they are C++
264exceptions that pybind11 catches and converts to Python exceptions. Noexcept
265functions cannot propagate these exceptions either. A useful approach is to
266convert them to Python exceptions and then ``discard_as_unraisable`` as shown
267below.
James R. Barlow3618bea2020-08-08 03:07:14 -0700268
269.. code-block:: cpp
270
271 void nonthrowing_func() noexcept(true) {
272 try {
273 // ...
274 } catch (py::error_already_set &eas) {
275 // Discard the Python error using Python APIs, using the C++ magic
276 // variable __func__. Python already knows the type and value and of the
277 // exception object.
278 eas.discard_as_unraisable(__func__);
279 } catch (const std::exception &e) {
280 // Log and discard C++ exceptions.
James R. Barlow3618bea2020-08-08 03:07:14 -0700281 third_party::log(e);
282 }
283 }
Henry Schreinera6887b62020-08-19 14:53:59 -0400284
285.. versionadded:: 2.6