[C++-sig] How to create a custom exception derived from Exception

Glenn Ramsey gr at componic.co.nz
Wed Aug 1 02:07:08 CEST 2012


On 31/07/12 22:58, Jim Bosch wrote:
> On 07/31/2012 06:14 PM, Glenn Ramsey wrote:
>>
>> Using boost::python how can I create an a custom exception that is
>> derived from Python's Exception? The functionality I would like to get
>> by doing this is to provide additional methods for the catching code to
>> retrieve information from the exception.
>>
>
> The approach I've taken in the past (sorry, don't have an example right now) is
> to raise a true Python exception (from PyErr_NewException), and attach your
> Boost.Python-wrapped C++ exception to it as an instance variable.  Then put a
> __getattr__ in the true Python exception that forwards to the Boost.Python
> object it holds.
>
> I can try to reconstruct more details if needed, but hopefully that's enough to
> get you started.

Thanks, based on that I have done this, which seems to work, but I'm not sure if 
it is entirely correct. I didn't need to implement __getattr__ and would be 
interested in seeing some more details of your approach.

PyObject *exceptionType=NULL; // will be initialised inside 
BOOST_PYTHON_MODULE(...) using createExceptionClass(...)

void translator(const MyCPPException &x) {
	
	bp::object exc(x);

	bp::object exc_t(bp::handle<>(bp::borrowed(exceptionType)));
	exc_t.attr("cause") = exc;

	PyErr_SetString(exceptionType, x.what());
}

PyObject* createExceptionClass(const char* name, PyObject* baseTypeObj = 
PyExc_Exception)
{
     std::string scopeName = bp::extract<std::string (bp::scope().attr("__name__"));

     std::string qualifiedName0 = scopeName + "." + name;

     char* qualifiedName1 = const_cast<char*>(qualifiedName0.c_str());

     PyObject* typeObj = PyErr_NewException(qualifiedName1, baseTypeObj, 0);
     if(!typeObj)
     {
        bp::throw_error_already_set();
     }

     bp::scope().attr(name) = bp::handle<>(bp::borrowed(typeObj));
     return typeObj;
}

BOOST_PYTHON_MODULE(MyModule)
{
     bp::register_exception_translator<MyCPPException>(translator);
     ....
     bp::class_<MyCPPException>("MyCPPException")
         .def(...);
     exceptionType = createExceptionClass("MyCPPExceptionType");
     ....
}


In Python:

try:
     ...
except MyModule.MyCPPExceptionType as e:
    cause = e.cause # wrapped exception can be accessed here
     ...


Glenn




More information about the Cplusplus-sig mailing list