two pitfals when extending c++ classes from python

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

two pitfals when extending c++ classes from python

Holger Brandsmeier
Dear list,

The boost_python Tutorial describes nicely and very brief how to
subclass a boost::python exported class in python.

I stumbeled over two pitfalls, which I did not expect by reading the tutorial.

1) When you put a wrapper class around a pure virtual class, you have
to remove the "no_init" argument, e.g. for the example in the tutorial
 class_<BaseWrap, boost::noncopyable>("Base", no_init)
is wrong, it should be
 class_<BaseWrap, boost::noncopyable>("Base")
This is also what is shown in the tutorial, but it is not mentioned,
that adding 'no_init' makes your wrapper unusable.

If you don't override __init__ in your python class or if you call the
super constructor in your overriden __init__, then you actually get an
error when "no_init" is present:
 RuntimeError: This class cannot be instantiated from Python
So, yes, you might argue that I should have been warned by this error.
But unfortunately for me that error was misleading. Given this error I
assumed that you didn't want me to call the super constructor in my
__init__ if my super class is pure virtual (why not? pure virtual
classes simply shouldn't have constructors). Then I spend a lot of
time debugging, why I couldn't pass my class back to C++ any more
until I found that the tutorial didn't have a "no_init" argument.

2) The method that I export as overridable in python takes on argument
`node` of type  `const parfem::Node&`. The class Node is a virtual
class. If I simply pass `node` to python then I obtain the misleading
message
 TypeError: No to_python (by-value) converter found for C++ type: parfem::Node
This message actually doesn't mean that there is no such converter,
there is certainly one present. This method probably has to do with
the fact that Node is exported as "noncopyable" and "no_init".
Admittedly the problem here is how to handle the lifetime of the
object and after thinking about it I fully why boost::python has a
problem here.  My solution was then to pass a smart pointer instance.
I just wanted to point out that the error message was very misleading
here for me.

-Holger


--
Holger Brandsmeier, SAM, ETH Zürich
http://www.sam.math.ethz.ch/people/bholger
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: two pitfals when extending c++ classes from python

Ralf Grosse-Kunstleve
Hi Holger,
chances that Dave, Joel, or me get to work on the tutorial are very small. But if you send me updated files I'll check them in. Maybe simpler would be to add to the FAQ.
Ralf

On Tue, Oct 25, 2011 at 3:50 AM, Holger Brandsmeier <[hidden email]> wrote:
Dear list,

The boost_python Tutorial describes nicely and very brief how to
subclass a boost::python exported class in python.

I stumbeled over two pitfalls, which I did not expect by reading the tutorial.

1) When you put a wrapper class around a pure virtual class, you have
to remove the "no_init" argument, e.g. for the example in the tutorial
 class_<BaseWrap, boost::noncopyable>("Base", no_init)
is wrong, it should be
 class_<BaseWrap, boost::noncopyable>("Base")
This is also what is shown in the tutorial, but it is not mentioned,
that adding 'no_init' makes your wrapper unusable.

If you don't override __init__ in your python class or if you call the
super constructor in your overriden __init__, then you actually get an
error when "no_init" is present:
 RuntimeError: This class cannot be instantiated from Python
So, yes, you might argue that I should have been warned by this error.
But unfortunately for me that error was misleading. Given this error I
assumed that you didn't want me to call the super constructor in my
__init__ if my super class is pure virtual (why not? pure virtual
classes simply shouldn't have constructors). Then I spend a lot of
time debugging, why I couldn't pass my class back to C++ any more
until I found that the tutorial didn't have a "no_init" argument.

2) The method that I export as overridable in python takes on argument
`node` of type  `const parfem::Node&`. The class Node is a virtual
class. If I simply pass `node` to python then I obtain the misleading
message
 TypeError: No to_python (by-value) converter found for C++ type: parfem::Node
This message actually doesn't mean that there is no such converter,
there is certainly one present. This method probably has to do with
the fact that Node is exported as "noncopyable" and "no_init".
Admittedly the problem here is how to handle the lifetime of the
object and after thinking about it I fully why boost::python has a
problem here.  My solution was then to pass a smart pointer instance.
I just wanted to point out that the error message was very misleading
here for me.

-Holger


--
Holger Brandsmeier, SAM, ETH Zürich
http://www.sam.math.ethz.ch/people/bholger
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig


_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig