Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pybind11
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
pybind11
Commits
b24c5ed2
Unverified
Commit
b24c5ed2
authored
May 31, 2022
by
Ralf W. Grosse-Kunstleve
Committed by
GitHub
May 31, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Replace "Unknown internal error occurred" with a more helpful message. (#3982)
parent
de4ba92c
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
30 additions
and
14 deletions
+30
-14
include/pybind11/detail/type_caster_base.h
+8
-6
include/pybind11/pytypes.h
+14
-6
tests/test_exceptions.cpp
+4
-1
tests/test_exceptions.py
+4
-1
No files found.
include/pybind11/detail/type_caster_base.h
View file @
b24c5ed2
...
@@ -470,14 +470,16 @@ PYBIND11_NOINLINE bool isinstance_generic(handle obj, const std::type_info &tp)
...
@@ -470,14 +470,16 @@ PYBIND11_NOINLINE bool isinstance_generic(handle obj, const std::type_info &tp)
return
isinstance
(
obj
,
type
);
return
isinstance
(
obj
,
type
);
}
}
PYBIND11_NOINLINE
std
::
string
error_string
()
{
PYBIND11_NOINLINE
std
::
string
error_string
(
const
char
*
called
)
{
if
(
!
PyErr_Occurred
())
{
error_scope
scope
;
// Fetch error state (will be restored when this function returns).
PyErr_SetString
(
PyExc_RuntimeError
,
"Unknown internal error occurred"
);
if
(
scope
.
type
==
nullptr
)
{
return
"Unknown internal error occurred"
;
if
(
called
==
nullptr
)
{
called
=
"pybind11::detail::error_string()"
;
}
pybind11_fail
(
"Internal error: "
+
std
::
string
(
called
)
+
" called while Python error indicator not set."
);
}
}
error_scope
scope
;
// Preserve error state
PyErr_NormalizeException
(
&
scope
.
type
,
&
scope
.
value
,
&
scope
.
trace
);
PyErr_NormalizeException
(
&
scope
.
type
,
&
scope
.
value
,
&
scope
.
trace
);
if
(
scope
.
trace
!=
nullptr
)
{
if
(
scope
.
trace
!=
nullptr
)
{
PyException_SetTraceback
(
scope
.
value
,
scope
.
trace
);
PyException_SetTraceback
(
scope
.
value
,
scope
.
trace
);
...
...
include/pybind11/pytypes.h
View file @
b24c5ed2
...
@@ -360,7 +360,7 @@ T reinterpret_steal(handle h) {
...
@@ -360,7 +360,7 @@ T reinterpret_steal(handle h) {
}
}
PYBIND11_NAMESPACE_BEGIN
(
detail
)
PYBIND11_NAMESPACE_BEGIN
(
detail
)
std
::
string
error_string
();
std
::
string
error_string
(
const
char
*
called
=
nullptr
);
PYBIND11_NAMESPACE_END
(
detail
)
PYBIND11_NAMESPACE_END
(
detail
)
#if defined(_MSC_VER)
#if defined(_MSC_VER)
...
@@ -375,20 +375,27 @@ PYBIND11_NAMESPACE_END(detail)
...
@@ -375,20 +375,27 @@ 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. The current
/// Python error indicator will be cleared.
/// Python error indicator will be cleared.
error_already_set
()
:
std
::
runtime_error
(
detail
::
error_string
())
{
error_already_set
()
:
std
::
runtime_error
(
detail
::
error_string
(
"pybind11::error_already_set"
))
{
PyErr_Fetch
(
&
m_type
.
ptr
(),
&
m_value
.
ptr
(),
&
m_trace
.
ptr
());
PyErr_Fetch
(
&
m_type
.
ptr
(),
&
m_value
.
ptr
(),
&
m_trace
.
ptr
());
}
}
/// WARNING: The GIL must be held when this copy constructor is invoked!
error_already_set
(
const
error_already_set
&
)
=
default
;
error_already_set
(
const
error_already_set
&
)
=
default
;
error_already_set
(
error_already_set
&&
)
=
default
;
error_already_set
(
error_already_set
&&
)
=
default
;
/// WARNING: This destructor needs to acquire the Python GIL. This can lead to
/// crashes (undefined behavior) if the Python interpreter is finalizing.
inline
~
error_already_set
()
override
;
inline
~
error_already_set
()
override
;
/// Give the currently-held error back to Python, if any. If there is currently a Python error
/// Restores the currently-held Python error (which will clear the Python error indicator first
/// already set it is cleared first. After this call, the current object no longer stores the
/// if already set). After this call, the current object no longer stores the error variables.
/// error variables (but the `.what()` string is still available).
/// NOTE: Any copies of this object may still store the error variables. Currently there is no
// protection against calling restore() from multiple copies.
/// NOTE: This member function will always restore the normalized exception, which may or may
/// not be the original Python exception.
/// WARNING: The GIL must be held when this member function is called!
void
restore
()
{
void
restore
()
{
PyErr_Restore
(
m_type
.
release
().
ptr
(),
m_value
.
release
().
ptr
(),
m_trace
.
release
().
ptr
());
PyErr_Restore
(
m_type
.
release
().
ptr
(),
m_value
.
release
().
ptr
(),
m_trace
.
release
().
ptr
());
}
}
...
@@ -405,6 +412,7 @@ public:
...
@@ -405,6 +412,7 @@ public:
}
}
/// An alternate version of `discard_as_unraisable()`, where a string provides information on
/// An alternate version of `discard_as_unraisable()`, where a string provides information on
/// the location of the error. For example, `__func__` could be helpful.
/// the location of the error. For example, `__func__` could be helpful.
/// WARNING: The GIL must be held when this member function is called!
void
discard_as_unraisable
(
const
char
*
err_context
)
{
void
discard_as_unraisable
(
const
char
*
err_context
)
{
discard_as_unraisable
(
reinterpret_steal
<
object
>
(
PYBIND11_FROM_STRING
(
err_context
)));
discard_as_unraisable
(
reinterpret_steal
<
object
>
(
PYBIND11_FROM_STRING
(
err_context
)));
}
}
...
...
tests/test_exceptions.cpp
View file @
b24c5ed2
...
@@ -228,7 +228,10 @@ TEST_SUBMODULE(exceptions, m) {
...
@@ -228,7 +228,10 @@ TEST_SUBMODULE(exceptions, m) {
throw
py
::
error_already_set
();
throw
py
::
error_already_set
();
}
catch
(
const
std
::
runtime_error
&
e
)
{
}
catch
(
const
std
::
runtime_error
&
e
)
{
if
((
err
&&
e
.
what
()
!=
std
::
string
(
"ValueError: foo"
))
if
((
err
&&
e
.
what
()
!=
std
::
string
(
"ValueError: foo"
))
||
(
!
err
&&
e
.
what
()
!=
std
::
string
(
"Unknown internal error occurred"
)))
{
||
(
!
err
&&
e
.
what
()
!=
std
::
string
(
"Internal error: pybind11::error_already_set 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"
);
}
}
...
...
tests/test_exceptions.py
View file @
b24c5ed2
...
@@ -16,7 +16,10 @@ def test_std_exception(msg):
...
@@ -16,7 +16,10 @@ def test_std_exception(msg):
def
test_error_already_set
(
msg
):
def
test_error_already_set
(
msg
):
with
pytest
.
raises
(
RuntimeError
)
as
excinfo
:
with
pytest
.
raises
(
RuntimeError
)
as
excinfo
:
m
.
throw_already_set
(
False
)
m
.
throw_already_set
(
False
)
assert
msg
(
excinfo
.
value
)
==
"Unknown internal error occurred"
assert
(
msg
(
excinfo
.
value
)
==
"Internal error: pybind11::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
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment