C API : Creating a Py_Method object from a C function.

H

Hugh Macdonald

I've got a pure python module that parses a certain type of file. It
has a load() function that allows a callback function to be passed for
getting progress information.

In straight python, this works fine.

However, I'm now trying to use this from a C++ program. The current
flow that I'm trying to get is as follows:

C++ calls python interface function, passing a C++ function pointer
Python interface function stores C++ function pointer
Python interface function generates new Py_Object method pointer
pointing to a different C python function. (This different function
calls the stored C++ function pointer)
Python interface function calls python function
Python function calls the python method pointer it was passed
C python function then calls the stored C++ function pointer.


The problem in this workflow is taking the C python function that I've
defined (using the standard "static PyObject *someFunction(PyObject
*self, PyObject *args)" method) and converting this into a Py_Object.
Any ideas?

Py_Method doesn't seem to allow you to generate a new one with your own
pointers inside... and I can't see anything else in the docs that might
allow me to do this...


Thanks for any advice!
 
?

=?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=

Hugh said:
The problem in this workflow is taking the C python function that I've
defined (using the standard "static PyObject *someFunction(PyObject
*self, PyObject *args)" method) and converting this into a Py_Object.
Any ideas?

You should use PyCFunction_New(Ex), passing a static PyMethodDef
variable that you define along with your function definition.

Regards,
Martin
 
H

Hugh Macdonald

Thanks Martin - that worked wonderfully....


For the record (and for anyone searching for this in future), here's
the code that worked (with names changed to protect my job...)


myPython is the C++/Python interface class containing static methods
which pass on calls to the underlying python module. It's not really
commented, but if you're trying to do this kind of thing, it should
give you what you need.

----------------------------------------------------------------------------------------------------
// myPython.h

#ifndef ___MYPYTHON_H___
#define ___MYPYTHON_H___

#include <list>

using namespace std;

typedef struct _object PyObject;
typedef void (*loadCallback)(string message, int progress, void
*callbackData);

static PyObject *myPython_doLoadCallback(PyObject *self,
PyObject *args);

class myPython {
public:
static list<string> *loadDetails(string file, loadCallback
callbackFunc = NULL, void *callbackData = NULL);
static void doLoadCallback(string message, int
progress);
private:
static PyObject *getResults(char *moduleName, char
*functionName, PyObject *args);

static loadCallback callbackFunc;
static void *callbackData;
};

#endif // ___MYPYTHON_H___
----------------------------------------------------------------------------------------------------


----------------------------------------------------------------------------------------------------
// myPython.cpp

#include <myPython.h>
#include <Python.h>

loadCallback myPython::callbackFunc = NULL;
void *myPython::callbackData = NULL;

list<string> *myPython::loadDetails(string file, loadCallback
newCallbackFunc, void *newCallbackData)
{
PyObject *pArgs, *pResult;

callbackFunc = newCallbackFunc;
callbackData = newCallbackData;

PyMethodDef *callbackFunctionDef = new PyMethodDef;
callbackFunctionDef->ml_name = "doLoadCallback";
callbackFunctionDef->ml_meth = &myPython_doLoadCallback;
callbackFunctionDef->ml_flags = 1;

PyObject *pyCallbackFunc = PyCFunction_New(callbackFunctionDef,
NULL);

pArgs = Py_BuildValue("(sO)", file.c_str(), pyCallbackFunc);

pResult = getResults("myPythonModule", "loadDetails", pArgs);

if(!pResult)
{
Py_DECREF(pArgs);
return NULL;
}

if(PyList_Check(pResult))
{
// Convert pResult into a list<string> and return that.
}

return NULL;
}

PyObject *myPython_doLoadCallback(PyObject *self, PyObject *args)
{
char *message;
int progress;

if(!PyArg_ParseTuple(args, "si", &message, &progress))
return NULL;

myPython::doLoadCallback(message, progress);

return Py_None;
}

void myPython::doLoadCallback(string message, int progress)
{
if(callbackFunc)
callbackFunc(message, progress, callbackData);
}
----------------------------------------------------------------------------------------------------
 
?

=?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=

Hugh said:
PyMethodDef *callbackFunctionDef = new PyMethodDef;
callbackFunctionDef->ml_name = "doLoadCallback";
callbackFunctionDef->ml_meth = &myPython_doLoadCallback;
callbackFunctionDef->ml_flags = 1;

I think this gives a memory leak. I was rather thinking of

static PyMethodDef doLoadCallback = {
"doLoadCallback", &myPython_doLoadCallback, 1
};

PyObject *pyCallbackFunc = PyCFunction_New(&doLoadCallback,
NULL);

Since you have to write the C(++) functions statically, you can also
provide the PyMethodDef objects statically.

Regards,
Martin
 

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
474,261
Messages
2,571,308
Members
47,968
Latest member
SerenaRusc

Latest Threads

Top