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
_______________________________________________
Cplusplus-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to