Skip to content

Commit 5590d93

Browse files
committed
- Replaced with_internals_for_exception_translator by with_exception_translators
- Incremented PYBIND11_INTERNALS_VERSION - Added a test
1 parent 8bcdab6 commit 5590d93

File tree

6 files changed

+86
-23
lines changed

6 files changed

+86
-23
lines changed

include/pybind11/detail/exception_translation.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,17 @@ inline void try_translate_exceptions() {
5050
- delegate translation to the next translator by throwing a new type of exception.
5151
*/
5252

53-
bool handled = with_internals_for_exception_translator([&](internals &internals) {
54-
auto &local_exception_translators = get_local_internals().registered_exception_translators;
55-
if (detail::apply_exception_translators(local_exception_translators)) {
56-
return true;
57-
}
58-
auto &exception_translators = internals.registered_exception_translators;
59-
if (detail::apply_exception_translators(exception_translators)) {
60-
return true;
61-
}
62-
return false;
63-
});
53+
bool handled = with_exception_translators(
54+
[&](std::forward_list<ExceptionTranslator> &exception_translators,
55+
std::forward_list<ExceptionTranslator> &local_exception_translators) {
56+
if (detail::apply_exception_translators(local_exception_translators)) {
57+
return true;
58+
}
59+
if (detail::apply_exception_translators(exception_translators)) {
60+
return true;
61+
}
62+
return false;
63+
});
6464

6565
if (!handled) {
6666
set_error(PyExc_SystemError, "Exception escaped from default exception translator!");

include/pybind11/detail/internals.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@
3939
# if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER)
4040
// Version bump for Python 3.12+, before first 3.12 beta release.
4141
// Version bump for MSVC piggy-backed on PR #4779. See comments there.
42-
# define PYBIND11_INTERNALS_VERSION 5
42+
# ifdef Py_GIL_DISABLED
43+
# define PYBIND11_INTERNALS_VERSION 6
44+
# else
45+
# define PYBIND11_INTERNALS_VERSION 5
46+
# endif
4347
# else
4448
# define PYBIND11_INTERNALS_VERSION 4
4549
# endif
@@ -643,12 +647,16 @@ inline auto with_internals(const F &cb) -> decltype(cb(get_internals())) {
643647
}
644648

645649
template <typename F>
646-
inline auto with_internals_for_exception_translator(const F &cb) -> decltype(cb(get_internals())) {
650+
inline auto with_exception_translators(const F &cb)
651+
-> decltype(cb(get_internals().registered_exception_translators,
652+
get_local_internals().registered_exception_translators)) {
647653
auto &internals = get_internals();
648654
#ifdef Py_GIL_DISABLED
649655
std::unique_lock<pymutex> lock((internals).exception_translator_mutex);
650656
#endif
651-
return cb(internals);
657+
auto &local_internals = get_local_internals();
658+
return cb(internals.registered_exception_translators,
659+
local_internals.registered_exception_translators);
652660
}
653661

654662
inline std::uint64_t mix64(std::uint64_t z) {

include/pybind11/pybind11.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2573,10 +2573,12 @@ void implicitly_convertible() {
25732573
}
25742574

25752575
inline void register_exception_translator(ExceptionTranslator &&translator) {
2576-
detail::with_internals_for_exception_translator([&](detail::internals &internals) {
2577-
internals.registered_exception_translators.push_front(
2578-
std::forward<ExceptionTranslator>(translator));
2579-
});
2576+
detail::with_exception_translators(
2577+
[&](std::forward_list<ExceptionTranslator> &exception_translators,
2578+
std::forward_list<ExceptionTranslator> &local_exception_translators) {
2579+
(void) local_exception_translators;
2580+
exception_translators.push_front(std::forward<ExceptionTranslator>(translator));
2581+
});
25802582
}
25812583

25822584
/**
@@ -2586,11 +2588,12 @@ inline void register_exception_translator(ExceptionTranslator &&translator) {
25862588
* the exception.
25872589
*/
25882590
inline void register_local_exception_translator(ExceptionTranslator &&translator) {
2589-
detail::with_internals_for_exception_translator([&](detail::internals &internals) {
2590-
(void) internals;
2591-
detail::get_local_internals().registered_exception_translators.push_front(
2592-
std::forward<ExceptionTranslator>(translator));
2593-
});
2591+
detail::with_exception_translators(
2592+
[&](std::forward_list<ExceptionTranslator> &exception_translators,
2593+
std::forward_list<ExceptionTranslator> &local_exception_translators) {
2594+
(void) exception_translators;
2595+
local_exception_translators.push_front(std::forward<ExceptionTranslator>(translator));
2596+
});
25942597
}
25952598

25962599
/**

tests/custom_exceptions.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
class PythonMyException7(Exception):
3+
def __init__(self, message):
4+
self.message = message
5+
super().__init__(message)
6+
7+
def __str__(self):
8+
s = "[PythonMyException7]: " + self.message.a
9+
return s

tests/test_exceptions.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ struct PythonAlreadySetInDestructor {
111111
py::str s;
112112
};
113113

114+
struct CustomData {
115+
CustomData(const std::string &a) : a(a) {}
116+
std::string a;
117+
};
118+
119+
struct MyException7 {
120+
MyException7(const CustomData &message) : message(message) {}
121+
CustomData message;
122+
};
123+
114124
TEST_SUBMODULE(exceptions, m) {
115125
m.def("throw_std_exception",
116126
[]() { throw std::runtime_error("This exception was intentionally thrown."); });
@@ -385,4 +395,32 @@ TEST_SUBMODULE(exceptions, m) {
385395

386396
// m.def("pass_exception_void", [](const py::exception<void>&) {}); // Does not compile.
387397
m.def("return_exception_void", []() { return py::exception<void>(); });
398+
399+
m.def("throws7", []() {
400+
auto data = CustomData("abc");
401+
throw MyException7(data);
402+
});
403+
404+
py::class_<CustomData>(m, "CustomData", py::module_local())
405+
.def(py::init<const std::string &>())
406+
.def_readwrite("a", &CustomData::a);
407+
408+
PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object> storage;
409+
storage.call_once_and_store_result([&]() {
410+
auto mod = py::module_::import("custom_exceptions");
411+
py::object obj = mod.attr("PythonMyException7");
412+
return obj;
413+
});
414+
415+
py::register_local_exception_translator([](std::exception_ptr p) {
416+
try {
417+
if (p) {
418+
std::rethrow_exception(p);
419+
}
420+
} catch (const MyException7 &e) {
421+
auto obj = storage.get_stored();
422+
py::object obj2 = obj(e.message);
423+
PyErr_SetObject(PyExc_Exception, obj2.ptr());
424+
}
425+
});
388426
}

tests/test_exceptions.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import sys
44

55
import pytest
6+
from custom_exceptions import PythonMyException7
67

78
import env
89
import pybind11_cross_module_tests as cm
@@ -195,6 +196,10 @@ def test_custom(msg):
195196
raise RuntimeError("Exception error: caught child from parent") from err
196197
assert msg(excinfo.value) == "this is a helper-defined translated exception"
197198

199+
with pytest.raises(PythonMyException7) as excinfo:
200+
m.throws7()
201+
assert msg(excinfo.value) == "[PythonMyException7]: abc"
202+
198203

199204
def test_nested_throws(capture):
200205
"""Tests nested (e.g. C++ -> Python -> C++) exception handling"""

0 commit comments

Comments
 (0)