sending a c++ class to a python function

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

sending a c++ class to a python function

Josh Stratton
I'm getting an error when I try to pass down my object that results in
a seg fault.  I've registered my class I'm sending down, but when I
actually send it, my program exits at this line in the library right
after I call the importFile() function...

        return call<obj>(get_managed_object(self, tag),
BOOST_PP_ENUM_PARAMS_Z(1, N, a));

// here's the class I'm trying to send down
class Scene
{
public:
    MeshP                       mesh(int key);
    void                        clearScene();
    CameraP                     createCamera(QString name);
    MeshP                       createMesh(QString name);
    void                        setMesh(int meshKey, MeshP mesh) {
_meshes[meshKey] = mesh; }
    QHashIterator<int, MeshP>   meshes() { return
QHashIterator<int,MeshP>(_meshes); }
    QHashIterator<int, CameraP> cameras() { return
QHashIterator<int,CameraP>(_cameras); }
    CameraP                     fetchCamera(QString name);
    QList<QString>              importExtensions();
    void                        importFile(QString fileName);
    void                        evalPythonFile(QString fileName);
                                Scene();
protected:
    int                                uniqueCameraKey();
    int                                uniqueMeshKey();
    QString                            uniqueName(QString prefix);

private:
    QHash<int,MeshP>                   _meshes;
    QHash<int,CameraP>                 _cameras;
    //QHash<int,Light*>      _lights;
    QSet<QString>                      _names;
//    PythonQtObjectPtr                  _context;
    object                             _pyMainModule;
    object                             _pyMainNamespace;
public slots:
    void                               pythonStdOut(const QString &s)
{ std::cout << s.toStdString() << std::flush; }
    void                               pythonStdErr(const QString &s)
{ std::cout << s.toStdString() << std::flush; }
};

// first I create the mapping, which I'm not sure is correct, trying
to follow: http://misspent.wordpress.com/2009/09/27/how-to-write-boost-python-converters/
struct SceneToPython
{
    static PyObject* convert(Scene const& scene)
    {
        return boost::python::incref(boost::python::object(scene).ptr());
    }
};

// then I register it
    boost::python::to_python_converter<Scene,SceneToPython>();

// then I send it down from inside my Scene object
    try {
        object processFileFunc =
_pyMainModule.attr("MeshImporter").attr("processFile");
        processFileFunc(this, fileName); // seems to error here
    } catch (boost::python::error_already_set const &) {
        QString perror = parse_python_exception();
        std::cerr << "Error in Python: " << perror.toStdString() << std::endl;
    }

I'm not really sure what actually is wrong besides something being
setup incorrectly.  Do I need to make a python-to-C++ converter as
well even if I'm not sending it back to C++?  Or is my convert()
function just improperly implemented?  I wasn't sure how much I need
to actually get it to map correctly.  Thanks.
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: sending a c++ class to a python function

Jim Bosch-2
Normally a to-python converter is needed when you have a function that
returns a C++ object, and you want to wrap that function so the returned
thing can be used in Python.  I don't see any functions that return a
Scene object.  They will also enable expressions of the form
"object(scene)", but you can't use that sort of expression to define the
converter itself.

When you're writing the conversion function, remember that Boost.Python
really doesn't know anything about your class unless you tell it about
it using a boost::python::class_ definition, and doing that will already
define a to-python converter for it.  The instructions you're following
are for things like strings that already have a Python type they can be
converted to; you probably want to use class_ for something like Scene.
  Now, if you just wanted to convert Scene to a dict instead of having a
Scene type in Python, a custom conversion would indeed be the way to go,
but you'd need to create a dict and fill it in the convert function.

Anyhow, my best guess for the segfault is that you have an infinite
recursion - when you call object(scene), it needs to look for a
to-python converter in the registry.  So it finds yours, which calls
object(scene).  Repeat.

Jim




On 08/28/2011 08:22 PM, Josh Stratton wrote:

