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 */
9 
10 #include "pybind11_tests.h"
11 
12 // A type that should be raised as an exception in Python
13 class MyException : public std::exception {
14 public:
15  explicit MyException(const char * m) : message{m} {}
16  const char * what() const noexcept override {return message.c_str();}
17 private:
18  std::string message = "";
19 };
20 
21 // A type that should be translated to a standard Python exception
22 class MyException2 : public std::exception {
23 public:
24  explicit MyException2(const char * m) : message{m} {}
25  const char * what() const noexcept override {return message.c_str();}
26 private:
27  std::string message = "";
28 };
29 
30 // A type that is not derived from std::exception (and is thus unknown)
31 class MyException3 {
32 public:
33  explicit MyException3(const char * m) : message{m} {}
34  virtual const char * what() const noexcept {return message.c_str();}
35 private:
36  std::string message = "";
37 };
38 
39 // A type that should be translated to MyException
40 // and delegated to its exception translator
41 class MyException4 : public std::exception {
42 public:
43  explicit MyException4(const char * m) : message{m} {}
44  const char * what() const noexcept override {return message.c_str();}
45 private:
46  std::string message = "";
47 };
48 
49 
50 // Like the above, but declared via the helper function
51 class MyException5 : public std::logic_error {
52 public:
53  explicit MyException5(const std::string &what) : std::logic_error(what) {}
54 };
55 
56 // Inherits from MyException5
57 class MyException5_1 : public MyException5 {
59 };
60 
62  PythonCallInDestructor(const py::dict &d) : d(d) {}
63  ~PythonCallInDestructor() { d["good"] = true; }
64 
65  py::dict d;
66 };
67 
68 
69 
73  py::dict foo;
74  try {
75  // Assign to a py::object to force read access of nonexistent dict entry
76  py::object o = foo["bar"];
77  }
78  catch (py::error_already_set& ex) {
79  ex.discard_as_unraisable(s);
80  }
81  }
82 
84 };
85 
86 
87 TEST_SUBMODULE(exceptions, m) {
88  m.def("throw_std_exception", []() {
89  throw std::runtime_error("This exception was intentionally thrown.");
90  });
91 
92  // make a new custom exception and use it as a translation target
93  static py::exception<MyException> ex(m, "MyException");
94  py::register_exception_translator([](std::exception_ptr p) {
95  try {
96  if (p) std::rethrow_exception(p);
97  } catch (const MyException &e) {
98  // Set MyException as the active python error
99  ex(e.what());
100  }
101  });
102 
103  // register new translator for MyException2
104  // no need to store anything here because this type will
105  // never by visible from Python
106  py::register_exception_translator([](std::exception_ptr p) {
107  try {
108  if (p) std::rethrow_exception(p);
109  } catch (const MyException2 &e) {
110  // Translate this exception to a standard RuntimeError
111  PyErr_SetString(PyExc_RuntimeError, e.what());
112  }
113  });
114 
115  // register new translator for MyException4
116  // which will catch it and delegate to the previously registered
117  // translator for MyException by throwing a new exception
118  py::register_exception_translator([](std::exception_ptr p) {
119  try {
120  if (p) std::rethrow_exception(p);
121  } catch (const MyException4 &e) {
122  throw MyException(e.what());
123  }
124  });
125 
126  // A simple exception translation:
127  auto ex5 = py::register_exception<MyException5>(m, "MyException5");
128  // A slightly more complicated one that declares MyException5_1 as a subclass of MyException5
129  py::register_exception<MyException5_1>(m, "MyException5_1", ex5.ptr());
130 
131  m.def("throws1", []() { throw MyException("this error should go to a custom type"); });
132  m.def("throws2", []() { throw MyException2("this error should go to a standard Python exception"); });
133  m.def("throws3", []() { throw MyException3("this error cannot be translated"); });
134  m.def("throws4", []() { throw MyException4("this error is rethrown"); });
135  m.def("throws5", []() { throw MyException5("this is a helper-defined translated exception"); });
136  m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); });
137  m.def("throws_logic_error", []() { throw std::logic_error("this error should fall through to the standard handler"); });
138  m.def("throws_overflow_error", []() {throw std::overflow_error(""); });
139  m.def("exception_matches", []() {
140  py::dict foo;
141  try {
142  // Assign to a py::object to force read access of nonexistent dict entry
143  py::object o = foo["bar"];
144  }
145  catch (py::error_already_set& ex) {
146  if (!ex.matches(PyExc_KeyError)) throw;
147  return true;
148  }
149  return false;
150  });
151  m.def("exception_matches_base", []() {
152  py::dict foo;
153  try {
154  // Assign to a py::object to force read access of nonexistent dict entry
155  py::object o = foo["bar"];
156  }
157  catch (py::error_already_set &ex) {
158  if (!ex.matches(PyExc_Exception)) throw;
159  return true;
160  }
161  return false;
162  });
163  m.def("modulenotfound_exception_matches_base", []() {
164  try {
165  // On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError
166  py::module::import("nonexistent");
167  }
168  catch (py::error_already_set &ex) {
169  if (!ex.matches(PyExc_ImportError)) throw;
170  return true;
171  }
172  return false;
173  });
174 
175  m.def("throw_already_set", [](bool err) {
176  if (err)
177  PyErr_SetString(PyExc_ValueError, "foo");
178  try {
179  throw py::error_already_set();
180  } catch (const std::runtime_error& e) {
181  if ((err && e.what() != std::string("ValueError: foo")) ||
182  (!err && e.what() != std::string("Unknown internal error occurred")))
183  {
184  PyErr_Clear();
185  throw std::runtime_error("error message mismatch");
186  }
187  }
188  PyErr_Clear();
189  if (err)
190  PyErr_SetString(PyExc_ValueError, "foo");
191  throw py::error_already_set();
192  });
193 
194  m.def("python_call_in_destructor", [](py::dict d) {
195  try {
196  PythonCallInDestructor set_dict_in_destructor(d);
197  PyErr_SetString(PyExc_ValueError, "foo");
198  throw py::error_already_set();
199  } catch (const py::error_already_set&) {
200  return true;
201  }
202  return false;
203  });
204 
205  m.def("python_alreadyset_in_destructor", [](py::str s) {
206  PythonAlreadySetInDestructor alreadyset_in_destructor(s);
207  return true;
208  });
209 
210  // test_nested_throws
211  m.def("try_catch", [m](py::object exc_type, py::function f, py::args args) {
212  try { f(*args); }
213  catch (py::error_already_set &ex) {
214  if (ex.matches(exc_type))
215  py::print(ex.what());
216  else
217  throw;
218  }
219  });
220 
221  // Test repr that cannot be displayed
222  m.def("simple_bool_passthrough", [](bool x) {return x;});
223 
224 }
void print(const Matrix &A, const string &s, ostream &stream)
Definition: Matrix.cpp:155
Matrix3f m
MyException4(const char *m)
PythonCallInDestructor(const py::dict &d)
Definition: pytypes.h:1322
Definition: Half.h:150
MyException2(const char *m)
void foo(CV_QUALIFIER Matrix3d &m)
const char * what() const noexceptoverride
const char * what() const noexceptoverride
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
MyException(const char *m)
Array< double, 1, 3 > e(1./3., 0.5, 2.)
RealScalar s
MyException3(const char *m)
TEST_SUBMODULE(exceptions, m)
const char * what() const noexceptoverride
void register_exception_translator(ExceptionTranslator &&translator)
Definition: pybind11.h:1857
float * p
PythonAlreadySetInDestructor(const py::str &s)
MyException5(const std::string &what)
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
virtual const char * what() const noexcept
std::string message


gtsam
Author(s):
autogenerated on Sat May 8 2021 02:46:03