Adding "proxy" functions to a type

I

Iker Arizmendi

Hello all.

Is there a convenient scheme within a C extension to add
methods to a type in such a way as to allow me to
transparently add a "proxy" around them? For example:

typedef PyObject* (*PyMethodCall)(PyObject*, PyObject*);

PyObject* middleMan(PyObject* self, PyObject* args) {
printf("Before call to wrapped funct\n");
PyMethodCall actualFunc = getRealFunction(...);
PyObject* retval = actualFunc(self, args);
printf("After call to wrapped func\n");
return retval;
}

void addMethod(PyTypeObject* t, PyMethodCall* m,
char* name, char* doc) {
// code to forward calls to "middleMan" while putting the
// pointer to "m" somewhere convenient
...
}

My current solution is cumbersome and involves adding a
special field to the PyObject associated with my type, a
custom tp_getattro function and the "middleMan" function:

struct MyPyObj {
PyObject_HEAD
PyMethodCall realfunc;
};

// when adding the method def for "m" instead of pointing it to
// the given function, I point it to the middle man and save
// the "m" function somewhere I can find it later.
void addMethod(PyTypeObject* t, PyMethodCall m,
char* name, char* doc) {

PyMethodDef* def = allocPyMethodDef(t, name);
def->ml_name = name;
def->ml_doc = doc;
def->ml_meth = middleMan;
def->ml_flags = METH_VARARGS;

saveTargetFunction(name, m);
// note I add these here so that documentation is
// available within the interpreter
PyObject* methobj = PyDescr_NewMethod(t, def);
PyDict_SetItemString(t->tp_dict, def->ml_name, methobj);
Py_DECREF(methobj);
}

// when the interpreter does a lookup on an instance of my
// type I set the "realfunc" member of my PyObject and return
// a bound method (which will call into middleMan).
PyObject* customGetaAttro(PyObject* self, PyObject* name) {
MyPyObj* rself = (MyPyObj*)self;
rself->realfunc = findSavedTargetFunc(name);
PyMethodDef* mdef = getMethodDef(self->ob_type, name);
return PyCFunction_New(def, self);
}

// finally, when the middle man is called it extracts the "real"
// function from self and calls that.
PyObject* middleMan(PyObject* self, PyObject* args) {
MyPyObj* rself = (MyPyObj*)(self);
printf("pre call\n");
PyObject* rv = rself->realfunc(rself->obj, args);
printf("post call\n");
rself->realfunc = 0;
return rv;
}

The problem here is that this doesn't work for static functions which
lack a self argument, or for module level functions.

Is there a better way?

Thanks,
Iker Arizmendi
 

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

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,278
Latest member
BuzzDefenderpro

Latest Threads

Top