> I'm getting an error when I try to pass down my object that results in
> a seg fault.  I've registered my class I'm sending down, but when I
> actually send it, my program exits at this line in the library right
> after I call the importFile() function...
>
>          return call<obj>(get_managed_object(self, tag),
> BOOST_PP_ENUM_PARAMS_Z(1, N, a));
>
> // here's the class I'm trying to send down
> class Scene
> {
> public:
>      MeshP                       mesh(int key);
>      void                        clearScene();
>      CameraP                     createCamera(QString name);
>      MeshP                       createMesh(QString name);
>      void                        setMesh(int meshKey, MeshP mesh) {
> _meshes[meshKey] = mesh; }
>      QHashIterator<int, MeshP>    meshes() { return
> QHashIterator<int,MeshP>(_meshes); }
>      QHashIterator<int, CameraP>  cameras() { return
> QHashIterator<int,CameraP>(_cameras); }
>      CameraP                     fetchCamera(QString name);
>      QList<QString>               importExtensions();
>      void                        importFile(QString fileName);
>      void                        evalPythonFile(QString fileName);
>                                  Scene();
> protected:
>      int                                uniqueCameraKey();
>      int                                uniqueMeshKey();
>      QString                            uniqueName(QString prefix);
>
> private:
>      QHash<int,MeshP>                    _meshes;
>      QHash<int,CameraP>                  _cameras;
>      //QHash<int,Light*>       _lights;
>      QSet<QString>                       _names;
> //    PythonQtObjectPtr                  _context;
>      object                             _pyMainModule;
>      object                             _pyMainNamespace;
> public slots:
>      void                               pythonStdOut(const QString&s)
> { std::cout<<  s.toStdString()<<  std::flush; }
>      void                               pythonStdErr(const QString&s)
> { std::cout<<  s.toStdString()<<  std::flush; }
> };
>
> // first I create the mapping, which I'm not sure is correct, trying
> to follow: http://misspent.wordpress.com/2009/09/27/how-to-write-boost-python-converters/
> struct SceneToPython
> {
>      static PyObject* convert(Scene const&  scene)
>      {
>          return boost::python::incref(boost::python::object(scene).ptr());
>      }
> };
>
> // then I register it
>      boost::python::to_python_converter<Scene,SceneToPython>();
>
> // then I send it down from inside my Scene object
>      try {
>          object processFileFunc =
> _pyMainModule.attr("MeshImporter").attr("processFile");
>          processFileFunc(this, fileName); // seems to error here
>      } catch (boost::python::error_already_set const&) {
>          QString perror = parse_python_exception();
>          std::cerr<<  "Error in Python: "<<  perror.toStdString()<<  std::endl;
>      }
>
> I'm not really sure what actually is wrong besides something being
> setup incorrectly.  Do I need to make a python-to-C++ converter as
> well even if I'm not sending it back to C++?  Or is my convert()
> function just improperly implemented?  I wasn't sure how much I need
> to actually get it to map correctly.  Thanks.
> _______________________________________________
> 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
Reply | Threaded
Open this post in threaded view
|

Re: sending a c++ class to a python function

Josh Stratton
Oh, okay.  So I can create a module...

#include "scene.h"
BOOST_PYTHON_MODULE(scene)
{
    class_<Scene>("Scene");
}

and then import it (even though) in my python I normally don't import
things I'm not creating.  I'm assuming this is a boost-python thing to
get the class into scope, which gets rid of the "converter found for
C++ type: Scene" error.

from scene import Scene # in my python code

In my terminal I get...

Error in Python: <class 'Boost.Python.ArgumentError'>: Python argument types in
    Mesh.buildByIndex(Scene, PrimitiveParts)
did not match C++ signature:
    buildByIndex(QSharedPointer<Scene>, PrimitiveParts):   File
"<string>", line 21, in processFile

for this function:

    static void                  buildByIndex(SceneP scene,
PrimitiveParts parts);

The function I'm calling has SceneP typedeffed as a
QSharedPointer<Scene> and I'm assuming this error is because I haven't
made a Scene to QSharedPointer<Scene> converter, which should just
wrap the Scene object when it comes in requiring a custom conversion
function.

struct QSceneFromPythonScene
{
    static PyObject* convert(Scene const& s)
    {
        return boost::python::incref(boost::python::object(SceneP(&s)));
    }
};

But I'm not converting that properly, I guess.

"invalid conversion of const Scene* to Scene*.

On Mon, Aug 29, 2011 at 11:08 AM, Jim Bosch <[hidden email]> wrote:

