Skip to content

Commit 129fc50

Browse files
committed
Always display python type information in cast errors
1 parent 8ece7d6 commit 129fc50

File tree

5 files changed

+30
-8
lines changed

5 files changed

+30
-8
lines changed

include/pybind11/cast.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,8 @@ make_caster_for_intrinsic<T> &load_type(make_caster_for_intrinsic<T> &conv, cons
10591059
"Internal error: type_caster should only be used for C++ types");
10601060
if (!conv.load(handle, true)) {
10611061
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
1062-
throw cast_error("Unable to cast Python instance to C++ type (#define "
1062+
throw cast_error("Unable to cast Python instance of type "
1063+
+ (std::string) str(type::handle_of(handle)) + " to C++ type '?' (#define "
10631064
"PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
10641065
#else
10651066
throw cast_error("Unable to cast Python instance of type "
@@ -1127,7 +1128,8 @@ detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
11271128
if (obj.ref_count() > 1) {
11281129
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
11291130
throw cast_error(
1130-
"Unable to cast Python instance to C++ rvalue: instance has multiple references"
1131+
"Unable to cast Python " + (std::string) str(type::handle_of(obj))
1132+
+ " instance to C++ rvalue: instance has multiple references"
11311133
" (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
11321134
#else
11331135
throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj))
@@ -1237,8 +1239,8 @@ PYBIND11_NAMESPACE_END(detail)
12371239
// The overloads could coexist, i.e. the #if is not strictly speaking needed,
12381240
// but it is an easy minor optimization.
12391241
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
1240-
inline cast_error cast_error_unable_to_convert_call_arg() {
1241-
return cast_error("Unable to convert call argument to Python object (#define "
1242+
inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name) {
1243+
return cast_error("Unable to convert call argument '" + name + "' to Python object (#define "
12421244
"PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
12431245
}
12441246
#else
@@ -1262,7 +1264,7 @@ tuple make_tuple(Args &&...args_) {
12621264
for (size_t i = 0; i < args.size(); i++) {
12631265
if (!args[i]) {
12641266
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
1265-
throw cast_error_unable_to_convert_call_arg();
1267+
throw cast_error_unable_to_convert_call_arg(std::to_string(i));
12661268
#else
12671269
std::array<std::string, size> argtypes{{type_id<Args>()...}};
12681270
throw cast_error_unable_to_convert_call_arg(std::to_string(i), argtypes[i]);
@@ -1552,7 +1554,7 @@ class unpacking_collector {
15521554
detail::make_caster<T>::cast(std::forward<T>(x), policy, {}));
15531555
if (!o) {
15541556
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
1555-
throw cast_error_unable_to_convert_call_arg();
1557+
throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()));
15561558
#else
15571559
throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()),
15581560
type_id<T>());
@@ -1584,7 +1586,7 @@ class unpacking_collector {
15841586
}
15851587
if (!a.value) {
15861588
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
1587-
throw cast_error_unable_to_convert_call_arg();
1589+
throw cast_error_unable_to_convert_call_arg(a.name);
15881590
#else
15891591
throw cast_error_unable_to_convert_call_arg(a.name, a.type);
15901592
#endif

include/pybind11/detail/common.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,11 @@ constexpr
12511251
// Pybind offers detailed error messages by default for all builts that are debug (through the
12521252
// negation of ndebug). This can also be manually enabled by users, for any builds, through
12531253
// defining PYBIND11_DETAILED_ERROR_MESSAGES.
1254+
//
1255+
// Pybind attempts to provide useful error messages by default. Specifically, this macro will
1256+
// enable two categories of behavior:
1257+
// - Embed C++ type information which isn't going to be available in a release build
1258+
// - Aid those who are writing (as opposed to merely using) libraries that use pybind11
12541259
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) && !defined(NDEBUG)
12551260
# define PYBIND11_DETAILED_ERROR_MESSAGES
12561261
#endif

tests/test_exceptions.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,4 +339,9 @@ TEST_SUBMODULE(exceptions, m) {
339339
}
340340
return py::str("UNEXPECTED");
341341
});
342+
343+
m.def("test_hidden_error", [](py::function fn) {
344+
// function returns none instead of int, should give a useful error message
345+
fn().cast<int>();
346+
});
342347
}

tests/test_exceptions.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,3 +381,13 @@ def test_pypy_oserror_normalization():
381381
# https://github.com/pybind/pybind11/issues/4075
382382
what = m.test_pypy_oserror_normalization()
383383
assert "this_filename_must_not_exist" in what
384+
385+
386+
def test_sane_hidden_exception():
387+
with pytest.raises(RuntimeError) as excinfo:
388+
m.test_hidden_error(lambda: None)
389+
390+
# Always display the python type even if the C++ type isn't available
391+
assert str(excinfo.value).startswith(
392+
"Unable to cast Python instance of type <class 'NoneType'> to C++ type"
393+
)

tests/test_pytypes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ def test_print(capture):
536536
assert str(excinfo.value) == "Unable to convert call argument " + (
537537
"'1' of type 'UnregisteredType' to Python object"
538538
if detailed_error_messages_enabled
539-
else "to Python object (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"
539+
else "'1' to Python object (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"
540540
)
541541

542542

0 commit comments

Comments
 (0)