How to pickle a C struct?

Dave Cole djc at object-craft.com.au
Tue Feb 13 20:05:28 EST 2001


>>>>> "Michael" == Michael Husmann <Michael.Husmann at teleatlas.com> writes:

Michael> I have SWIG(ed) a C library with lots of structs and wanted
Michael> to use the shelve module to store some data on harddisk.
Michael> Those data contains a simple C struct.  I have read that I
Michael> have to add the two functions __getstate__() and
Michael> __setstate__() in addmethods for storing and retrieving.

Michael> Is there someone who has done so to give me an example.

I thought you had to do that too.  You need to use the copy_reg
module.  Here is some code from my Sybase module which allows you to
pickle the numeric type I implemented.

There is probably more code here than you need, but I would prefer to
err on the side of caution.

- Dave

- - from numeric.c - - - - - - - - - - - - - - - - - - - - - - - - - - - -

/* Implement the Sybase.numeric() method
 */
PyObject *NumericType_new(PyObject *module, PyObject *args)
{
    NumericObj *self;
    int precision, scale;
    PyObject *obj;

    self = PyObject_NEW(NumericObj, &NumericType);
    if (self == NULL)
        return NULL;

    precision = -1;
    scale = -1;
    if (PyArg_ParseTuple(args, "O|ii", &obj, &precision, &scale)) {
        NumericObj *num = NULL;

        if (PyInt_Check(obj))
            num = Numeric_FromInt(obj, precision, scale);
        else if (PyLong_Check(obj))
            num = Numeric_FromLong(obj, precision, scale);
        else if (PyFloat_Check(obj))
            num = Numeric_FromFloat(obj, precision, scale);
        else if (PyString_Check(obj))
            num = Numeric_FromString(obj, precision, scale);
        else if (Numeric_Check(obj))
            num = Numeric_FromNumeric(obj, precision, scale);
        else
            raise_exception_string(DataError, "could not convert to Numeric");
        if (num)
            return (PyObject*)num;
    }

    Py_DECREF(self);
    return NULL;
}

/* Used in unpickler
 */
static PyObject *numeric_constructor = NULL;

/* Register the numeric type with the copy_reg module.  This allows
 * Python to (un)pickle numeric objects.  The equivalent Python code
 * is this:
 *
 * def pickle_numeric(n):
 *     return numeric, (str(n), n.precision, n.scale)
 * 
 * copy_reg.pickle(type(numeric(1)), pickle_numeric, numeric)
 */
/* Numeric pickling function
 */
PyObject *pickle_numeric(PyObject *module, PyObject *args)
{
    NumericObj *obj = NULL;
    PyObject *values = NULL,
        *tuple = NULL;
    char text[NUMERIC_LEN];

    if (!PyArg_ParseTuple(args, "O!", &NumericType, &obj))
        goto error;
    numeric_as_string(obj, text);
    if ((values = Py_BuildValue("(sii)", text,
                                obj->num.precision, obj->num.scale)) == NULL)
        goto error;
    tuple = Py_BuildValue("(OO)", numeric_constructor, values);

error:
    Py_XDECREF(values);
    return tuple;
}

/* Register Numeric type pickler
 */
void copy_reg_numeric(PyObject *dict)
{
    PyObject *module = NULL,
        *pickle_func = NULL,
        *pickler = NULL,
        *obj = NULL;

    module = PyImport_ImportModule("copy_reg");
    if (module == NULL)
        goto error;
    if ((pickle_func = PyObject_GetAttrString(module, "pickle")) == NULL)
        goto error;
    if ((numeric_constructor = PyDict_GetItemString(dict, "numeric")) == NULL)
        goto error;
    if ((pickler = PyDict_GetItemString(dict, "pickle_numeric")) == NULL)
        goto error;
    Py_XINCREF(numeric_constructor);
    obj = PyObject_CallFunction(pickle_func, "OOO",
                                &NumericType, pickler, numeric_constructor);

error:
    Py_XDECREF(obj);
    Py_XDECREF(pickler);
    Py_XDECREF(pickle_func);
    Py_XDECREF(module);
}

- - from Sybase.c - - - - - - - - - - - - - - - - - - - - - - - - - - - -

static struct PyMethodDef Sybase_methods[] = {
    { "connect", (PyCFunction)ConnectType_new, METH_VARARGS | METH_KEYWORDS },
    { "numeric", (PyCFunction)NumericType_new, METH_VARARGS },
    { "pickle_numeric", (PyCFunction)pickle_numeric, METH_VARARGS },
    { NULL, NULL }
};

void initSybase(void)
{
    PyObject *module;
    PyObject *dict;

    module = Py_InitModule(module_name, Sybase_methods);
    dict = PyModule_GetDict(module);
        :
        :
    copy_reg_numeric(dict);
}


-- 
http://www.object-craft.com.au



More information about the Python-list mailing list