blob: 67133a6370138d58b7ef2a64e4708facc0d31497 [file] [log] [blame]
Pim Schellart5a7d17f2016-06-17 17:35:59 -04001/*
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02002 tests/test_custom-exceptions.cpp -- exception translation
Pim Schellart5a7d17f2016-06-17 17:35:59 -04003
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
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020010#include "pybind11_tests.h"
Pim Schellart5a7d17f2016-06-17 17:35:59 -040011
12// A type that should be raised as an exeption in Python
13class MyException : public std::exception {
14public:
15 explicit MyException(const char * m) : message{m} {}
16 virtual const char * what() const noexcept override {return message.c_str();}
17private:
18 std::string message = "";
19};
20
21// A type that should be translated to a standard Python exception
22class MyException2 : public std::exception {
23public:
24 explicit MyException2(const char * m) : message{m} {}
25 virtual const char * what() const noexcept override {return message.c_str();}
26private:
27 std::string message = "";
28};
29
30// A type that is not derived from std::exception (and is thus unknown)
31class MyException3 {
32public:
33 explicit MyException3(const char * m) : message{m} {}
34 virtual const char * what() const noexcept {return message.c_str();}
35private:
36 std::string message = "";
37};
38
39// A type that should be translated to MyException
40// and delegated to its exception translator
41class MyException4 : public std::exception {
42public:
43 explicit MyException4(const char * m) : message{m} {}
44 virtual const char * what() const noexcept override {return message.c_str();}
45private:
46 std::string message = "";
47};
48
49void throws1() {
50 throw MyException("this error should go to a custom type");
51}
52
53void throws2() {
54 throw MyException2("this error should go to a standard Python exception");
55}
56
57void throws3() {
58 throw MyException3("this error cannot be translated");
59}
60
61void throws4() {
62 throw MyException4("this error is rethrown");
63}
64
65void throws_logic_error() {
66 throw std::logic_error("this error should fall through to the standard handler");
67}
68
Jason Rhinelander52f4be82016-09-03 14:54:22 -040069test_initializer custom_exceptions([](py::module &m) {
Pim Schellart5a7d17f2016-06-17 17:35:59 -040070 // make a new custom exception and use it as a translation target
71 static py::exception<MyException> ex(m, "MyException");
72 py::register_exception_translator([](std::exception_ptr p) {
73 try {
74 if (p) std::rethrow_exception(p);
75 } catch (const MyException &e) {
76 PyErr_SetString(ex.ptr(), e.what());
77 }
78 });
79
80 // register new translator for MyException2
81 // no need to store anything here because this type will
82 // never by visible from Python
83 py::register_exception_translator([](std::exception_ptr p) {
84 try {
85 if (p) std::rethrow_exception(p);
86 } catch (const MyException2 &e) {
87 PyErr_SetString(PyExc_RuntimeError, e.what());
88 }
89 });
90
91 // register new translator for MyException4
92 // which will catch it and delegate to the previously registered
93 // translator for MyException by throwing a new exception
94 py::register_exception_translator([](std::exception_ptr p) {
95 try {
96 if (p) std::rethrow_exception(p);
97 } catch (const MyException4 &e) {
98 throw MyException(e.what());
99 }
100 });
101
102 m.def("throws1", &throws1);
103 m.def("throws2", &throws2);
104 m.def("throws3", &throws3);
105 m.def("throws4", &throws4);
106 m.def("throws_logic_error", &throws_logic_error);
Pim Schellart5a7d17f2016-06-17 17:35:59 -0400107
Ivan Smirnov67b54892016-09-07 21:10:16 +0100108 m.def("throw_already_set", [](bool err) {
109 if (err)
110 PyErr_SetString(PyExc_ValueError, "foo");
111 try {
112 throw py::error_already_set();
113 } catch (const std::runtime_error& e) {
114 if ((err && e.what() != std::string("ValueError: foo")) ||
115 (!err && e.what() != std::string("Unknown internal error occurred")))
116 {
117 PyErr_Clear();
118 throw std::runtime_error("error message mismatch");
119 }
120 }
121 PyErr_Clear();
122 if (err)
123 PyErr_SetString(PyExc_ValueError, "foo");
124 throw py::error_already_set();
125 });
126});