test_exceptions.cpp
Go to the documentation of this file.
1 /*
2  tests/test_custom-exceptions.cpp -- exception translation
3 
4  Copyright (c) 2016 Pim Schellart <P.Schellart@princeton.edu>
5 
6  All rights reserved. Use of this source code is governed by a
7  BSD-style license that can be found in the LICENSE file.
8 */
10 
11 #include "test_exceptions.h"
12 
13 #include "local_bindings.h"
14 #include "pybind11_tests.h"
15 
16 #include <exception>
17 #include <stdexcept>
18 #include <utility>
19 
20 // A type that should be raised as an exception in Python
21 class MyException : public std::exception {
22 public:
23  explicit MyException(const char *m) : message{m} {}
24  const char *what() const noexcept override { return message.c_str(); }
25 
26 private:
27  std::string message = "";
28 };
29 
32 };
33 
34 // A type that should be translated to a standard Python exception
35 class MyException2 : public std::exception {
36 public:
37  explicit MyException2(const char *m) : message{m} {}
38  const char *what() const noexcept override { return message.c_str(); }
39 
40 private:
41  std::string message = "";
42 };
43 
44 // A type that is not derived from std::exception (and is thus unknown)
45 class MyException3 {
46 public:
47  explicit MyException3(const char *m) : message{m} {}
48  virtual const char *what() const noexcept { return message.c_str(); }
49  // Rule of 5 BEGIN: to preempt compiler warnings.
50  MyException3(const MyException3 &) = default;
51  MyException3(MyException3 &&) = default;
52  MyException3 &operator=(const MyException3 &) = default;
53  MyException3 &operator=(MyException3 &&) = default;
54  virtual ~MyException3() = default;
55  // Rule of 5 END.
56 private:
57  std::string message = "";
58 };
59 
60 // A type that should be translated to MyException
61 // and delegated to its exception translator
62 class MyException4 : public std::exception {
63 public:
64  explicit MyException4(const char *m) : message{m} {}
65  const char *what() const noexcept override { return message.c_str(); }
66 
67 private:
68  std::string message = "";
69 };
70 
71 // Like the above, but declared via the helper function
72 class MyException5 : public std::logic_error {
73 public:
74  explicit MyException5(const std::string &what) : std::logic_error(what) {}
75 };
76 
77 // Inherits from MyException5
78 class MyException5_1 : public MyException5 {
80 };
81 
82 // Exception that will be caught via the module local translator.
83 class MyException6 : public std::exception {
84 public:
85  explicit MyException6(const char *m) : message{m} {}
86  const char *what() const noexcept override { return message.c_str(); }
87 
88 private:
89  std::string message = "";
90 };
91 
93  explicit PythonCallInDestructor(const py::dict &d) : d(d) {}
94  ~PythonCallInDestructor() { d["good"] = true; }
95 
96  py::dict d;
97 };
98 
100  explicit PythonAlreadySetInDestructor(const py::str &s) : s(s) {}
102  py::dict foo;
103  try {
104  // Assign to a py::object to force read access of nonexistent dict entry
105  py::object o = foo["bar"];
106  } catch (py::error_already_set &ex) {
107  ex.discard_as_unraisable(s);
108  }
109  }
110 
112 };
113 
114 TEST_SUBMODULE(exceptions, m) {
115  m.def("throw_std_exception",
116  []() { throw std::runtime_error("This exception was intentionally thrown."); });
117 
118  // PLEASE KEEP IN SYNC with docs/advanced/exceptions.rst
119  PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object> ex_storage;
120  ex_storage.call_once_and_store_result(
121  [&]() { return py::exception<MyException>(m, "MyException"); });
122  py::register_exception_translator([](std::exception_ptr p) {
123  try {
124  if (p) {
125  std::rethrow_exception(p);
126  }
127  } catch (const MyException &e) {
128  // Set MyException as the active python error
129  py::set_error(ex_storage.get_stored(), e.what());
130  }
131  });
132 
133  // Same as above, but using the deprecated `py::exception<>::operator()`
134  // We want to be sure it still works, until it's removed.
135  static const auto *const exd = new py::exception<MyExceptionUseDeprecatedOperatorCall>(
136  m, "MyExceptionUseDeprecatedOperatorCall");
137  py::register_exception_translator([](std::exception_ptr p) {
138  try {
139  if (p) {
140  std::rethrow_exception(p);
141  }
142  } catch (const MyExceptionUseDeprecatedOperatorCall &e) {
143 #if defined(__INTEL_COMPILER) || defined(__NVCOMPILER)
144  // It is not worth the trouble dealing with warning suppressions for these compilers.
145  // Falling back to the recommended approach to keep the test code simple.
146  py::set_error(*exd, e.what());
147 #else
148  PYBIND11_WARNING_PUSH
149  PYBIND11_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
150  PYBIND11_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
152  (*exd)(e.what());
154 #endif
155  }
156  });
157 
158  // register new translator for MyException2
159  // no need to store anything here because this type will
160  // never by visible from Python
161  py::register_exception_translator([](std::exception_ptr p) {
162  try {
163  if (p) {
164  std::rethrow_exception(p);
165  }
166  } catch (const MyException2 &e) {
167  // Translate this exception to a standard RuntimeError
168  py::set_error(PyExc_RuntimeError, e.what());
169  }
170  });
171 
172  // register new translator for MyException4
173  // which will catch it and delegate to the previously registered
174  // translator for MyException by throwing a new exception
175  py::register_exception_translator([](std::exception_ptr p) {
176  try {
177  if (p) {
178  std::rethrow_exception(p);
179  }
180  } catch (const MyException4 &e) {
181  throw MyException(e.what());
182  }
183  });
184 
185  // A simple exception translation:
186  auto ex5 = py::register_exception<MyException5>(m, "MyException5");
187  // A slightly more complicated one that declares MyException5_1 as a subclass of MyException5
188  py::register_exception<MyException5_1>(m, "MyException5_1", ex5.ptr());
189 
190  // py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException")
191 
192  py::register_local_exception_translator([](std::exception_ptr p) {
193  try {
194  if (p) {
195  std::rethrow_exception(p);
196  }
197  } catch (const MyException6 &e) {
198  py::set_error(PyExc_RuntimeError, e.what());
199  }
200  });
201 
202  m.def("throws1",
203  []() { throw MyException("this error should go to py::exception<MyException>"); });
204  m.def("throws1d", []() {
206  "this error should go to py::exception<MyExceptionUseDeprecatedOperatorCall>");
207  });
208  m.def("throws2",
209  []() { throw MyException2("this error should go to a standard Python exception"); });
210  m.def("throws3", []() { throw MyException3("this error cannot be translated"); });
211  m.def("throws4", []() { throw MyException4("this error is rethrown"); });
212  m.def("throws5",
213  []() { throw MyException5("this is a helper-defined translated exception"); });
214  m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); });
215  m.def("throws6", []() { throw MyException6("MyException6 only handled in this module"); });
216  m.def("throws_logic_error", []() {
217  throw std::logic_error("this error should fall through to the standard handler");
218  });
219  m.def("throws_overflow_error", []() { throw std::overflow_error(""); });
220  m.def("throws_local_error", []() { throw LocalException("never caught"); });
221  m.def("throws_local_simple_error", []() { throw LocalSimpleException("this mod"); });
222  m.def("exception_matches", []() {
223  py::dict foo;
224  try {
225  // Assign to a py::object to force read access of nonexistent dict entry
226  py::object o = foo["bar"];
227  } catch (py::error_already_set &ex) {
228  if (!ex.matches(PyExc_KeyError)) {
229  throw;
230  }
231  return true;
232  }
233  return false;
234  });
235  m.def("exception_matches_base", []() {
236  py::dict foo;
237  try {
238  // Assign to a py::object to force read access of nonexistent dict entry
239  py::object o = foo["bar"];
240  } catch (py::error_already_set &ex) {
241  if (!ex.matches(PyExc_Exception)) {
242  throw;
243  }
244  return true;
245  }
246  return false;
247  });
248  m.def("modulenotfound_exception_matches_base", []() {
249  try {
250  // On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError
251  py::module_::import("nonexistent");
252  } catch (py::error_already_set &ex) {
253  if (!ex.matches(PyExc_ImportError)) {
254  throw;
255  }
256  return true;
257  }
258  return false;
259  });
260 
261  m.def("throw_already_set", [](bool err) {
262  if (err) {
263  py::set_error(PyExc_ValueError, "foo");
264  }
265  try {
266  throw py::error_already_set();
267  } catch (const std::runtime_error &e) {
268  if ((err && e.what() != std::string("ValueError: foo"))
269  || (!err
270  && e.what()
271  != std::string("Internal error: pybind11::error_already_set called "
272  "while Python error indicator not set."))) {
273  PyErr_Clear();
274  throw std::runtime_error("error message mismatch");
275  }
276  }
277  PyErr_Clear();
278  if (err) {
279  py::set_error(PyExc_ValueError, "foo");
280  }
281  throw py::error_already_set();
282  });
283 
284  m.def("python_call_in_destructor", [](const py::dict &d) {
285  bool retval = false;
286  try {
287  PythonCallInDestructor set_dict_in_destructor(d);
288  py::set_error(PyExc_ValueError, "foo");
289  throw py::error_already_set();
290  } catch (const py::error_already_set &) {
291  retval = true;
292  }
293  return retval;
294  });
295 
296  m.def("python_alreadyset_in_destructor", [](const py::str &s) {
297  PythonAlreadySetInDestructor alreadyset_in_destructor(s);
298  return true;
299  });
300 
301  // test_nested_throws
302  m.def("try_catch",
303  [m](const py::object &exc_type, const py::function &f, const py::args &args) {
304  try {
305  f(*args);
306  } catch (py::error_already_set &ex) {
307  if (ex.matches(exc_type)) {
308  py::print(ex.what());
309  } else {
310  // Simply `throw;` also works and is better, but using `throw ex;`
311  // here to cover that situation (as observed in the wild).
312  throw ex; // Invokes the copy ctor.
313  }
314  }
315  });
316 
317  // Test repr that cannot be displayed
318  m.def("simple_bool_passthrough", [](bool x) { return x; });
319 
320  m.def("throw_should_be_translated_to_key_error", []() { throw shared_exception(); });
321 
322  m.def("raise_from", []() {
323  py::set_error(PyExc_ValueError, "inner");
324  py::raise_from(PyExc_ValueError, "outer");
325  throw py::error_already_set();
326  });
327 
328  m.def("raise_from_already_set", []() {
329  try {
330  py::set_error(PyExc_ValueError, "inner");
331  throw py::error_already_set();
332  } catch (py::error_already_set &e) {
333  py::raise_from(e, PyExc_ValueError, "outer");
334  throw py::error_already_set();
335  }
336  });
337 
338  m.def("throw_nested_exception", []() {
339  try {
340  throw std::runtime_error("Inner Exception");
341  } catch (const std::runtime_error &) {
342  std::throw_with_nested(std::runtime_error("Outer Exception"));
343  }
344  });
345 
346  m.def("error_already_set_what", [](const py::object &exc_type, const py::object &exc_value) {
347  py::set_error(exc_type, exc_value);
348  std::string what = py::error_already_set().what();
349  bool py_err_set_after_what = (PyErr_Occurred() != nullptr);
350  PyErr_Clear();
351  return py::make_tuple(std::move(what), py_err_set_after_what);
352  });
353 
354  m.def("test_cross_module_interleaved_error_already_set", []() {
355  auto cm = py::module_::import("cross_module_interleaved_error_already_set");
356  auto interleaved_error_already_set
357  = reinterpret_cast<void (*)()>(PyLong_AsVoidPtr(cm.attr("funcaddr").ptr()));
358  interleaved_error_already_set();
359  });
360 
361  m.def("test_error_already_set_double_restore", [](bool dry_run) {
362  py::set_error(PyExc_ValueError, "Random error.");
363  py::error_already_set e;
364  e.restore();
365  PyErr_Clear();
366  if (!dry_run) {
367  e.restore();
368  }
369  });
370 
371  // https://github.com/pybind/pybind11/issues/4075
372  m.def("test_pypy_oserror_normalization", []() {
373  try {
374  py::module_::import("io").attr("open")("this_filename_must_not_exist", "r");
375  } catch (const py::error_already_set &e) {
376  return py::str(e.what()); // str must be built before e goes out of scope.
377  }
378  return py::str("UNEXPECTED");
379  });
380 
381  m.def("test_fn_cast_int", [](const py::function &fn) {
382  // function returns None instead of int, should give a useful error message
383  fn().cast<int>();
384  });
385 
386  // m.def("pass_exception_void", [](const py::exception<void>&) {}); // Does not compile.
387  m.def("return_exception_void", []() { return py::exception<void>(); });
388 }
MyException3::what
virtual const char * what() const noexcept
Definition: test_exceptions.cpp:48
Eigen::internal::print
EIGEN_STRONG_INLINE Packet4f print(const Packet4f &a)
Definition: NEON/PacketMath.h:3115
PYBIND11_CONSTINIT
#define PYBIND11_CONSTINIT
Definition: wrap/pybind11/include/pybind11/detail/common.h:125
MyException4::message
std::string message
Definition: test_exceptions.cpp:68
PYBIND11_WARNING_DISABLE_GCC
#define PYBIND11_WARNING_DISABLE_GCC(name)
Definition: wrap/pybind11/include/pybind11/detail/common.h:67
s
RealScalar s
Definition: level1_cplx_impl.h:126
e
Array< double, 1, 3 > e(1./3., 0.5, 2.)
d
static const double d[K][N]
Definition: igam.h:11
fn
static double fn[10]
Definition: fresnl.c:103
MyExceptionUseDeprecatedOperatorCall
Definition: test_exceptions.cpp:30
MyException::message
std::string message
Definition: test_exceptions.cpp:27
x
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
Definition: gnuplot_common_settings.hh:12
MyException2::message
std::string message
Definition: test_exceptions.cpp:41
test_exceptions.h
MyException3
Definition: test_exceptions.cpp:45
PYBIND11_WARNING_POP
PYBIND11_WARNING_PUSH PYBIND11_WARNING_POP
Definition: tensor.h:30
PythonCallInDestructor
Definition: test_exceptions.cpp:92
PythonAlreadySetInDestructor::s
py::str s
Definition: test_exceptions.cpp:111
PythonAlreadySetInDestructor
Definition: test_exceptions.cpp:99
PythonCallInDestructor::d
py::dict d
Definition: test_exceptions.cpp:96
register_exception_translator
void register_exception_translator(ExceptionTranslator &&translator)
Definition: pybind11.h:2626
MyException::MyException
MyException(const char *m)
Definition: test_exceptions.cpp:23
process_shonan_timing_results.args
args
Definition: process_shonan_timing_results.py:163
MyException3::message
std::string message
Definition: test_exceptions.cpp:57
MyException2::MyException2
MyException2(const char *m)
Definition: test_exceptions.cpp:37
raise_from
void raise_from(PyObject *type, const char *message)
Definition: pytypes.h:797
MyException6
Definition: test_exceptions.cpp:83
MyException5_1
Definition: test_exceptions.cpp:78
MyException6::what
const char * what() const noexcept override
Definition: test_exceptions.cpp:86
make_tuple
tuple make_tuple()
Definition: cast.h:1383
foo
void foo(CV_QUALIFIER Matrix3d &m)
Definition: block_nonconst_ctor_on_const_xpr_0.cpp:11
shared_exception
Definition: test_exceptions.h:8
MyException3::MyException3
MyException3(const char *m)
Definition: test_exceptions.cpp:47
MyException2::what
const char * what() const noexcept override
Definition: test_exceptions.cpp:38
MyException2
Definition: test_exceptions.cpp:35
m
Matrix3f m
Definition: AngleAxis_mimic_euler.cpp:1
MyException6::message
std::string message
Definition: test_exceptions.cpp:89
register_local_exception_translator
void register_local_exception_translator(ExceptionTranslator &&translator)
Definition: pybind11.h:2639
set_error
void set_error(const handle &type, const char *message)
Definition: pytypes.h:346
MyException5
Definition: test_exceptions.cpp:72
MyException3::operator=
MyException3 & operator=(const MyException3 &)=default
tree::f
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
Definition: testExpression.cpp:218
PythonAlreadySetInDestructor::~PythonAlreadySetInDestructor
~PythonAlreadySetInDestructor()
Definition: test_exceptions.cpp:101
MyException3::~MyException3
virtual ~MyException3()=default
LocalException
Definition: local_bindings.h:40
PYBIND11_WARNING_DISABLE_MSVC
PYBIND11_WARNING_PUSH PYBIND11_WARNING_DISABLE_MSVC(5054) PYBIND11_WARNING_POP static_assert(EIGEN_VERSION_AT_LEAST(3
MyException
Definition: test_exceptions.cpp:21
pybind11_tests.h
gil_safe_call_once.h
std
Definition: BFloat16.h:88
args
Definition: pytypes.h:2210
p
float * p
Definition: Tutorial_Map_using.cpp:9
TEST_SUBMODULE
TEST_SUBMODULE(exceptions, m)
Definition: test_exceptions.cpp:114
cm
static const double cm
Definition: TimeOfArrivalExample.cpp:34
PythonCallInDestructor::~PythonCallInDestructor
~PythonCallInDestructor()
Definition: test_exceptions.cpp:94
MyException::what
const char * what() const noexcept override
Definition: test_exceptions.cpp:24
MyException5::MyException5
MyException5(const std::string &what)
Definition: test_exceptions.cpp:74
MyException6::MyException6
MyException6(const char *m)
Definition: test_exceptions.cpp:85
MyException4::MyException4
MyException4(const char *m)
Definition: test_exceptions.cpp:64
PythonAlreadySetInDestructor::PythonAlreadySetInDestructor
PythonAlreadySetInDestructor(const py::str &s)
Definition: test_exceptions.cpp:100
MyException4::what
const char * what() const noexcept override
Definition: test_exceptions.cpp:65
gtsam.examples.ShonanAveragingCLI.str
str
Definition: ShonanAveragingCLI.py:115
LocalSimpleException
Definition: local_bindings.h:50
MyException4
Definition: test_exceptions.cpp:62
PYBIND11_WARNING_DISABLE_CLANG
#define PYBIND11_WARNING_DISABLE_CLANG(name)
Definition: wrap/pybind11/include/pybind11/detail/common.h:61
PythonCallInDestructor::PythonCallInDestructor
PythonCallInDestructor(const py::dict &d)
Definition: test_exceptions.cpp:93
local_bindings.h


gtsam
Author(s):
autogenerated on Sat Nov 16 2024 04:07:05