creating simple Python scripting interfaces via C++

B

Ben Sizer

I have Python embedded in a C++ application (yes, yes, I know, I'd
prefer it the other way around too) and essentially need to expose some
read-only values and functions to Python so it can be used to script
the host application.

When scripting a similar app in TCL, it's possible to associate each
command with some client data, so that the command can be written in
the script as a free function but it actually executes in some sort of
context, accessed via the client data pointer in C++. In Python, there
doesn't appear to be this mechanism, so I think I'd have to inject the
context in another way, either as some sort of module-level global, or
as an object, implementing the previously free functions as methods.

Is this correct? If so, what is the simplest way of implementing the
former method - inserting the pointer to the required context as a long
(via PyDict_SetItemString(globals, "context", PyInt_FromLong(pointer))
or similar) and then converting it back in the bound function? And for
the latter method, is it possible to make an arbitrary object and then
attach methods and the context data? Or will I have to create a whole
Python class for this (as in
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/54352)?

I'm not interested in wrapping whole C++ objects at this stage, and
libraries like Boost::python aren't currently an option. I just need a
few pointers on doing it the low-level way for now.
 
B

Ben Sizer

Ok, my first attempt at this creates proxy objects in Python, and
stores a pointer to the C++ instance in the Python object. I cast that
pointer to an int and pass it as a single parameter to the object's
__init__ function.

static PyObject* Actor_init(PyObject *self, PyObject *args)
{
PyObject* selfParam;
PyObject* ptrValue;
if (!PyArg_ParseTuple(args, "OO", &selfParam, &ptrValue))
return NULL;

PyObject_SetAttrString(selfParam, "_cpp_ptr", ptrValue);

Py_INCREF(Py_None);
return Py_None;
}

I have no idea why self is always NULL, when I'm calling the functions
as methods of an object. Any ideas why this is the case? For what it's
worth I attach each method via the PyMethodDef -> PyCFunction_New ->
PyMethod_New -> PyDict_SetItemString(classDict) route.

To get data back from the C++ object to Python, I extract that value
and cast it back to the appropriate pointer type.

static PyObject* Actor_showName(PyObject *self, PyObject *args)
{
PyObject* selfParam;
if (!PyArg_ParseTuple(args, "O", &selfParam))
return NULL;

PyObject* cppPtr = PyObject_GetAttrString(selfParam, "_cpp_ptr");
long cppPtrVal = PyInt_AsLong(cppPtr);
Actor* pActor = reinterpret_cast<Actor*>(cppPtrVal);

// Delegate to the C++ object
pActor->ShowName();

Py_INCREF(Py_None);
return Py_None;
}

I've omitted some error checking, but this is the way I'm going for
now. Are there any glaring errors I've made (apart from perhaps
assuming sizeof(pointer) <= sizeof(long), that is)? And is there
anywhere else more appropriate that I should be asking this question,
given the lack of responses to this and my other embedding topic so
far?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top