diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index d34c92c24a..3a7d7b8849 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -776,7 +776,11 @@ class cpp_function : public function { for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) { if (!some_args) some_args = true; else msg += ", "; - msg += pybind11::repr(args_[ti]); + try { + msg += pybind11::repr(args_[ti]); + } catch (const error_already_set&) { + msg += ""; + } } if (kwargs_in) { auto kwargs = reinterpret_borrow(kwargs_in); @@ -787,7 +791,12 @@ class cpp_function : public function { for (auto kwarg : kwargs) { if (first) first = false; else msg += ", "; - msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second); + msg += pybind11::str("{}=").format(kwarg.first); + try { + msg += pybind11::repr(kwarg.second); + } catch (const error_already_set&) { + msg += ""; + } } } } diff --git a/tests/test_exceptions.cpp b/tests/test_exceptions.cpp index 56cd9bc48f..c99393b03b 100644 --- a/tests/test_exceptions.cpp +++ b/tests/test_exceptions.cpp @@ -194,4 +194,7 @@ TEST_SUBMODULE(exceptions, m) { } }); + // Test repr that cannot be displayed + m.def("simple_bool_passthrough", [](bool x) {return x;}); + } diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 053e7d4a28..64a34b6bb6 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -149,3 +149,14 @@ def pycatch(exctype, f, *args): with pytest.raises(m.MyException5) as excinfo: m.try_catch(m.MyException, pycatch, m.MyException, m.throws5) assert str(excinfo.value) == "this is a helper-defined translated exception" + + +# This can often happen if you wrap a pybind11 class in a Python wrapper +def test_invalid_repr(): + + class MyRepr(object): + def __repr__(self): + raise AttributeError("Example error") + + with pytest.raises(TypeError): + m.simple_bool_passthrough(MyRepr())