[Python-Dev] Extending types in C - help needed
Martin v. Loewis
martin@v.loewis.de
Fri, 18 Jan 2002 20:36:20 +0100
> Also, the method seems rather complicated for doing a simple thing. The
> only thing I really want is a way to refer to an _New or _Convert method
> from Python code.
I believe the attached code implements your requirements. In
particular, see PyArg_GenericCopy for an application that extracts a
void* from an object through a type-safe protocol, then creates a
clone of the original object through the same protocol. Both extractor
and creator function are associated with the type object.
To see this work in Python, run
>>> import handle
>>> x=handle.new(10)
>>> x
<handle.Handle object at 0x81683a0>
>>> y=handle.copy(x)
>>> y
<handle.Handle object at 0x819f270>
Regards,
Martin
#include "Python.h"
/************* Generic Converters ***************/
struct converters{
PyObject* (*create)(void*);
int (*extract)(PyObject*, void**);
};
char descr_string[] = "calldll converter structure";
void PyArg_AddConverters(PyTypeObject *type, struct converters* convs)
{
PyObject *cobj = PyCObject_FromVoidPtrAndDesc(convs,
descr_string,
NULL);
PyDict_SetItemString(type->tp_dict,
"__calldll__",
cobj);
Py_DECREF(cobj);
}
struct converters* PyArg_GetConverters(PyTypeObject *type)
{
PyObject *cobj;
void *descr;
cobj = PyObject_GetAttrString((PyObject*)type, "__calldll__");
if (!cobj)
return NULL;
descr = PyCObject_GetDesc(cobj);
if (!descr)
return NULL;
if (descr != descr_string){
PyErr_SetString(PyExc_TypeError, "invalid cobj");
return NULL;
}
return (struct converters*)PyCObject_AsVoidPtr(cobj);
}
PyObject *PyArg_Create(PyTypeObject* type, void * value)
{
struct converters *convs = PyArg_GetConverters(type);
if (!convs)
return NULL;
return convs->create(value);
}
int PyArg_Extract(PyObject* obj, void** value)
{
struct converters *convs = PyArg_GetConverters(obj->ob_type);
if (!convs)
return -1;
convs->extract(obj, value);
return 0;
}
PyObject* PyArg_GenericCopy(PyObject* obj)
{
void *tmp;
if (PyArg_Extract(obj, &tmp))
return NULL;
return PyArg_Create(obj->ob_type, tmp);
}
/************* End Generic Converters ***************/
typedef struct {
PyObject_HEAD
int handle;
} HandleObject;
staticforward PyTypeObject Handle_Type;
#define HandleObject_Check(v) ((v)->ob_type == &Handle_Type)
static HandleObject *
newHandleObject(int i)
{
HandleObject *self;
self = PyObject_New(HandleObject, &Handle_Type);
if (self == NULL)
return NULL;
self->handle = i;
return self;
}
/* Handle methods */
static void
Handle_dealloc(HandleObject *self)
{
PyObject_Del(self);
}
/**************** Generic Converters: Handle support ***************/
static PyObject*
handle_conv_new(void *s){
return (PyObject*)newHandleObject((int)s);
}
static int
handle_conv_extract(PyObject *o, void **dest){
HandleObject *h = (HandleObject*)o;
*dest = (void*)h->handle;
return 0;
}
struct converters HandleConvs = {
handle_conv_new,
handle_conv_extract
};
/**************** Generic Converters: Handle support ***************/
statichere PyTypeObject Handle_Type = {
/* The ob_type field must be initialized in the module init function
* to be portable to Windows without using C++. */
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"handle.Handle", /*tp_name*/
sizeof(HandleObject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)Handle_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
};
/* --------------------------------------------------------------------- */
static PyObject *
xx_new(PyObject *self, PyObject *args)
{
HandleObject *rv;
int h;
if (!PyArg_ParseTuple(args, "i:new", &h))
return NULL;
rv = newHandleObject(h);
if ( rv == NULL )
return NULL;
return (PyObject *)rv;
}
static PyObject *
xx_copy(PyObject *self, PyObject *args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O:copy", &obj))
return NULL;
return PyArg_GenericCopy(obj);
}
static PyMethodDef xx_methods[] = {
{"new", xx_new, METH_VARARGS},
{"copy", xx_copy, METH_VARARGS},
{NULL, NULL} /* sentinel */
};
DL_EXPORT(void)
inithandle(void)
{
PyObject *m;
Handle_Type.ob_type = &PyType_Type;
PyType_Ready(&Handle_Type);
PyArg_AddConverters(&Handle_Type, &HandleConvs);
/* Create the module and add the functions */
m = Py_InitModule("handle", xx_methods);
}