[C++-sig] Can't get Boost.Python to use extensions generated and wrapped with Py++

Lawrence Spector Lawrence.Spector at CanfieldSci.com
Tue Jul 17 16:34:36 CEST 2007


Ok, I've been playing with it some more, still not getting everything to work though.  I tried the things you said; it still wasn't working.  I took out the constructors from the python interface and added shared_ptr support.  I then pass the shared_ptr through.  It still doesn't work upon creating the object -- it throws an exception, saying that there's no converter.

TestClass:

#pragma once

#include <iostream>
#include <tchar.h>

class TestClass
{
private:
        std::ostream&   m_outStream;
        int                             m_x;
        float                   m_y;
        char                    m_z;

public:
        TestClass() : m_outStream(std::cout), m_x(0), m_y(0), m_z(0) {}

        TestClass(std::ostream& p_outStream, int p_x, float p_y, char p_z) :
                m_outStream(p_outStream), m_x(p_x), m_y(p_y), m_z(p_z)
        {
                std::cout << __FUNCTION__ << " called.  this = " << this << std::endl;
        } // end TestClass

        ~TestClass()
        {
                std::cout << __FUNCTION__ << " called.  this = " << this << std::endl;
        } // end TestClass

        virtual void output()
        {
                m_outStream << "x = " << m_x << ", y = " << m_y << ", z = " << m_z << "\n";
                std::cout << __FUNCTION__ << " called.  this = " << this << std::endl;
        } // end callMethod
}; // end TestClass

The wrapper:

struct TestClass_wrapper : TestClass, bp::wrapper< TestClass > {

    TestClass_wrapper( )
    : TestClass( )
      , bp::wrapper< TestClass >(){
        // null constructor

    }

    TestClass_wrapper(int p_x, float p_y, char p_z )
        : TestClass( boost::ref(std::cout), p_x, p_y, p_z )
      , bp::wrapper< TestClass >(){
        // constructor

    }

    virtual void output(  ) {
        if( bp::override func_output = this->get_override( "output" ) )
            func_output(  );
        else
            this->TestClass::output(  );
    }


    void default_output(  ) {
        TestClass::output( );
    }

};

The Boost.Build Python extension code:

#include <string>
#include <boost/python.hpp>
#include <iostream>
#include "TestClass.hpp"
#include "TestClassWrap.hpp"

namespace bp = boost::python;

BOOST_PYTHON_MODULE(PythonInterface){
        bp::class_< TestClass_wrapper, boost::shared_ptr<TestClass>, boost::noncopyable >( "TestClass" )
//        .def( bp::init< >() )
//        .def( bp::init< int, float, char >(( bp::arg("p_x"), bp::arg("p_y"), bp::arg("p_z") )) )
        .def(
            "output"
            , &::TestClass::output
            , &TestClass_wrapper::default_output );
}

#include <boost/python.hpp>
#include "TestClass.hpp"
#include "TestClassWrap.hpp"
#include <iostream>

using namespace boost::python;

class Deleter
{
public:
        template <class T>
        void operator()(T&)
        {
        }
};

int main()
{
        try
        {
                Py_Initialize();

                object main_module((
                        handle<>(borrowed(PyImport_AddModule("__main__")))));

                object main_namespace = main_module.attr("__dict__");

                {
                        handle<> ignored((PyRun_String(
                                "import PythonInterface\n"
                                "print dir(PythonInterface)\n"
                                "print 'HELLO'\n"
                          , Py_file_input
                          , main_namespace.ptr()
                          , main_namespace.ptr())
                        ));
                }

                TestClass testClass(std::cout, 3, 9.6f, 'Q');
                boost::shared_ptr<TestClass> pTestClass(&testClass, Deleter());
                boost::python::object pyTestClass(pTestClass);
                main_namespace[L"pyTestClass"] = pyTestClass;

                std::cout << "### Calling pyTestClass.attr(\"output\")()" << std::endl;
                pyTestClass.attr("output")();

                std::cout << "### Calling exec(\"pyTestClass.output()\")" << std::endl;
                {
                        object result = exec(
// Works:                               "pyTestClass = PythonInterface.TestClass(6, 8.3, 'W')\n"
                                "pyTestClass.output()\n",
                                main_namespace, main_namespace);
                }

                std::cout << "### Calling testClassWrapper.output()" << std::endl;
//              testClassWrapper.output();

                std::cout << "### Calling testClass.output()" << std::endl;
                testClass.output();
        }
        catch(boost::python::error_already_set& e)
        {
                std::cerr << "Caught error_already_set" << std::endl;
                if (PyErr_Occurred() != 0)
                {
                        PyErr_Print();
                } // end if
        }
        catch(...)
        {
                std::cerr << "Caught unknown error" << std::endl;
        } // end try-catch

        std::cin.get();

        return 0;
} // end main

Output:

['TestClass', '__doc__', '__file__', '__name__']
HELLO
TestClass::TestClass called.  this = 0012FF1C
TestClass::~TestClass called.  this = 0012FF1C
Caught error_already_set
TypeError: No to_python (by-value) converter found for C++ type: class boost::shared_ptr<class TestClass>


This is very frustrating.  All I want to do is be able to expose classes, create some instances in C++ and use the instances in both C++ and Python.  In addition, I want to create some instances in Python, and use those instances from Python and C++.  It seems like the wrappers pose a huge problem; I just can't seem to get things working reliably when there's a wrapper involved.  I also haven't found enough documentation on the Boost.Python system available in order to get started and be able to actually make use of the system.  Any help you can provide would be greatly appreciated.

Thanks,

Lawrence

-----Original Message-----
From: c++-sig-bounces at python.org [mailto:c++-sig-bounces at python.org] On Behalf Of Roman Yakovenko
Sent: Tuesday, July 17, 2007 1:23 AM
To: Development of Python/C++ integration
Subject: Re: [C++-sig] Can't get Boost.Python to use extensions generated and wrapped with Py++

On 7/17/07, Lawrence Spector <Lawrence.Spector at canfieldsci.com> wrote:

> Any ideas what steps I've missed?  I've successfully built a few python
> extensions without using Boost.Python, but never successfully using a
> wrapper.  Am I missing something?
>

You didn't expose std::ostream class. So, when Boost.Python tries to
create an instance of your class in Python, it sees some argument type
it cannot treat. As a result, you've got an exception.

If you intend to create all your class instance in C++ than you can
exclude constructors.
In this case may be you can pass your object by reference, I am not
sure whether this will work:

TestClass testClass(std::cout, 3, 9.6f, 'Q');
boost::python::object pyTestClass(boost::ref( testClass) );

--
Roman Yakovenko
C++ Python language binding
http://www.language-binding.net/
_______________________________________________
C++-sig mailing list
C++-sig at python.org
http://mail.python.org/mailman/listinfo/c++-sig



More information about the Cplusplus-sig mailing list