[C++-sig] bad exception conversion

Jim Bosch talljimbo at gmail.com
Thu Jun 14 01:02:21 CEST 2012


On 06/13/2012 06:31 AM, Wichert Akkerman wrote:
> I have some glue code that calls a C++ function which can raise an
> unsuitable_error exception. I have an exception translator which will
> convert that to a more pythonic version (UnsuitableError), but when I
> use that I get an "SystemError: 'finally' pops bad exception" error on
> the python side. As far as I can see my code looks correct, but I
> suspect I am overlooking something trivial somewhere.
>
>
> using namespace boost::python;
>
> class UnsuitableError : public std::exception {
> public:
>      UnsuitableError() : reasons() { }
>      ~UnsuitableError() throw() {}
>      boost::python::list reasons;
> };
>
> namespace {
>      PyObject *UnsuitableErrorType = NULL;
>
>      void translator(const unsuitable_error &e) {
>          std::list<const char*>::const_iterator i;
>          PyObject* unicode;
>          UnsuitableError error=UnsuitableError();
>          for (i=e.reasons.begin(); i!=e.reasons.end(); i++) {
>              unicode = PyUnicode_FromString(*i);
> error.reasons.append(boost::python::object(boost::python::handle<>(unicode)));
>
>          }
>
>          boost::python::object exc(error);
>          PyErr_SetObject(UnsuitableErrorType, exc.ptr());
>      }
> }
>
>
> void export() {
>      object
> module(handle<>(borrowed(PyImport_AddModule("mypkg.article"))));
>      scope().attr("article")=module;
>      scope module_scope = module;
>
>      class_<UnsuitableError> UnsuitableErrorClass("UnsuitableError");
>      UnsuitableErrorClass.def_readonly("reasons",
> &UnsuitableError::reasons);
>      UnsuitableErrorType=UnsuitableErrorClass.ptr();
>
>      register_exception_translator<unsuitable_error>(&translator);
> }

I suspect the problem is that your custom exception doesn't derived from 
Python's built-in Exception base class.  Unfortunately, it's impossible 
to do that with a Boost.Python wrapped class, but you can get it all 
done with the Python C API:

namespace {
     PyObject *UnsuitableErrorType = NULL;

     void translator(const unsuitable_error &e) {
         std::list<const char*>::const_iterator i;
         PyObject* unicode;
	boost::python::list reasons;
         for (i=e.reasons.begin(); i!=e.reasons.end(); i++) {
             boost::python::handle<> unicode(PyUnicode_FromString(*i));
             reasons.append(boost::python::object(unicode));
         }
         boost::python::handle<> error(
             PyObject_CallFunctionObjArgs(
                 UnsuitableErrorType, NULL
             )
         );
         PyObject_SetAttrString(error.get(), "reasons", reasons.get());
         PyErr_SetObject(UnsuitableErrorType, error.get());
     }
}


void export() {
     object module(handle<>(borrowed(PyImport_AddModule("mypkg.article"))));
     scope().attr("article")=module;
     scope module_scope = module;

     // NOTE: can use something other than RuntimeError for base class
     UnsuitableErrorType = PyErr_NewException(
         "UnsuitableError", PyExc_RuntimeError, NULL
     );
     module_scope.attr("UnsuitableError") =
         object(handle<>(borrowed(UnsuitableErrorType)));

     register_exception_translator<unsuitable_error>(&translator);
}


I haven't tested any of that, but hopefully it's close enough to point 
you in the right direction.


Jim


More information about the Cplusplus-sig mailing list