[C++-sig] Passing a reference to my object to python

Lawrence Spector Lawrence.Spector at CanfieldSci.com
Thu Jul 5 22:03:31 CEST 2007


As a follow up to this, I'm still having no success in my actual program.  I changed it to use the wrapper.  I'm going to post a small portion of the code, in hopes it will clarify the situation.  I cleaned up some confidental portions, but otherwise, the snippet should be enough to illustrate the issue.

The wrapper:

using namespace boost::python;

struct PythonScriptDebuggerWrap : public PythonScriptMgr, public wrapper<PythonScriptMgr>
{
        bool default_CheckBreakpoint(const std::wstring& p_file, boost::uint32_t p_line)
        {
                return this->PythonScriptMgr::checkBreakpoint(p_file, p_line);
        } // end defaultCheckBreakpoint

        virtual bool checkBreakpoint(const std::wstring& p_file, boost::uint32_t p_line)
        {
                if (override f = this->get_override("checkBreakpoint")(p_file, p_line))
                {
                        return f();
                } // end if

                return default_CheckBreakpoint(p_file, p_line);
        }

        virtual void setBreakpoint(const std::wstring& p_file, boost::uint32_t p_line)
        {
                return call<void>(this->get_override("setBreakpoint")(p_file, p_line));
        }
        virtual void clearBreakpoint(const std::wstring& p_file, boost::uint32_t p_line)
        {
                return call<void>(this->get_override("clearBreakpoint")(p_file, p_line));
        }
};

The python interface:

BOOST_PYTHON_MODULE(_PythonInterface)
{
        class_<PythonScriptDebuggerWrap, boost::noncopyable>("PyScriptDebugger", init<>())
                .def("checkBreakpoint", &PythonScriptMgr::checkBreakpoint, &PythonScriptDebuggerWrap::default_CheckBreakpoint)
                ;
} // end module

Usage (where I get an error):

                        // pass a reference to our object over to the current Python script
                        handle<> ignored((PyRun_String(
                                "import PythonInterface"
                                , Py_file_input
                                , m_mainNamespace.ptr()
                                , m_mainNamespace.ptr())
                                ));

                        // Throws the error_already_set exception, with:
                        // TypeError: No to_python (by-value) converter found for C++ type:
                        //     struct PythonScriptDebuggerWrap
                        boost::python::object pyScriptDebugger(static_cast<PythonScriptDebuggerWrap&>(m_scriptMgr));

Any idea where I've gone wrong?  Let me know.

Thanks,

Lawrence

-----Original Message-----
From: c++-sig-bounces at python.org [mailto:c++-sig-bounces at python.org] On Behalf Of Lawrence Spector
Sent: Thursday, July 05, 2007 2:19 PM
To: Development of Python/C++ integration
Subject: Re: [C++-sig] Passing a reference to my object to python

Ok, I went through and created an example.

Here's what the code looks like, as of right now:

PythonPassReference.cpp:

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

using namespace boost::python;

int main()
{
        try
        {
                Py_Initialize();

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

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

                TestClass testClass(std::cout, 3, 9.6f, 'Q');

                {
                        handle<> ignored((PyRun_String(
                                "import PythonInterface"
                          , Py_file_input
                          , main_namespace.ptr()
                          , main_namespace.ptr())
                        ));
                }

                TestClassWrap testClassWrapper(testClass);
                boost::python::object pyTestClass(testClassWrapper);

// Works:               pyTestClass.attr("output")();

                {
                        handle<> ignored((PyRun_String(
// Works:                               "pyTestClass = PythonInterface.TestClass(6, 8.3, 'W')\n"
                                "pyTestClass.output()\n" // Error unless the previous line is uncommented
                          , Py_file_input
                          , main_namespace.ptr()
                          , main_namespace.ptr())
                        ));
                }
        }
        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

TestClass.hpp:

#pragma once

#include <iostream>

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

public:
        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)
        {
        } // end TestClass

        ~TestClass()
        {
        } // end TestClass

        void output()
        {
                m_outStream << "x = " << m_x << ", y = " << m_y << ", z = " << m_z << "\n";
        } // end callMethod
}; // end TestClass

TestClassWrap.hpp:

#pragma once

#include "TestClass.hpp"

class TestClassWrap
{
private:
        TestClass m_testClass;

public:
        TestClassWrap(const TestClass& p_testClass) :
                m_testClass(p_testClass)
        {
        } // end TestClassWrap

        TestClassWrap(int p_x, float p_y, char p_z) :
                m_testClass(std::cout, p_x, p_y, p_z)
        {
        } // end TestClass

        ~TestClassWrap()
        {
        } // end TestClass

        void output()
        {
                m_testClass.output();
        } // end callMethod
}; // end TestClassWrap

PythonInterface.cpp (Built with BJam, makes PythonInterface.pyd, PythonInterface.lib):

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

using namespace boost::python;

BOOST_PYTHON_MODULE(PythonInterface)
{
        class_<TestClassWrap>("TestClass", init<int, float, char>())
                .def("output", &TestClassWrap::output)
                ;
} // end module


In doing so, one issue was illustrated.  I was making a wrapper around the class in my interface code to expose to Python.  However, when I put it into a boost::python::object, I used the unwrapped class, instead of the wrapped one.  Once I started using the wrapped class in my example, the error I was talking about earlier went away, which is good!  So I'm past that point.

I ran into a second error, however.  As you can see in the example above, I have an object which I wrap and then pass to python as follows:

TestClassWrap testClassWrapper(testClass);
boost::python::object pyTestClass(testClassWrapper);

This works just fine, and I can call methods on the object.  However, when I try to run it as a string (as it would be if read from a .py script file), I get an error.  Here's the code for that:

                {
                        handle<> ignored((PyRun_String(
                                "pyTestClass.output()\n" // Error unless the previous line is uncommented
                          , Py_file_input
                          , main_namespace.ptr()
                          , main_namespace.ptr())
                        ));
                }

Which produces the following error:

Caught error_already_set
Traceback (most recent call last):
  File "<string>", line 1, in <module>
NameError: name 'pyTestClass' is not defined

So, I guess the question is, how do I expose an instance called pyTestClass, in such a way, that I can call methods on it from a script?

I'm definitely further along now and I appreciate all the help.  If I can get this piece, I think I'll be in good shape.

Thanks,

Lawrence

-----Original Message-----
From: c++-sig-bounces at python.org [mailto:c++-sig-bounces at python.org] On Behalf Of Roman Yakovenko
Sent: Thursday, July 05, 2007 12:33 PM
To: Development of Python/C++ integration
Subject: Re: [C++-sig] Passing a reference to my object to python

On 7/5/07, Lawrence Spector <Lawrence.Spector at canfieldsci.com> wrote:
>
> Anyway, I guess I'm stuck and I was wondering if someone might be able to supply or direct me to some working sample code.  I'm sure I'm missing an important concept.

Can you create small & complete example which reproduce the error, and
attach the error?

--
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
_______________________________________________
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