mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-27 16:14:46 +00:00
Various changes.
This commit is contained in:
parent
acdf332cda
commit
58ad49b05e
@ -473,12 +473,12 @@ PYBIND11_NOINLINE bool isinstance_generic(handle obj, const std::type_info &tp)
|
|||||||
PYBIND11_NOINLINE std::string
|
PYBIND11_NOINLINE std::string
|
||||||
error_string(PyObject *exc_type, PyObject *exc_value, PyObject *exc_trace) {
|
error_string(PyObject *exc_type, PyObject *exc_value, PyObject *exc_trace) {
|
||||||
if (!exc_type) {
|
if (!exc_type) {
|
||||||
static const char *msg
|
pybind11_fail(
|
||||||
= "Internal error: error_string() called without a Python error available.";
|
"Internal error: pybind11::detail::error_string() called with exc_type == nullptr");
|
||||||
PyErr_SetString(PyExc_RuntimeError, msg);
|
|
||||||
return msg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyErr_NormalizeException(&exc_type, &exc_value, &exc_trace);
|
||||||
|
|
||||||
auto result = handle(exc_type).attr("__name__").cast<std::string>();
|
auto result = handle(exc_type).attr("__name__").cast<std::string>();
|
||||||
result += ": ";
|
result += ": ";
|
||||||
|
|
||||||
@ -530,10 +530,7 @@ error_string(PyObject *exc_type, PyObject *exc_value, PyObject *exc_trace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NOINLINE std::string error_string() {
|
PYBIND11_NOINLINE std::string error_string() {
|
||||||
error_scope scope; // Preserve error state.
|
error_scope scope; // Fetch error state.
|
||||||
if (scope.type) {
|
|
||||||
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
|
|
||||||
}
|
|
||||||
return error_string(scope.type, scope.value, scope.trace);
|
return error_string(scope.type, scope.value, scope.trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2611,8 +2611,8 @@ void print(Args &&...args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
error_already_set::~error_already_set() {
|
error_already_set::~error_already_set() {
|
||||||
if (m_type) {
|
gil_scoped_acquire gil;
|
||||||
gil_scoped_acquire gil;
|
{
|
||||||
error_scope scope;
|
error_scope scope;
|
||||||
m_type.release().dec_ref();
|
m_type.release().dec_ref();
|
||||||
m_value.release().dec_ref();
|
m_value.release().dec_ref();
|
||||||
|
@ -387,13 +387,15 @@ PYBIND11_NAMESPACE_END(detail)
|
|||||||
/// python).
|
/// python).
|
||||||
class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::runtime_error {
|
class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::runtime_error {
|
||||||
public:
|
public:
|
||||||
/// Constructs a new exception from the current Python error indicator, if any. The current
|
/// Constructs a new exception from the current Python error indicator, or substitutes a
|
||||||
/// Python error indicator will be cleared.
|
/// RuntimeError("Internal error: ..."). The current Python error indicator will be cleared.
|
||||||
error_already_set() : std::runtime_error("") {
|
error_already_set() : std::runtime_error("") {
|
||||||
PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
|
if (!PyErr_Occurred()) {
|
||||||
if (m_type) {
|
m_lazy_what = "Internal error: pybind11::detail::error_already_set called while "
|
||||||
PyErr_NormalizeException(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
|
"Python error indicator not set.";
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, m_lazy_what.c_str());
|
||||||
}
|
}
|
||||||
|
PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
error_already_set(const error_already_set &) = default;
|
error_already_set(const error_already_set &) = default;
|
||||||
@ -411,22 +413,22 @@ public:
|
|||||||
// Negate the if condition to test the catch(...) block below.
|
// Negate the if condition to test the catch(...) block below.
|
||||||
if (m_lazy_what.empty()) {
|
if (m_lazy_what.empty()) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"FATAL failure building pybind11::error_already_set error_string.");
|
"FATAL failure building pybind11::detail::error_already_set what()");
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// Terminating the process, to not mask the original error by errors in the error
|
// Terminating the process, to not mask the original error by errors in the error
|
||||||
// handling. Reporting the original error on stderr & stdout. Intentionally using
|
// handling. Reporting the original error on stderr & stdout. Intentionally using
|
||||||
// the Python C API directly, to maximize reliability.
|
// the Python C API directly, to maximize reliability.
|
||||||
std::string msg
|
std::string msg
|
||||||
= "FATAL failure building pybind11::error_already_set error_string: ";
|
= "FATAL failure building pybind11::detail::error_already_set what(): ";
|
||||||
if (m_type.ptr() == nullptr) {
|
if (m_type.ptr() == nullptr) {
|
||||||
msg += "PYTHON_EXCEPTION_TYPE_IS_NULLPTR";
|
msg += "PYTHON_EXCEPTION_TYPE_IS_NULLPTR";
|
||||||
} else {
|
} else {
|
||||||
const char *tp_name = detail::obj_class_name(m_type.ptr());
|
const char *class_name = detail::obj_class_name(m_type.ptr());
|
||||||
if (tp_name == nullptr) {
|
if (class_name == nullptr) {
|
||||||
msg += "PYTHON_EXCEPTION_TP_NAME_IS_NULLPTR";
|
msg += "PYTHON_EXCEPTION_CLASS_NAME_IS_NULLPTR";
|
||||||
} else {
|
} else {
|
||||||
msg += tp_name;
|
msg += class_name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg += ": ";
|
msg += ": ";
|
||||||
@ -443,8 +445,8 @@ public:
|
|||||||
+ '"';
|
+ '"';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Intentionally using C calls to maximize reliability (and to avoid #include
|
// Intentionally using C calls to maximize reliability
|
||||||
// <iostream>).
|
// (and to avoid #include <iostream>).
|
||||||
fprintf(stderr, "%s [STDERR]\n", msg.c_str());
|
fprintf(stderr, "%s [STDERR]\n", msg.c_str());
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
fprintf(stdout, "%s [STDOUT]\n", msg.c_str());
|
fprintf(stdout, "%s [STDOUT]\n", msg.c_str());
|
||||||
@ -455,15 +457,12 @@ public:
|
|||||||
return m_lazy_what.c_str();
|
return m_lazy_what.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restores the currently-held Python error, if any (which will clear the Python error
|
/// Restores the currently-held Python error (which will clear the Python error indicator first
|
||||||
/// indicator first if already set).
|
// if already set).
|
||||||
void restore() {
|
void restore() {
|
||||||
if (m_type) {
|
// As long as this type is copyable, there is no point in releasing m_type, m_value,
|
||||||
// As long as this type is copyable, there is no point in releasing m_type, m_value,
|
// m_trace.
|
||||||
// m_trace.
|
PyErr_Restore(m_type.inc_ref().ptr(), m_value.inc_ref().ptr(), m_trace.inc_ref().ptr());
|
||||||
PyErr_Restore(
|
|
||||||
m_type.inc_ref().ptr(), m_value.inc_ref().ptr(), m_trace.inc_ref().ptr());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If it is impossible to raise the currently-held error, such as in a destructor, we can
|
/// If it is impossible to raise the currently-held error, such as in a destructor, we can
|
||||||
|
@ -230,8 +230,8 @@ TEST_SUBMODULE(exceptions, m) {
|
|||||||
if ((err && e.what() != std::string("ValueError: foo"))
|
if ((err && e.what() != std::string("ValueError: foo"))
|
||||||
|| (!err
|
|| (!err
|
||||||
&& e.what()
|
&& e.what()
|
||||||
!= std::string("Internal error: error_string() called without a Python "
|
!= std::string("Internal error: pybind11::detail::error_already_set "
|
||||||
"error available."))) {
|
"called while Python error indicator not set."))) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
throw std::runtime_error("error message mismatch");
|
throw std::runtime_error("error message mismatch");
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,13 @@ def test_std_exception(msg):
|
|||||||
|
|
||||||
|
|
||||||
def test_error_already_set(msg):
|
def test_error_already_set(msg):
|
||||||
with pytest.raises(SystemError) as excinfo:
|
with pytest.raises(RuntimeError) as excinfo:
|
||||||
m.throw_already_set(False)
|
m.throw_already_set(False)
|
||||||
assert "without setting" in str(excinfo.value)
|
assert (
|
||||||
|
msg(excinfo.value)
|
||||||
|
== "Internal error: pybind11::detail::error_already_set called"
|
||||||
|
" while Python error indicator not set."
|
||||||
|
)
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
m.throw_already_set(True)
|
m.throw_already_set(True)
|
||||||
|
Loading…
Reference in New Issue
Block a user