> Normally a to-python converter is needed when you have a function that
> returns a C++ object, and you want to wrap that function so the returned
> thing can be used in Python.  I don't see any functions that return a Scene
> object.  They will also enable expressions of the form "object(scene)", but
> you can't use that sort of expression to define the converter itself.
>
> When you're writing the conversion function, remember that Boost.Python
> really doesn't know anything about your class unless you tell it about it
> using a boost::python::class_ definition, and doing that will already define
> a to-python converter for it.  The instructions you're following are for
> things like strings that already have a Python type they can be converted
> to; you probably want to use class_ for something like Scene.  Now, if you
> just wanted to convert Scene to a dict instead of having a Scene type in
> Python, a custom conversion would indeed be the way to go, but you'd need to
> create a dict and fill it in the convert function.
>
> Anyhow, my best guess for the segfault is that you have an infinite
> recursion - when you call object(scene), it needs to look for a to-python
> converter in the registry.  So it finds yours, which calls object(scene).
>  Repeat.
>
> Jim
>
>
>
>
> On 08/28/2011 08:22 PM, Josh Stratton wrote:
>>
>> I'm getting an error when I try to pass down my object that results in
>> a seg fault.  I've registered my class I'm sending down, but when I
>> actually send it, my program exits at this line in the library right
>> after I call the importFile() function...
>>
>>         return call<obj>(get_managed_object(self, tag),
>> BOOST_PP_ENUM_PARAMS_Z(1, N, a));
>>
>> // here's the class I'm trying to send down
>> class Scene
>> {
>> public:
>>     MeshP                       mesh(int key);
>>     void                        clearScene();
>>     CameraP                     createCamera(QString name);
>>     MeshP                       createMesh(QString name);
>>     void                        setMesh(int meshKey, MeshP mesh) {
>> _meshes[meshKey] = mesh; }
>>     QHashIterator<int, MeshP>    meshes() { return
>> QHashIterator<int,MeshP>(_meshes); }
>>     QHashIterator<int, CameraP>  cameras() { return
>> QHashIterator<int,CameraP>(_cameras); }
>>     CameraP                     fetchCamera(QString name);
>>     QList<QString>               importExtensions();
>>     void                        importFile(QString fileName);
>>     void                        evalPythonFile(QString fileName);
>>                                 Scene();
>> protected:
>>     int                                uniqueCameraKey();
>>     int                                uniqueMeshKey();
>>     QString                            uniqueName(QString prefix);
>>
>> private:
>>     QHash<int,MeshP>                    _meshes;
>>     QHash<int,CameraP>                  _cameras;
>>     //QHash<int,Light*>       _lights;
>>     QSet<QString>                       _names;
>> //    PythonQtObjectPtr                  _context;
>>     object                             _pyMainModule;
>>     object                             _pyMainNamespace;
>> public slots:
>>     void                               pythonStdOut(const QString&s)
>> { std::cout<<  s.toStdString()<<  std::flush; }
>>     void                               pythonStdErr(const QString&s)
>> { std::cout<<  s.toStdString()<<  std::flush; }
>> };
>>
>> // first I create the mapping, which I'm not sure is correct, trying
>> to follow:
>> http://misspent.wordpress.com/2009/09/27/how-to-write-boost-python-converters/
>> struct SceneToPython
>> {
>>     static PyObject* convert(Scene const&  scene)
>>     {
>>         return boost::python::incref(boost::python::object(scene).ptr());
>>     }
>> };
>>
>> // then I register it
>>     boost::python::to_python_converter<Scene,SceneToPython>();
>>
>> // then I send it down from inside my Scene object
>>     try {
>>         object processFileFunc =
>> _pyMainModule.attr("MeshImporter").attr("processFile");
>>         processFileFunc(this, fileName); // seems to error here
>>     } catch (boost::python::error_already_set const&) {
>>         QString perror = parse_python_exception();
>>         std::cerr<<  "Error in Python: "<<  perror.toStdString()<<
>>  std::endl;
>>     }
>>
>> I'm not really sure what actually is wrong besides something being
>> setup incorrectly.  Do I need to make a python-to-C++ converter as
>> well even if I'm not sending it back to C++?  Or is my convert()
>> function just improperly implemented?  I wasn't sure how much I need
>> to actually get it to map correctly.  Thanks.
>> _______________________________________________
>> 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
Reply | Threaded
Open this post in threaded view
|

Re: sending a c++ class to a python function

Jim Bosch-2
On 08/30/2011 07:45 AM, Josh Stratton wrote:

> Oh, okay.  So I can create a module...
>
> #include "scene.h"
> BOOST_PYTHON_MODULE(scene)
> {
>      class_<Scene>("Scene");
> }
>
> and then import it (even though) in my python I normally don't import
> things I'm not creating.  I'm assuming this is a boost-python thing to
> get the class into scope, which gets rid of the "converter found for
> C++ type: Scene" error.

I don't really understand what you mean; if you want to use code that
was defined in another Python module, you always have to import it.
It's just that in this case the module happens to be written in C++.

