I have a C++ library with a custom exception that's derived from std::runtime_error. It represents a type of assertion failure, so I would like to map this to AssertionError in python. So far, this is easy:
%exception {
try {
$action
} catch(MyNamespace::Assertion& e) {
PyErr_SetString(PyExc_AssertionError, e.what() );
return nullptr;
} catch(...) {
PyErr_SetString(PyExc_RuntimeError, "Unknown Exception");
return nullptr;
}
}
and this works just fine.
The issue is that I just added a data member to MyNamespace::Assertion in C++, and I would like to propagate this to the python exception. The catch (and what makes this different than the similar questions that have been answered before) is that I would like the exception type in python to be derived from AssertionError. If the client cares about the new data member, they can catch it explicitly, but if the client doesn't care, I want them to be able to catch AssertionError and have it work.
I can add my own exception type derived from AssertionError and map the C++ assertion to it
%{
static PyObject* p_MyAssertionError;
%}
%init %{
p_MyAssertionError = PyErr_NewException("_MyModule.MyAssertionError",PyExc_AssertionError, NULL);
Py_INCREF(p_MyAssertionError);
PyModule_AddObject(m, "MyAssertionError", p_MyAssertionError);
%}
%pythoncode %{
MyAssertionError = _MyModule.MyAssertionError
%}
%exception {
try {
$action
} catch(MyNamespace::Assertion& e) {
PyErr_SetString(p_MyAssertionError, e.what() );
return nullptr;
} catch(...) {
PyErr_SetString(PyExc_RuntimeError, "Unknown Exception");
return nullptr;
}
}
and this works fine as well. The problem is that now I want to add the new data member to the python exception, and I don't know how to do that (I'm not terribly familiar with the python API). From what I see in the documentation for PyErr_NewException, the third argument can be a dictionary of attributes to add, so I would imagine that would be part of the solution, but I don't see any examples of how exactly to do that. The documentation just says that this parameter is usually NULL.
The other issue is that if I create my own derived exception type using PyErr_NewException, how do I construct one on the %exception block? I assume that I need to use PyErr_SetObject() instead of PyErr_SetString(), and although I see examples of how to use PyErr_SetObject() to create an exception of a fully custom type, I don't see any that create one that's derived from a standard exception type but has additional attributes.