Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- References:
- https://stackoverflow.com/questions/2261858/boostpython-export-custom-exception
- https://stackoverflow.com/questions/9620268/boost-python-custom-exception-class
- https://stackoverflow.com/questions/11448735/boostpython-export-custom-exception-and-inherit-from-pythons-exception
- https://github.com/boostorg/python/blob/develop/src/errors.cpp#L19
- https://docs.python.org/2/c-api/exceptions.html
- and probably some more...
- */
- // ============================================================================
- #include <boost/python.hpp>
- #include <boost/core/typeinfo.hpp>
- #include <boost/stacktrace.hpp>
- #include <boost/exception/all.hpp>
- #include <iostream>
- // ============================================================================
- namespace bp = boost::python;
- // ============================================================================
- typedef boost::error_info<struct tag_stacktrace, boost::stacktrace::stacktrace> traced;
- template <class E>
- void throw_with_trace(const E& e)
- {
- throw boost::enable_error_info(e)
- << traced(boost::stacktrace::stacktrace());
- }
- // ============================================================================
- std::string format_pyerror()
- {
- PyObject *exc, *val, *tb;
- bp::object formatted_list, formatted;
- PyErr_Fetch(&exc, &val, &tb);
- PyErr_NormalizeException(&exc, &val, &tb);
- bp::handle<> hexc(exc), hval(bp::allow_null(val)), htb(bp::allow_null(tb));
- bp::object traceback(bp::import("traceback"));
- if (!tb) {
- bp::object format_exception_only(traceback.attr("format_exception_only"));
- formatted_list = format_exception_only(hexc, hval);
- } else {
- bp::object format_exception(traceback.attr("format_exception"));
- formatted_list = format_exception(hexc, hval, htb);
- }
- formatted = bp::str("").join(formatted_list);
- return bp::extract<std::string>(formatted);
- }
- // ============================================================================
- void raise_cpp_ex(bool with_trace)
- {
- if (with_trace) {
- throw_with_trace(std::runtime_error("Error from C++"));
- } else {
- throw std::runtime_error("Error from C++");
- }
- }
- void raise_cpp_ex2()
- {
- bp::object main = bp::import("__main__");
- bp::object globals = main.attr("__dict__");
- bp::dict locals;
- bp::exec("import foo\nfoo.raise_cpp_ex(True)\n", globals, locals);
- }
- void raise_python_ex()
- {
- bp::object main = bp::import("__main__");
- bp::object globals = main.attr("__dict__");
- bp::dict locals;
- bp::exec("raise RuntimeError('Error from Python')\n", globals, locals);
- }
- // ============================================================================
- template<typename T, PyObject** E>
- void translator(T const& x)
- {
- PyObject *args = PyDict_New();
- PyDict_SetItemString(args, "message", PyString_FromString(x.what()));
- PyDict_SetItemString(args, "origin", PyString_FromString("C++"));
- boost::core::typeinfo const & ti = BOOST_CORE_TYPEID(x);
- PyDict_SetItemString(args, "type", PyString_FromString(boost::core::demangled_name(ti).c_str()));
- const boost::stacktrace::stacktrace* st = boost::get_error_info<traced>(x);
- if (st) {
- std::stringstream ss;
- ss << *st;
- PyDict_SetItemString(args, "trace", PyString_FromString(ss.str().c_str()));
- }
- PyErr_SetObject(*E, args);
- }
- // ============================================================================
- BOOST_PYTHON_MODULE(foo)
- {
- bp::register_exception_translator<boost::bad_numeric_cast>(translator<boost::bad_numeric_cast, &PyExc_OverflowError>);
- bp::register_exception_translator<std::out_of_range>(translator<std::out_of_range, &PyExc_IndexError>);
- bp::register_exception_translator<std::invalid_argument>(translator<std::invalid_argument, &PyExc_ValueError>);
- bp::register_exception_translator<std::exception>(translator<std::exception, &PyExc_RuntimeError>);
- bp::def("raise_cpp_ex", &raise_cpp_ex);
- bp::def("raise_python_ex", &raise_python_ex);
- bp::def("raise_cpp_ex2", &raise_cpp_ex2);
- }
- // ============================================================================
- void test(std::string const& code)
- {
- try {
- bp::object main = bp::import("__main__");
- bp::object globals = main.attr("__dict__");
- bp::dict locals;
- bp::exec(code.c_str(), globals, locals);
- } catch (bp::error_already_set&) {
- if (PyErr_Occurred()) {
- std::cout << "Python error: " << format_pyerror() << std::endl;
- }
- PyErr_Clear();
- }
- }
- // ============================================================================
- int main()
- {
- if (!Py_IsInitialized()) {
- Py_Initialize();
- }
- initfoo();
- std::cout << "Error in Python code: missing function:\n\n";
- test("import foo\n"
- "foo.test()\n");
- std::cout << "Exception raised in Python:\n\n";
- test("import foo\n"
- "raise RuntimeError('Fake')\n");
- std::cout << "C++ exception:\n\n";
- test("import foo\n"
- "foo.raise_cpp_ex(False)\n");
- std::cout << "C++ exception (with backtrace):\n\n";
- test("import foo\n"
- "foo.raise_cpp_ex(True)\n");
- std::cout << "Exception from Python called in C++ code:\n\n";
- test("import foo\n"
- "foo.raise_python_ex()\n");
- std::cout << "C++ exception (nested):\n\n";
- test("import foo\n"
- "foo.raise_cpp_ex2()\n");
- Py_Finalize();
- return 0;
- }
- // ============================================================================
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement