2016-06-17 21:35:59 +00:00
|
|
|
/*
|
2016-08-12 11:50:00 +00:00
|
|
|
tests/test_custom-exceptions.cpp -- exception translation
|
2016-06-17 21:35:59 +00:00
|
|
|
|
|
|
|
Copyright (c) 2016 Pim Schellart <P.Schellart@princeton.edu>
|
|
|
|
|
|
|
|
All rights reserved. Use of this source code is governed by a
|
|
|
|
BSD-style license that can be found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2016-08-12 11:50:00 +00:00
|
|
|
#include "pybind11_tests.h"
|
2016-06-17 21:35:59 +00:00
|
|
|
|
|
|
|
// A type that should be raised as an exeption in Python
|
|
|
|
class MyException : public std::exception {
|
|
|
|
public:
|
|
|
|
explicit MyException(const char * m) : message{m} {}
|
|
|
|
virtual const char * what() const noexcept override {return message.c_str();}
|
|
|
|
private:
|
|
|
|
std::string message = "";
|
|
|
|
};
|
|
|
|
|
|
|
|
// A type that should be translated to a standard Python exception
|
|
|
|
class MyException2 : public std::exception {
|
|
|
|
public:
|
|
|
|
explicit MyException2(const char * m) : message{m} {}
|
|
|
|
virtual const char * what() const noexcept override {return message.c_str();}
|
|
|
|
private:
|
|
|
|
std::string message = "";
|
|
|
|
};
|
|
|
|
|
|
|
|
// A type that is not derived from std::exception (and is thus unknown)
|
|
|
|
class MyException3 {
|
|
|
|
public:
|
|
|
|
explicit MyException3(const char * m) : message{m} {}
|
|
|
|
virtual const char * what() const noexcept {return message.c_str();}
|
|
|
|
private:
|
|
|
|
std::string message = "";
|
|
|
|
};
|
|
|
|
|
|
|
|
// A type that should be translated to MyException
|
|
|
|
// and delegated to its exception translator
|
|
|
|
class MyException4 : public std::exception {
|
|
|
|
public:
|
|
|
|
explicit MyException4(const char * m) : message{m} {}
|
|
|
|
virtual const char * what() const noexcept override {return message.c_str();}
|
|
|
|
private:
|
|
|
|
std::string message = "";
|
|
|
|
};
|
|
|
|
|
|
|
|
void throws1() {
|
|
|
|
throw MyException("this error should go to a custom type");
|
|
|
|
}
|
|
|
|
|
|
|
|
void throws2() {
|
|
|
|
throw MyException2("this error should go to a standard Python exception");
|
|
|
|
}
|
|
|
|
|
|
|
|
void throws3() {
|
|
|
|
throw MyException3("this error cannot be translated");
|
|
|
|
}
|
|
|
|
|
|
|
|
void throws4() {
|
|
|
|
throw MyException4("this error is rethrown");
|
|
|
|
}
|
|
|
|
|
|
|
|
void throws_logic_error() {
|
|
|
|
throw std::logic_error("this error should fall through to the standard handler");
|
|
|
|
}
|
|
|
|
|
Rename examples files, as per #288
This renames example files from `exampleN` to `example-description`.
Specifically, the following renaming is applied:
example1 -> example-methods-and-attributes
example2 -> example-python-types
example3 -> example-operator-overloading
example4 -> example-constants-and-functions
example5 -> example-callbacks (*)
example6 -> example-sequence-and-iterators
example7 -> example-buffers
example8 -> example-custom-ref-counting
example9 -> example-modules
example10 -> example-numpy-vectorize
example11 -> example-arg-keywords-and-defaults
example12 -> example-virtual-functions
example13 -> example-keep-alive
example14 -> example-opaque-types
example15 -> example-pickling
example16 -> example-inheritance
example17 -> example-stl-binders
example18 -> example-eval
example19 -> example-custom-exceptions
* the inheritance parts of example5 are moved into example-inheritance
(previously example16), and the remainder is left as example-callbacks.
This commit also renames the internal variables ("Example1",
"Example2", "Example4", etc.) into non-numeric names ("ExampleMandA",
"ExamplePythonTypes", "ExampleWithEnum", etc.) to correspond to the
file renaming.
The order of tests is preserved, but this can easily be changed if
there is some more natural ordering by updating the list in
examples/CMakeLists.txt.
2016-07-18 20:43:18 +00:00
|
|
|
void init_ex_custom_exceptions(py::module &m) {
|
2016-06-17 21:35:59 +00:00
|
|
|
// make a new custom exception and use it as a translation target
|
|
|
|
static py::exception<MyException> ex(m, "MyException");
|
|
|
|
py::register_exception_translator([](std::exception_ptr p) {
|
|
|
|
try {
|
|
|
|
if (p) std::rethrow_exception(p);
|
|
|
|
} catch (const MyException &e) {
|
|
|
|
PyErr_SetString(ex.ptr(), e.what());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// register new translator for MyException2
|
|
|
|
// no need to store anything here because this type will
|
|
|
|
// never by visible from Python
|
|
|
|
py::register_exception_translator([](std::exception_ptr p) {
|
|
|
|
try {
|
|
|
|
if (p) std::rethrow_exception(p);
|
|
|
|
} catch (const MyException2 &e) {
|
|
|
|
PyErr_SetString(PyExc_RuntimeError, e.what());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// register new translator for MyException4
|
|
|
|
// which will catch it and delegate to the previously registered
|
|
|
|
// translator for MyException by throwing a new exception
|
|
|
|
py::register_exception_translator([](std::exception_ptr p) {
|
|
|
|
try {
|
|
|
|
if (p) std::rethrow_exception(p);
|
|
|
|
} catch (const MyException4 &e) {
|
|
|
|
throw MyException(e.what());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
m.def("throws1", &throws1);
|
|
|
|
m.def("throws2", &throws2);
|
|
|
|
m.def("throws3", &throws3);
|
|
|
|
m.def("throws4", &throws4);
|
|
|
|
m.def("throws_logic_error", &throws_logic_error);
|
|
|
|
}
|
|
|
|
|