Scenario
Say we have written a Python binding with Boost.Python. Something like following code.
// some.cpp
#include <stdexcept>
#include <boost/python.hpp>
struct my_exception : std::exception
{
my_exception(int extra_info): extra_info(extra_info) {}
char const *what() noexcept(true) { return "My exception"; }
int const extra_info;
};
void do_throw()
{
throw my_exception();
}
// Something should be done here ...
BOOST_PYTHON_MODULE(MyLib)
{
using namespace boost::python;
def("do_throw", &do_throw);
}
And we wish to catch a Python exception object in Python code, e.g.
import MyLib
try:
MyLib.do_throw()
except MyLib.MyException as e:
print e, e.extra_info
pass
The situation is, we can’t directly pass the exception object, my_exception, to Python. Now the rescue is:
- Define a Python MyException class
- Create an unique instance of above class in your library
- Translate my_exception to MyException
Define MyException Class
PyObject *createExceptionClass(std::string const &module,
std::string const &exception_name,
PyObject *base)
{
namespace bp = boost::python
std::string fullname = module + "." + exception_name;
PyObject* typeObj = PyErr_NewException((char*)fullname.c_str(),
base, 0);
if (!typeObj) boost::python::throw_error_already_set();
bp::scope().attr(exception_name.c_str()) =
// semantically equal to make_shared(typeObj)
bp::handle<>(bp::borrowed(typeObj));
return typeObj;
}
Create an Exception Instance
// static instance
PyObject *myexception_instanct_ = 0;
BOOST_PYTHON_MODULE(pyvddk)
{
myexcdption_instance_ =
createExceptionClass("pyvddk", "MyException",
PyExc_RuntimeError);
}
Translate Exception
// static instance
PyObject *myexception_instanct_ = 0;
void translate(my_excpetion const &e)
{
namespace bp = boost::python;
bp::object exc(bp::handle<>(bp::borrowed(myexception_instance_)));
// copy data from my_exception to MyException
exc.attr("extra_info") = e.extra_info;
PyErr_SetString(myexception_instance, e.what());
}
BOOST_PYTHON_MODULE(pyvddk)
{
using namespace boost:python;
myexcdption_instance_ =
createExceptionClass("pyvddk", "MyException",
PyExc_RuntimeError);
register_exception_translator<my_exception>(&translate)
}
Full Code Listing
PyObject *createExceptionClass(std::string const &module,
std::string const &exception_name,
PyObject *base)
{
namespace bp = boost::python
std::string fullname = module + "." + exception_name;
PyObject* typeObj = PyErr_NewException((char*)fullname.c_str(),
base, 0);
if (!typeObj) boost::python::throw_error_already_set();
bp::scope().attr(exception_name.c_str()) =
// semantically equal to make_shared(typeObj)
bp::handle<>(bp::borrowed(typeObj));
return typeObj;
}
// static instance
PyObject *myexception_instanct_ = 0;
void translate(my_excpetion const &e)
{
namespace bp = boost::python;
bp::object exc(bp::handle<>(bp::borrowed(myexception_instance_)));
// copy data from my_exception to MyException
exc.attr("extra_info") = e.extra_info;
PyErr_SetString(myexception_instance, e.what());
}
BOOST_PYTHON_MODULE(pyvddk)
{
using namespace boost:python;
myexcdption_instance_ =
createExceptionClass("pyvddk", "MyException",
PyExc_RuntimeError);
register_exception_translator<my_exception>(&translate)
}
Written with StackEdit.
留言
張貼留言