Commits

Antonio Cuni  committed 3ab160d

implement a very simple 'fakearray' type, which exposes just the info for being converted to a regular numpy array

  • Participants
  • Parent commits 40f0d5a

Comments (0)

Files changed (4)

     exe = sys.executable
     ret = os.system('"%s" "%s" build' % (exe, SETUP_PY))
     if ret != 0:
-        sys.exit(1)
+        print "build failed, quitting py.test"
+        raise KeyboardInterrupt
     plat_dir = "lib.%s-%s" % (get_platform(), sys.version[0:3])
     build_dir = BUILD.join(plat_dir)
     for so in build_dir.listdir('*.so'):
 #include <Python.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include "fakenumpy.h"
 
-typedef struct {
-    PyObject_HEAD
-    /* Type-specific fields go here. */
-} PyArrayObject;
+static PyObject*
+PyArray_getbuffer(PyArrayObject* self) {
+    return Py_BuildValue("l", (long)self->data);
+}
+
+static PyObject*
+PyArray_getshape(PyArrayObject* self) {
+    PyObject* res = PyList_New(self->ndims);
+    int i;
+    for(i=0; i<self->ndims; i++)
+        PyList_SET_ITEM(res, i, Py_BuildValue("l", self->dims[i]));
+    return res;
+}
+
+static PyObject*
+PyArray_gettypenum(PyArrayObject* self) {
+    return Py_BuildValue("i", self->typenum);
+}
+
+static PyMethodDef PyArray_methods[] = {
+    {"getbuffer", (PyCFunction)PyArray_getbuffer, METH_NOARGS,
+     "Return the address of the buffer",
+    }, 
+    {"getshape", (PyCFunction)PyArray_getshape, METH_NOARGS,
+     "Return the shape of the array",
+    },
+    {"gettypenum", (PyCFunction)PyArray_gettypenum, METH_NOARGS,
+     "Return the dtype num",
+    },
+    {NULL}  /* Sentinel */
+};
 
 static PyTypeObject PyArray_Type = {
     PyObject_HEAD_INIT(NULL)
     0,                         /*tp_as_buffer*/
     Py_TPFLAGS_DEFAULT,        /*tp_flags*/
     "fake C numpy array",      /* tp_doc */
+    0,  		               /* tp_traverse */
+    0,	    	               /* tp_clear */
+    0,		                   /* tp_richcompare */
+    0,		                   /* tp_weaklistoffset */
+    0,		                   /* tp_iter */
+    0,		                   /* tp_iternext */
+    PyArray_methods,           /* tp_methods */
+    0,                         /* tp_members */
 };
 
 
-static PyObject *
-fakenumpy_foo(PyObject *self, PyObject *args)
-{
-    PyObject *argList = Py_BuildValue("");
+PyObject*
+PyArray_SimpleNewFromData(int nd, npy_intp* dims, int typenum, void* data) {
     PyObject *obj = PyObject_CallObject((PyObject *) &PyArray_Type, NULL);
-    Py_DECREF(argList);
+    PyArrayObject* array = (PyArrayObject*)obj;
+    int i;
+    array->ndims = nd;
+    for(i=0; i<nd; i++)
+        array->dims[i] = dims[i];
+    array->typenum = typenum;
+    array->data = data;
     return obj;
 }
 
 
+static PyObject *
+fakenumpy__frombuffer_2_2(PyObject *self, PyObject *args)
+{
+    npy_intp dims[2] = {2, 2};
+    long address;
+
+    if (!PyArg_ParseTuple(args, "l", &address))
+        return NULL;
+    void* data = (void*)address;
+
+    PyObject* obj = PyArray_SimpleNewFromData(2, dims, PyArray_FLOAT64, data);
+    return obj;
+}
+
+
 static PyMethodDef fakenumpy_methods[] = {
-    {"foo", fakenumpy_foo, METH_VARARGS, "..."},
+    {"_frombuffer_2_2", fakenumpy__frombuffer_2_2, METH_VARARGS, "..."},
     {NULL}  /* Sentinel */
 };
 
+#ifndef FAKENUMPY_H
+#define FAKENUMPY_H
+#include <Python.h>
+
+enum NPY_TYPES {    NPY_BOOL=0,
+                    NPY_BYTE, NPY_UBYTE,
+                    NPY_SHORT, NPY_USHORT,
+                    NPY_INT, NPY_UINT,
+                    NPY_LONG, NPY_ULONG,
+                    NPY_LONGLONG, NPY_ULONGLONG,
+                    NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE,
+                    NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE,
+                    NPY_OBJECT=17,
+                    NPY_STRING, NPY_UNICODE,
+                    NPY_VOID,
+                    /*
+                     * New 1.6 types appended, may be integrated
+                     * into the above in 2.0.
+                     */
+                    NPY_DATETIME, NPY_TIMEDELTA, NPY_HALF,
+
+                    NPY_NTYPES,
+                    NPY_NOTYPE,
+                    NPY_CHAR,      /* special flag */
+                    NPY_USERDEF=256,  /* leave room for characters */
+
+                    /* The number of types not including the new 1.6 types */
+                    NPY_NTYPES_ABI_COMPATIBLE=21
+};
+
+#define PyArray_FLOAT64 NPY_DOUBLE
+typedef long npy_intp;
+
+typedef struct {
+    PyObject_HEAD
+    int ndims;
+    npy_intp dims[10]; // max 10 dimensions
+    int typenum;
+    void* data;
+} PyArrayObject;
+
+static PyTypeObject PyArray_Type;
+
+PyObject*
+PyArray_SimpleNewFromData(int nd, npy_intp* dims, int typenum, void* data);
+
+#endif

File test_fakenumpy.py

+import ctypes
 import fakenumpy
+import numpypy as np
 
+def build_typedict():
+    d = {}
+    for info in np.typeinfo.itervalues():
+        if isinstance(info, tuple):
+            dtype = info[-1]
+            d[info[0]] = dtype
+            d[info[1]] = dtype
+    return d
+
+TYPEDICT = build_typedict()
+
+def _toarray(fakearray):
+    typenum = fakearray.gettypenum()
+    dtype = TYPEDICT[typenum]
+    return np.ndarray._from_shape_and_storage(fakearray.getshape(),
+                                              fakearray.getbuffer(),
+                                              dtype)
+
+
+def test_SimpleNewFromData():
+    buf = (ctypes.c_double*4)(1, 2, 3, 4)
+    addr = ctypes.cast(buf, ctypes.c_void_p).value
+    fakearray = fakenumpy._frombuffer_2_2(addr)
+    assert fakearray.getbuffer() == addr
+    assert fakearray.getshape() == [2, 2]
+    array = _toarray(fakearray)
+    assert array.dtype == np.float64
+    assert array[0, 0] == 1
+    assert array[0, 1] == 2
+    assert array[1, 0] == 3
+    assert array[1, 1] == 4
+    #
+    array[0, 0] = 42
+    assert buf[0] == 42