The source code and dockerfile for the GSW2024 AI Lab.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

142 lines
6.9 KiB

2 months ago
  1. Exceptions
  2. ##########
  3. Built-in exception translation
  4. ==============================
  5. When C++ code invoked from Python throws an ``std::exception``, it is
  6. automatically converted into a Python ``Exception``. pybind11 defines multiple
  7. special exception classes that will map to different types of Python
  8. exceptions:
  9. .. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}|
  10. +--------------------------------------+------------------------------+
  11. | C++ exception type | Python exception type |
  12. +======================================+==============================+
  13. | :class:`std::exception` | ``RuntimeError`` |
  14. +--------------------------------------+------------------------------+
  15. | :class:`std::bad_alloc` | ``MemoryError`` |
  16. +--------------------------------------+------------------------------+
  17. | :class:`std::domain_error` | ``ValueError`` |
  18. +--------------------------------------+------------------------------+
  19. | :class:`std::invalid_argument` | ``ValueError`` |
  20. +--------------------------------------+------------------------------+
  21. | :class:`std::length_error` | ``ValueError`` |
  22. +--------------------------------------+------------------------------+
  23. | :class:`std::out_of_range` | ``ValueError`` |
  24. +--------------------------------------+------------------------------+
  25. | :class:`std::range_error` | ``ValueError`` |
  26. +--------------------------------------+------------------------------+
  27. | :class:`pybind11::stop_iteration` | ``StopIteration`` (used to |
  28. | | implement custom iterators) |
  29. +--------------------------------------+------------------------------+
  30. | :class:`pybind11::index_error` | ``IndexError`` (used to |
  31. | | indicate out of bounds |
  32. | | accesses in ``__getitem__``, |
  33. | | ``__setitem__``, etc.) |
  34. +--------------------------------------+------------------------------+
  35. | :class:`pybind11::value_error` | ``ValueError`` (used to |
  36. | | indicate wrong value passed |
  37. | | in ``container.remove(...)`` |
  38. +--------------------------------------+------------------------------+
  39. | :class:`pybind11::key_error` | ``KeyError`` (used to |
  40. | | indicate out of bounds |
  41. | | accesses in ``__getitem__``, |
  42. | | ``__setitem__`` in dict-like |
  43. | | objects, etc.) |
  44. +--------------------------------------+------------------------------+
  45. | :class:`pybind11::error_already_set` | Indicates that the Python |
  46. | | exception flag has already |
  47. | | been initialized |
  48. +--------------------------------------+------------------------------+
  49. When a Python function invoked from C++ throws an exception, it is converted
  50. into a C++ exception of type :class:`error_already_set` whose string payload
  51. contains a textual summary.
  52. There is also a special exception :class:`cast_error` that is thrown by
  53. :func:`handle::call` when the input arguments cannot be converted to Python
  54. objects.
  55. Registering custom translators
  56. ==============================
  57. If the default exception conversion policy described above is insufficient,
  58. pybind11 also provides support for registering custom exception translators.
  59. To register a simple exception conversion that translates a C++ exception into
  60. a new Python exception using the C++ exception's ``what()`` method, a helper
  61. function is available:
  62. .. code-block:: cpp
  63. py::register_exception<CppExp>(module, "PyExp");
  64. This call creates a Python exception class with the name ``PyExp`` in the given
  65. module and automatically converts any encountered exceptions of type ``CppExp``
  66. into Python exceptions of type ``PyExp``.
  67. When more advanced exception translation is needed, the function
  68. ``py::register_exception_translator(translator)`` can be used to register
  69. functions that can translate arbitrary exception types (and which may include
  70. additional logic to do so). The function takes a stateless callable (e.g. a
  71. function pointer or a lambda function without captured variables) with the call
  72. signature ``void(std::exception_ptr)``.
  73. When a C++ exception is thrown, the registered exception translators are tried
  74. in reverse order of registration (i.e. the last registered translator gets the
  75. first shot at handling the exception).
  76. Inside the translator, ``std::rethrow_exception`` should be used within
  77. a try block to re-throw the exception. One or more catch clauses to catch
  78. the appropriate exceptions should then be used with each clause using
  79. ``PyErr_SetString`` to set a Python exception or ``ex(string)`` to set
  80. the python exception to a custom exception type (see below).
  81. To declare a custom Python exception type, declare a ``py::exception`` variable
  82. and use this in the associated exception translator (note: it is often useful
  83. to make this a static declaration when using it inside a lambda expression
  84. without requiring capturing).
  85. The following example demonstrates this for a hypothetical exception classes
  86. ``MyCustomException`` and ``OtherException``: the first is translated to a
  87. custom python exception ``MyCustomError``, while the second is translated to a
  88. standard python RuntimeError:
  89. .. code-block:: cpp
  90. static py::exception<MyCustomException> exc(m, "MyCustomError");
  91. py::register_exception_translator([](std::exception_ptr p) {
  92. try {
  93. if (p) std::rethrow_exception(p);
  94. } catch (const MyCustomException &e) {
  95. exc(e.what());
  96. } catch (const OtherException &e) {
  97. PyErr_SetString(PyExc_RuntimeError, e.what());
  98. }
  99. });
  100. Multiple exceptions can be handled by a single translator, as shown in the
  101. example above. If the exception is not caught by the current translator, the
  102. previously registered one gets a chance.
  103. If none of the registered exception translators is able to handle the
  104. exception, it is handled by the default converter as described in the previous
  105. section.
  106. .. seealso::
  107. The file :file:`tests/test_exceptions.cpp` contains examples
  108. of various custom exception translators and custom exception types.
  109. .. note::
  110. You must call either ``PyErr_SetString`` or a custom exception's call
  111. operator (``exc(string)``) for every exception caught in a custom exception
  112. translator. Failure to do so will cause Python to crash with ``SystemError:
  113. error return without exception set``.
  114. Exceptions that you do not plan to handle should simply not be caught, or
  115. may be explicity (re-)thrown to delegate it to the other,
  116. previously-declared existing exception translators.