/src/pybind11/include/pybind11/detail/exception_translation.h
Line | Count | Source |
1 | | /* |
2 | | pybind11/detail/exception_translation.h: means to translate C++ exceptions to Python exceptions |
3 | | |
4 | | Copyright (c) 2024 The Pybind Development Team. |
5 | | |
6 | | All rights reserved. Use of this source code is governed by a |
7 | | BSD-style license that can be found in the LICENSE file. |
8 | | */ |
9 | | |
10 | | #pragma once |
11 | | |
12 | | #include "common.h" |
13 | | #include "internals.h" |
14 | | |
15 | | PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) |
16 | | PYBIND11_NAMESPACE_BEGIN(detail) |
17 | | |
18 | | // Apply all the extensions translators from a list |
19 | | // Return true if one of the translators completed without raising an exception |
20 | | // itself. Return of false indicates that if there are other translators |
21 | | // available, they should be tried. |
22 | 0 | inline bool apply_exception_translators(std::forward_list<ExceptionTranslator> &translators) { |
23 | 0 | auto last_exception = std::current_exception(); |
24 | |
|
25 | 0 | for (auto &translator : translators) { |
26 | 0 | try { |
27 | 0 | translator(last_exception); |
28 | 0 | return true; |
29 | 0 | } catch (...) { |
30 | 0 | last_exception = std::current_exception(); |
31 | 0 | } |
32 | 0 | } |
33 | 0 | return false; |
34 | 0 | } |
35 | | |
36 | 0 | inline void try_translate_exceptions() { |
37 | | /* When an exception is caught, give each registered exception |
38 | | translator a chance to translate it to a Python exception. First |
39 | | all module-local translators will be tried in reverse order of |
40 | | registration. If none of the module-locale translators handle |
41 | | the exception (or there are no module-locale translators) then |
42 | | the global translators will be tried, also in reverse order of |
43 | | registration. |
44 | | |
45 | | A translator may choose to do one of the following: |
46 | | |
47 | | - catch the exception and call py::set_error() |
48 | | to set a standard (or custom) Python exception, or |
49 | | - do nothing and let the exception fall through to the next translator, or |
50 | | - delegate translation to the next translator by throwing a new type of exception. |
51 | | */ |
52 | |
|
53 | 0 | bool handled = with_exception_translators( |
54 | 0 | [&](std::forward_list<ExceptionTranslator> &exception_translators, |
55 | 0 | std::forward_list<ExceptionTranslator> &local_exception_translators) { |
56 | 0 | if (detail::apply_exception_translators(local_exception_translators)) { |
57 | 0 | return true; |
58 | 0 | } |
59 | 0 | if (detail::apply_exception_translators(exception_translators)) { |
60 | 0 | return true; |
61 | 0 | } |
62 | 0 | return false; |
63 | 0 | }); |
64 | |
|
65 | 0 | if (!handled) { |
66 | 0 | set_error(PyExc_SystemError, "Exception escaped from default exception translator!"); |
67 | 0 | } |
68 | 0 | } |
69 | | |
70 | | PYBIND11_NAMESPACE_END(detail) |
71 | | PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) |