470,591 Members | 1,440 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 470,591 developers. It's quick & easy.

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

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!

--
Hugh Macdonald

Jul 21 '05 #1
3 1673
Hugh Macdonald wrote:
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
Jul 21 '05 #2
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);
}
----------------------------------------------------------------------------------------------------

Jul 21 '05 #3
Hugh Macdonald wrote:
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
Jul 21 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

1 post views Thread by Dixie | last post: by
6 posts views Thread by Davinci_Jeremie | last post: by
15 posts views Thread by Carlos Lozano | last post: by
9 posts views Thread by Brian | last post: by
3 posts views Thread by Bartholomew Simpson | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.