I just wanted to thank
http://mail.python.org/pipermail/cplusplus-sig/2007-July/012293.html

I've extended what he wrote..  I needed late binding for c++ to python objects.
Hope this is useful for someone else.  Maybe there was some other way
I was supposed to do this, but I couldn't find it.

Um.. And yes this code was just cobbled together.. BasePtr is a
horrible name I know. :-)

#define BOOST_PYTHON_STATIC_LIB
#include <boost/python.hpp>

#include <boost/detail/lightweight_test.hpp>
#include <boost/python/module.hpp>

#include <iostream>
#include <map>
namespace python = boost::python;

class Base;

//------------------------------------------------------

#define IMPLEMENT_PYTHON_ACCESSOR_H \
public: \
        static void setClass (boost::python::object _clazz) { clazz = _clazz; } 
\
        static boost::python::object getClass() { return clazz; } \
        virtual void reflectBind (boost::python::object object) \
        { \
                ::bind(this, object); \
        } \
private: \
        static boost::python::object clazz; \

#define IMPLEMENT_PYTHON_ACCESSOR_CPP(x) \
        boost::python::object x::clazz;

//------------------------------------------------------

template<typename T>
void bind (T *self, boost::python::object object)
{
        // Insert new S object pointer into python object
        typedef boost::python::objects::pointer_holder<T *, T> holder;
        typedef boost::python::objects::instance<holder> instance_t;

        void* memory =
                holder::allocate(
                        object.ptr(),
                        offsetof(instance_t, storage),
                        sizeof(holder)
                );

        try {
                (new (memory) holder(self))->install(object.ptr());
        }
        catch(...) {
                holder::deallocate(object.ptr(), memory);
                throw;
        }
}

//------------------------------------------------------

class BasePtr
{
public:
        BasePtr() { std::cout << this; };
        virtual ~BasePtr () { };

        virtual void reflectBind (boost::python::object pyobject) { }

        void bind (boost::python::object pyobject)
        {
                reflectBind (pyobject);
                this->object = pyobject;
        }

        python::object object;

        python::object getObject () const
        {
                return object;
        }

        void doBind (python::object o)
        {
                bind( o);
        }

        static python::object nowhere (python::object);
} ;

//----------------------------------------------------

class Base : public BasePtr
{
        IMPLEMENT_PYTHON_ACCESSOR_H

public:

        virtual ~Base() { };

        Base () { }

        virtual std::string hello()
        {
          std::cout << this;
          return "Base says hello";
        }

        virtual Base *myself ()
        {
                return this;
        }
};

IMPLEMENT_PYTHON_ACCESSOR_CPP (Base);

class Inherited : public Base
{
        IMPLEMENT_PYTHON_ACCESSOR_H

public:
        Inherited () { }
        virtual ~Inherited () { }

        std::string hello()
        {
          std::cout << this;
          return "Inherited says hello";
        }
} ;

IMPLEMENT_PYTHON_ACCESSOR_CPP (Inherited);

/*
Not needed after all

template<typename T>
struct BaseToReference
{
    static PyObject* convert(const T &x)
    {
                if (&x == 0)
                        return python::incref(python::object().ptr());

                return python::incref(x.getObject().ptr());
    }
};
*/

python::object BasePtr::nowhere (python::object pyobject)
{
        return python::object();
}

//---------------------------------------------------

BOOST_PYTHON_MODULE(embedded_hello)
{
        Base::setClass(
        python::class_<Base, boost::noncopyable> ("Base", python::no_init)
                .def("__init__", &BasePtr::nowhere)
                .def ("hello", &Base::hello,
python::return_value_policy<python::return_by_value>())
                .def ("myself", &Base::myself,
python::return_value_policy<python::reference_existing_object>())
                );

        Inherited::setClass (
                python::class_<Inherited, python::bases<Base>, 
boost::noncopyable>
("Inherited", python::no_init)
                .def("__init__", &BasePtr::nowhere)
                .def ("hello", &Inherited::hello,
python::return_value_policy<python::return_by_value>())
                );

        // not needed after all
        // python::to_python_converter<Base, BaseToReference<Base> >();
}

//---------------------------------------------------

int main(int argc, char **argv)
{
        // Initialize the interpreter
        Py_Initialize();

        bool error_expected = false;

        if (PyImport_AppendInittab("embedded_hello", initembedded_hello) == -1)
        throw std::runtime_error("Failed to add embedded_hello to the 
interpreter's "
                                 "builtin modules");

        PyObject *z2 = PyImport_ImportModule ("embedded_hello");

        python::object module (python::handle<>(PyImport_ImportModule
("embedded_hello")));

        python::object dict = module.attr("__dict__");

        // Retrieve the main module
        python::object main = python::import("__main__");

        // Retrieve the main module's namespace
        python::object global(main.attr("__dict__"));

        python::object result1 = python::exec(
                "from embedded_hello import *        \n"
                "class PythonDerived(Base):          \n"
                "    def __init__(self):              \n"
                "        Base.__init__(self);         \n"
                "\n"
                "    def hello(self):                \n"
                "        print 'hello from python' \n"
                "        print Base.hello(self) \n"
                "        return 'Hello from Python!' \n"
                "\n"
                "    def test(self):                \n"
                "        print 'test1 says ' \n"
                "        print self.myself().hello()\n"
                ,

                global, global);

        Base b;
        b.doBind(global["PythonDerived"]());

        python::object o(b.object); ;
        python::object r = o.attr("hello")();
        o.attr("test")();

        python::object result2 = python::exec(
                "from embedded_hello import *        \n"
                "class PythonDerived2(Inherited):          \n"
                "    def __init__(self):              \n"
                "        Inherited.__init__(self);         \n"
                "\n"
                "    def hello(self):                \n"
                "        print 'hello from python' \n"
                "        print Inherited.hello(self) \n"
                "        return 'Hello from Python!' \n"
                "\n"
                "    def test(self):                \n"
                "        print 'test2 says ' \n"
                "        print self.myself().hello()\n"
                ,

                global, global);

        Inherited c;
        c.doBind(global["PythonDerived2"]());

        python::object oc(c.object); ;
        python::object rc = oc.attr("hello")();
        oc.attr("test")();

        std::cout << "success!" << std::endl;

}
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to