github.com/kaydxh/golang@v0.0.131/pkg/gocv/cgo/third_path/pybind11/docs/advanced/exceptions.rst (about) 1 Exceptions 2 ########## 3 4 Built-in C++ to Python exception translation 5 ============================================ 6 7 When Python calls C++ code through pybind11, pybind11 provides a C++ exception handler 8 that will trap C++ exceptions, translate them to the corresponding Python exception, 9 and raise them so that Python code can handle them. 10 11 pybind11 defines translations for ``std::exception`` and its standard 12 subclasses, and several special exception classes that translate to specific 13 Python exceptions. Note that these are not actually Python exceptions, so they 14 cannot be examined using the Python C API. Instead, they are pure C++ objects 15 that pybind11 will translate the corresponding Python exception when they arrive 16 at its exception handler. 17 18 .. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}| 19 20 +--------------------------------------+--------------------------------------+ 21 | Exception thrown by C++ | Translated to Python exception type | 22 +======================================+======================================+ 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 +--------------------------------------+--------------------------------------+ 33 | :class:`std::out_of_range` | ``IndexError`` | 34 +--------------------------------------+--------------------------------------+ 35 | :class:`std::range_error` | ``ValueError`` | 36 +--------------------------------------+--------------------------------------+ 37 | :class:`std::overflow_error` | ``OverflowError`` | 38 +--------------------------------------+--------------------------------------+ 39 | :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::key_error` | ``KeyError`` (used to indicate out | 47 | | of bounds access in ``__getitem__``, | 48 | | ``__setitem__`` in dict-like | 49 | | objects, etc.) | 50 +--------------------------------------+--------------------------------------+ 51 | :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` | ``ImportError`` | 60 +--------------------------------------+--------------------------------------+ 61 | :class:`pybind11::attribute_error` | ``AttributeError`` | 62 +--------------------------------------+--------------------------------------+ 63 | Any other exception | ``RuntimeError`` | 64 +--------------------------------------+--------------------------------------+ 65 66 Exception translation is not bidirectional. That is, *catching* the C++ 67 exceptions defined above will not trap exceptions that originate from 68 Python. For that, catch :class:`pybind11::error_already_set`. See :ref:`below 69 <handling_python_exceptions_cpp>` for further details. 70 71 There is also a special exception :class:`cast_error` that is thrown by 72 :func:`handle::call` when the input arguments cannot be converted to Python 73 objects. 74 75 Registering custom translators 76 ============================== 77 78 If the default exception conversion policy described above is insufficient, 79 pybind11 also provides support for registering custom exception translators. 80 Similar to pybind11 classes, exception translators can be local to the module 81 they are defined in or global to the entire python session. To register a simple 82 exception conversion that translates a C++ exception into a new Python exception 83 using the C++ exception's ``what()`` method, a helper function is available: 84 85 .. code-block:: cpp 86 87 py::register_exception<CppExp>(module, "PyExp"); 88 89 This call creates a Python exception class with the name ``PyExp`` in the given 90 module and automatically converts any encountered exceptions of type ``CppExp`` 91 into Python exceptions of type ``PyExp``. 92 93 A matching function is available for registering a local exception translator: 94 95 .. code-block:: cpp 96 97 py::register_local_exception<CppExp>(module, "PyExp"); 98 99 100 It is possible to specify base class for the exception using the third 101 parameter, a ``handle``: 102 103 .. code-block:: cpp 104 105 py::register_exception<CppExp>(module, "PyExp", PyExc_RuntimeError); 106 py::register_local_exception<CppExp>(module, "PyExp", PyExc_RuntimeError); 107 108 Then ``PyExp`` can be caught both as ``PyExp`` and ``RuntimeError``. 109 110 The class objects of the built-in Python exceptions are listed in the Python 111 documentation on `Standard Exceptions <https://docs.python.org/3/c-api/exceptions.html#standard-exceptions>`_. 112 The default base class is ``PyExc_Exception``. 113 114 When more advanced exception translation is needed, the functions 115 ``py::register_exception_translator(translator)`` and 116 ``py::register_local_exception_translator(translator)`` can be used to register 117 functions that can translate arbitrary exception types (and which may include 118 additional logic to do so). The functions takes a stateless callable (e.g. a 119 function pointer or a lambda function without captured variables) with the call 120 signature ``void(std::exception_ptr)``. 121 122 When a C++ exception is thrown, the registered exception translators are tried 123 in reverse order of registration (i.e. the last registered translator gets the 124 first shot at handling the exception). All local translators will be tried 125 before a global translator is tried. 126 127 Inside the translator, ``std::rethrow_exception`` should be used within 128 a try block to re-throw the exception. One or more catch clauses to catch 129 the appropriate exceptions should then be used with each clause using 130 ``PyErr_SetString`` to set a Python exception or ``ex(string)`` to set 131 the python exception to a custom exception type (see below). 132 133 To declare a custom Python exception type, declare a ``py::exception`` variable 134 and use this in the associated exception translator (note: it is often useful 135 to make this a static declaration when using it inside a lambda expression 136 without requiring capturing). 137 138 The following example demonstrates this for a hypothetical exception classes 139 ``MyCustomException`` and ``OtherException``: the first is translated to a 140 custom python exception ``MyCustomError``, while the second is translated to a 141 standard python RuntimeError: 142 143 .. code-block:: cpp 144 145 static py::exception<MyCustomException> exc(m, "MyCustomError"); 146 py::register_exception_translator([](std::exception_ptr p) { 147 try { 148 if (p) std::rethrow_exception(p); 149 } catch (const MyCustomException &e) { 150 exc(e.what()); 151 } catch (const OtherException &e) { 152 PyErr_SetString(PyExc_RuntimeError, e.what()); 153 } 154 }); 155 156 Multiple exceptions can be handled by a single translator, as shown in the 157 example above. If the exception is not caught by the current translator, the 158 previously registered one gets a chance. 159 160 If none of the registered exception translators is able to handle the 161 exception, it is handled by the default converter as described in the previous 162 section. 163 164 .. seealso:: 165 166 The file :file:`tests/test_exceptions.cpp` contains examples 167 of various custom exception translators and custom exception types. 168 169 .. note:: 170 171 Call either ``PyErr_SetString`` or a custom exception's call 172 operator (``exc(string)``) for every exception caught in a custom exception 173 translator. Failure to do so will cause Python to crash with ``SystemError: 174 error return without exception set``. 175 176 Exceptions that you do not plan to handle should simply not be caught, or 177 may be explicitly (re-)thrown to delegate it to the other, 178 previously-declared existing exception translators. 179 180 Note that ``libc++`` and ``libstdc++`` `behave differently under macOS 181 <https://stackoverflow.com/questions/19496643/using-clang-fvisibility-hidden-and-typeinfo-and-type-erasure/28827430>`_ 182 with ``-fvisibility=hidden``. Therefore exceptions that are used across ABI 183 boundaries need to be explicitly exported, as exercised in 184 ``tests/test_exceptions.h``. See also: 185 "Problems with C++ exceptions" under `GCC Wiki <https://gcc.gnu.org/wiki/Visibility>`_. 186 187 188 Local vs Global Exception Translators 189 ===================================== 190 191 When a global exception translator is registered, it will be applied across all 192 modules in the reverse order of registration. This can create behavior where the 193 order of module import influences how exceptions are translated. 194 195 If module1 has the following translator: 196 197 .. code-block:: cpp 198 199 py::register_exception_translator([](std::exception_ptr p) { 200 try { 201 if (p) std::rethrow_exception(p); 202 } catch (const std::invalid_argument &e) { 203 PyErr_SetString("module1 handled this") 204 } 205 } 206 207 and module2 has the following similar translator: 208 209 .. code-block:: cpp 210 211 py::register_exception_translator([](std::exception_ptr p) { 212 try { 213 if (p) std::rethrow_exception(p); 214 } catch (const std::invalid_argument &e) { 215 PyErr_SetString("module2 handled this") 216 } 217 } 218 219 then which translator handles the invalid_argument will be determined by the 220 order that module1 and module2 are imported. Since exception translators are 221 applied in the reverse order of registration, which ever module was imported 222 last will "win" and that translator will be applied. 223 224 If there are multiple pybind11 modules that share exception types (either 225 standard built-in or custom) loaded into a single python instance and 226 consistent error handling behavior is needed, then local translators should be 227 used. 228 229 Changing the previous example to use ``register_local_exception_translator`` 230 would mean that when invalid_argument is thrown in the module2 code, the 231 module2 translator will always handle it, while in module1, the module1 232 translator will do the same. 233 234 .. _handling_python_exceptions_cpp: 235 236 Handling exceptions from Python in C++ 237 ====================================== 238 239 When C++ calls Python functions, such as in a callback function or when 240 manipulating Python objects, and Python raises an ``Exception``, pybind11 241 converts the Python exception into a C++ exception of type 242 :class:`pybind11::error_already_set` whose payload contains a C++ string textual 243 summary and the actual Python exception. ``error_already_set`` is used to 244 propagate Python exception back to Python (or possibly, handle them in C++). 245 246 .. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}| 247 248 +--------------------------------------+--------------------------------------+ 249 | Exception raised in Python | Thrown as C++ exception type | 250 +======================================+======================================+ 251 | Any Python ``Exception`` | :class:`pybind11::error_already_set` | 252 +--------------------------------------+--------------------------------------+ 253 254 For example: 255 256 .. code-block:: cpp 257 258 try { 259 // open("missing.txt", "r") 260 auto file = py::module_::import("io").attr("open")("missing.txt", "r"); 261 auto text = file.attr("read")(); 262 file.attr("close")(); 263 } catch (py::error_already_set &e) { 264 if (e.matches(PyExc_FileNotFoundError)) { 265 py::print("missing.txt not found"); 266 } else if (e.matches(PyExc_PermissionError)) { 267 py::print("missing.txt found but not accessible"); 268 } else { 269 throw; 270 } 271 } 272 273 Note that C++ to Python exception translation does not apply here, since that is 274 a method for translating C++ exceptions to Python, not vice versa. The error raised 275 from Python is always ``error_already_set``. 276 277 This example illustrates this behavior: 278 279 .. code-block:: cpp 280 281 try { 282 py::eval("raise ValueError('The Ring')"); 283 } catch (py::value_error &boromir) { 284 // Boromir never gets the ring 285 assert(false); 286 } catch (py::error_already_set &frodo) { 287 // Frodo gets the ring 288 py::print("I will take the ring"); 289 } 290 291 try { 292 // py::value_error is a request for pybind11 to raise a Python exception 293 throw py::value_error("The ball"); 294 } catch (py::error_already_set &cat) { 295 // cat won't catch the ball since 296 // py::value_error is not a Python exception 297 assert(false); 298 } catch (py::value_error &dog) { 299 // dog will catch the ball 300 py::print("Run Spot run"); 301 throw; // Throw it again (pybind11 will raise ValueError) 302 } 303 304 Handling errors from the Python C API 305 ===================================== 306 307 Where possible, use :ref:`pybind11 wrappers <wrappers>` instead of calling 308 the Python C API directly. When calling the Python C API directly, in 309 addition to manually managing reference counts, one must follow the pybind11 310 error protocol, which is outlined here. 311 312 After calling the Python C API, if Python returns an error, 313 ``throw py::error_already_set();``, which allows pybind11 to deal with the 314 exception and pass it back to the Python interpreter. This includes calls to 315 the error setting functions such as ``PyErr_SetString``. 316 317 .. code-block:: cpp 318 319 PyErr_SetString(PyExc_TypeError, "C API type error demo"); 320 throw py::error_already_set(); 321 322 // But it would be easier to simply... 323 throw py::type_error("pybind11 wrapper type error"); 324 325 Alternately, to ignore the error, call `PyErr_Clear 326 <https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Clear>`_. 327 328 Any Python error must be thrown or cleared, or Python/pybind11 will be left in 329 an invalid state. 330 331 Chaining exceptions ('raise from') 332 ================================== 333 334 Python has a mechanism for indicating that exceptions were caused by other 335 exceptions: 336 337 .. code-block:: py 338 339 try: 340 print(1 / 0) 341 except Exception as exc: 342 raise RuntimeError("could not divide by zero") from exc 343 344 To do a similar thing in pybind11, you can use the ``py::raise_from`` function. It 345 sets the current python error indicator, so to continue propagating the exception 346 you should ``throw py::error_already_set()``. 347 348 .. code-block:: cpp 349 350 try { 351 py::eval("print(1 / 0")); 352 } catch (py::error_already_set &e) { 353 py::raise_from(e, PyExc_RuntimeError, "could not divide by zero"); 354 throw py::error_already_set(); 355 } 356 357 .. versionadded:: 2.8 358 359 .. _unraisable_exceptions: 360 361 Handling unraisable exceptions 362 ============================== 363 364 If a Python function invoked from a C++ destructor or any function marked 365 ``noexcept(true)`` (collectively, "noexcept functions") throws an exception, there 366 is no way to propagate the exception, as such functions may not throw. 367 Should they throw or fail to catch any exceptions in their call graph, 368 the C++ runtime calls ``std::terminate()`` to abort immediately. 369 370 Similarly, Python exceptions raised in a class's ``__del__`` method do not 371 propagate, but are logged by Python as an unraisable error. In Python 3.8+, a 372 `system hook is triggered 373 <https://docs.python.org/3/library/sys.html#sys.unraisablehook>`_ 374 and an auditing event is logged. 375 376 Any noexcept function should have a try-catch block that traps 377 class:`error_already_set` (or any other exception that can occur). Note that 378 pybind11 wrappers around Python exceptions such as 379 :class:`pybind11::value_error` are *not* Python exceptions; they are C++ 380 exceptions that pybind11 catches and converts to Python exceptions. Noexcept 381 functions cannot propagate these exceptions either. A useful approach is to 382 convert them to Python exceptions and then ``discard_as_unraisable`` as shown 383 below. 384 385 .. code-block:: cpp 386 387 void nonthrowing_func() noexcept(true) { 388 try { 389 // ... 390 } catch (py::error_already_set &eas) { 391 // Discard the Python error using Python APIs, using the C++ magic 392 // variable __func__. Python already knows the type and value and of the 393 // exception object. 394 eas.discard_as_unraisable(__func__); 395 } catch (const std::exception &e) { 396 // Log and discard C++ exceptions. 397 third_party::log(e); 398 } 399 } 400 401 .. versionadded:: 2.6