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