[C++-sig] Inheriting from a python base class/exception translation
Jim Bosch
talljimbo at gmail.com
Tue Nov 8 16:55:00 CET 2011
On 11/07/2011 09:19 PM, Nick Rasmussen wrote:
> I'm cleaning up some of our python bindings for public release as
> part of the openexr distribution, and wanted to update the python
> bindings of our exception library, Iex, to use boost::python.
>
> The first thing I did was the trivial binding of the class hierarchy
> out to python, and performed register_exception_translator<> for each
> type with a translator like:
>
> void
> translateExc(const BaseExc&exc)
> {
> PyErr_SetObject(pytype,boost::python::object(exc).ptr());
> }
>
> where pytype is the pointer to the type object for BaseExc's
> python binding. This allows instances of the exception types
> to be raised in c++, translated into python, and caught.
>
> However, the problem I'm having is this: to allow instances of
> the exception types to be raised in python (or in fact to have
> a try/except/else block finalize properly), the python objects
> need to be derived from the python Exception type or one of
> its subclasses.
>
This is a tough problem, and one I think Boost.Python wasn't designed to
do, since most of it was in place before one could even derive from
Python builtins using the C-API. It's definitely something I'd like to
fix in the future.
In the meantime, I've essentially followed the "parallel pure-Python
exception hierarchy" method, but you can do some metaprogramming tricks
to keep from having to actually build the Python hierarchy yourself. In
other words, write some Python code that inspects your
Boost.Python-wrapped C++ exception hierarchy and calls type(...) to make
corresponding Python types that derive from Exception. The pure-Python
exceptions can then be set as class members of the Boost.Python-wrapped
C++ exceptions, so your translate functions can do something like this:
void translateExc(const BaseExc & exc) {
bp::object wrappedExc(exc);
bp::object pyExcType = wrappedExc.attr("_pyExcType")
// assume the constructor for the Python exception accepts a
// C++ exception; useful if the C++ exception has data
bp::object pyExc = pyExcType(wrappedExc);
PyErr_SetObject(pyExcType.ptr(), pyExc.ptr());
}
To finish it off, you could add a from-Python converter that converts
the pure-Python exception back to the appropriate C++ exception when
it's passed to Boost.Python-wrapped functions, but that isn't always
necessary.
I don't have any code to do the metaprogramming bits on hand, but I'm
happy to help further if you have questions.
By the way, I do hope someone else has an even better idea - my approach
is more complicated than it ought to be, but at least it's all overhead
rather than something that scales with the number of exceptions you have.
Good luck!
Jim
More information about the Cplusplus-sig
mailing list