> from scene import Scene # in my python code
>
> In my terminal I get...
>
> Error in Python:<class 'Boost.Python.ArgumentError'>: Python argument types in
>      Mesh.buildByIndex(Scene, PrimitiveParts)
> did not match C++ signature:
>      buildByIndex(QSharedPointer<Scene>, PrimitiveParts):   File
> "<string>", line 21, in processFile
>
> for this function:
>
>      static void                  buildByIndex(SceneP scene,
> PrimitiveParts parts);
>
> The function I'm calling has SceneP typedeffed as a
> QSharedPointer<Scene>  and I'm assuming this error is because I haven't
> made a Scene to QSharedPointer<Scene>  converter, which should just
> wrap the Scene object when it comes in requiring a custom conversion
> function.

This is another case where you probably want to use something other than
a custom converter (and if you did use a custom converter, you'd want a
from-python lvalue converter, not a to-python converter, anyways, and
those are defined differently).

What you probably want to do is tell Boost.Python that QSharedPointer is
a smart pointer, and tell it to wrap your Scene objects inside one (at
least if you're going to have to deal with them a lot).

To do that, you'll want to specialize boost::python::pointee and provide
a get_pointer function:

namespace boost { namespace python {

template <typename T>
struct pointee< QSharedPointer<T> > {
     typedef T type;
};

}}

// in some namespace where ADL will find it...
template <typename T*>
inline Scene * get_pointer(QSharedPointer<T> const & p) {
     return p.get(); // or whatever
}

Then, when you define the class, use:

class_< Scene, QSharedPointer<Scene> >(...)

You can find more information in the reference documentation:

http://www.boost.org/doc/libs/1_47_0/libs/python/doc/v2/class.html#classes

Good Luck!

Jim
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: sending a c++ class to a python function

Josh Stratton
That worked.  Thanks.  I had trouble getting it to work as a template,
so I just removed that portion.

//template <typename T*>
inline Scene* get_pointer(QSharedPointer<Scene> const &p) {
   return p.data(); // or whatever
}


On Tue, Aug 30, 2011 at 10:57 AM, Jim Bosch <[hidden email]> wrote:

> On 08/30/2011 07:45 AM, Josh Stratton wrote:
>>
>> Oh, okay.  So I can create a module...
>>
>> #include "scene.h"
>> BOOST_PYTHON_MODULE(scene)
>> {
>>     class_<Scene>("Scene");
>> }
>>
>> and then import it (even though) in my python I normally don't import
>> things I'm not creating.  I'm assuming this is a boost-python thing to
>> get the class into scope, which gets rid of the "converter found for
>> C++ type: Scene" error.
>
> I don't really understand what you mean; if you want to use code that was
> defined in another Python module, you always have to import it. It's just
> that in this case the module happens to be written in C++.
>
>> from scene import Scene # in my python code
>>
>> In my terminal I get...
>>
>> Error in Python:<class 'Boost.Python.ArgumentError'>: Python argument
>> types in
>>     Mesh.buildByIndex(Scene, PrimitiveParts)
>> did not match C++ signature:
>>     buildByIndex(QSharedPointer<Scene>, PrimitiveParts):   File
>> "<string>", line 21, in processFile
>>
>> for this function:
>>
>>     static void                  buildByIndex(SceneP scene,
>> PrimitiveParts parts);
>>
>> The function I'm calling has SceneP typedeffed as a
>> QSharedPointer<Scene>  and I'm assuming this error is because I haven't
>> made a Scene to QSharedPointer<Scene>  converter, which should just
>> wrap the Scene object when it comes in requiring a custom conversion
>> function.
>
> This is another case where you probably want to use something other than a
> custom converter (and if you did use a custom converter, you'd want a
> from-python lvalue converter, not a to-python converter, anyways, and those
> are defined differently).
>
> What you probably want to do is tell Boost.Python that QSharedPointer is a
> smart pointer, and tell it to wrap your Scene objects inside one (at least
> if you're going to have to deal with them a lot).
>
> To do that, you'll want to specialize boost::python::pointee and provide a
> get_pointer function:
>
> namespace boost { namespace python {
>
> template <typename T>
> struct pointee< QSharedPointer<T> > {
>    typedef T type;
> };
>
> }}
>
> // in some namespace where ADL will find it...
> template <typename T*>
> inline Scene * get_pointer(QSharedPointer<T> const & p) {
>    return p.get(); // or whatever
> }
>
> Then, when you define the class, use:
>
> class_< Scene, QSharedPointer<Scene> >(...)
>
> You can find more information in the reference documentation:
>
> http://www.boost.org/doc/libs/1_47_0/libs/python/doc/v2/class.html#classes
>
> Good Luck!
>
> Jim
>
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig