[pypy-commit] pypy numpypy-ctypes: Added ctypes to arrays. Works, except 2 failing tests.

alex_gaynor noreply at buildbot.pypy.org
Sat Feb 18 03:16:57 CET 2012


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: numpypy-ctypes
Changeset: r52596:69d8667c5a60
Date: 2012-02-17 21:16 -0500
http://bitbucket.org/pypy/pypy/changeset/69d8667c5a60/

Log:	Added ctypes to arrays. Works, except 2 failing tests.

diff --git a/lib_pypy/numpypy/core/_internal.py b/lib_pypy/numpypy/core/_internal.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/numpypy/core/_internal.py
@@ -0,0 +1,78 @@
+#A place for code to be called from C-code
+#  that implements more complicated stuff.
+
+def _getintp_ctype():
+    from _numpypy import dtype
+    val = _getintp_ctype.cache
+    if val is not None:
+        return val
+    char = dtype('p').char
+    import ctypes
+    if (char == 'i'):
+        val = ctypes.c_int
+    elif char == 'l':
+        val = ctypes.c_long
+    elif char == 'q':
+        val = ctypes.c_longlong
+    else:
+        val = ctypes.c_long
+    _getintp_ctype.cache = val
+    return val
+_getintp_ctype.cache = None
+
+# Used for .ctypes attribute of ndarray
+
+class _missing_ctypes(object):
+    def cast(self, num, obj):
+        return num
+
+    def c_void_p(self, num):
+        return num
+
+class _ctypes(object):
+    def __init__(self, array, ptr=None):
+        try:
+            import ctypes
+            self._ctypes = ctypes
+        except ImportError:
+            self._ctypes = _missing_ctypes()
+        self._arr = array
+        self._data = ptr
+        if self._arr.ndim == 0:
+            self._zerod = True
+        else:
+            self._zerod = False
+
+    def data_as(self, obj):
+        return self._ctypes.cast(self._data, obj)
+
+    def shape_as(self, obj):
+        if self._zerod:
+            return None
+        return (obj*self._arr.ndim)(*self._arr.shape)
+
+    def strides_as(self, obj):
+        if self._zerod:
+            return None
+        return (obj*self._arr.ndim)(*self._arr.strides)
+
+    def get_data(self):
+        return self._data
+
+    def get_shape(self):
+        if self._zerod:
+            return None
+        return (_getintp_ctype()*self._arr.ndim)(*self._arr.shape)
+
+    def get_strides(self):
+        if self._zerod:
+            return None
+        return (_getintp_ctype()*self._arr.ndim)(*self._arr.strides)
+
+    def get_as_parameter(self):
+        return self._ctypes.c_void_p(self._data)
+
+    data = property(get_data, None, doc="c-types data")
+    shape = property(get_shape, None, doc="c-types shape")
+    strides = property(get_strides, None, doc="c-types strides")
+    _as_parameter_ = property(get_as_parameter, None, doc="_as parameter_")
diff --git a/pypy/module/micronumpy/appbridge.py b/pypy/module/micronumpy/appbridge.py
--- a/pypy/module/micronumpy/appbridge.py
+++ b/pypy/module/micronumpy/appbridge.py
@@ -2,28 +2,34 @@
 from pypy.rlib.objectmodel import specialize
 
 class AppBridgeCache(object):
+    w_numpypy_core__methods_module = None
     w__var = None
     w__std = None
-    w_module = None
     w_array_repr = None
     w_array_str = None
 
+    w_numpypy_core__internal_module = None
+    w__ctypes = None
+
     def __init__(self, space):
         self.w_import = space.appexec([], """():
-        def f():
+        def f(module):
             import sys
-            __import__('numpypy.core._methods')
-            return sys.modules['numpypy.core._methods']
+            __import__(module)
+            return sys.modules[module]
         return f
         """)
-    
-    @specialize.arg(2)
-    def call_method(self, space, name, *args):
-        w_meth = getattr(self, 'w_' + name)
+
+    @specialize.arg(2, 3)
+    def call_method(self, space, module, name, *args):
+        module_attr = "w_" + module.replace(".", "_") + "_module"
+        meth_attr = "w_" + name
+        w_meth = getattr(self, meth_attr)
         if w_meth is None:
-            if self.w_module is None:
-                self.w_module = space.call_function(self.w_import)
-            w_meth = space.getattr(self.w_module, space.wrap(name))
+            if getattr(self, module_attr) is None:
+                w_mod = space.call_function(self.w_import, space.wrap(module))
+                setattr(self, module_attr, w_mod)
+            w_meth = space.getattr(getattr(self, module_attr), space.wrap(name))
             setattr(self, 'w_' + name, w_meth)
         return space.call_function(w_meth, *args)
 
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -121,11 +121,14 @@
     itemsize = GetSetProperty(W_Dtype.descr_get_itemsize),
     shape = GetSetProperty(W_Dtype.descr_get_shape),
     name = interp_attrproperty('name', cls=W_Dtype),
+    char = interp_attrproperty("char", cls=W_Dtype),
 )
 W_Dtype.typedef.acceptable_as_base_class = False
 
 class DtypeCache(object):
     def __init__(self, space):
+        ptr_size = rffi.sizeof(rffi.VOIDP)
+
         self.w_booldtype = W_Dtype(
             types.Bool(),
             num=0,
@@ -173,6 +176,7 @@
             kind=SIGNEDLTR,
             name="int32",
             char="i",
+            aliases = ["p"] if ptr_size == 4 else [],
             w_box_type=space.gettypefor(interp_boxes.W_Int32Box),
        )
         self.w_uint32dtype = W_Dtype(
@@ -211,6 +215,7 @@
             name="int64",
             char="q",
             w_box_type=space.gettypefor(interp_boxes.W_Int64Box),
+            aliases = ["p"] if ptr_size == 8 else [],
             alternate_constructors=[space.w_long],
         )
         self.w_uint64dtype = W_Dtype(
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -256,9 +256,23 @@
             return
         self.get_concrete().setshape(space, new_shape)
 
+    @jit.unroll_safe
+    def descr_get_strides(self, space):
+        return space.newtuple([space.wrap(i) for i in self.strides])
+
     def descr_get_size(self, space):
         return space.wrap(self.size)
 
+    def descr_get_ctypes(self, space):
+        if not self.shape:
+            raise OperationError(space.w_TypeError, space.wrap("Can't get the ctypes of a scalar yet."))
+        concrete = self.get_concrete()
+        storage = concrete.storage
+        addr = rffi.cast(lltype.Signed, storage)
+        return get_appbridge_cache(space).call_method(space,
+            "numpypy.core._internal", "_ctypes", self, space.wrap(addr)
+        )
+
     def descr_copy(self, space):
         return self.copy(space)
 
@@ -513,12 +527,14 @@
         return space.div(self.descr_sum_promote(space, w_axis), w_denom)
 
     def descr_var(self, space, w_axis=None):
-        return get_appbridge_cache(space).call_method(space, '_var', self,
-                                                      w_axis)
+        return get_appbridge_cache(space).call_method(space,
+            'numpypy.core._methods', '_var', self, w_axis
+        )
 
     def descr_std(self, space, w_axis=None):
-        return get_appbridge_cache(space).call_method(space, '_std', self,
-                                                      w_axis)
+        return get_appbridge_cache(space).call_method(space,
+            'numpypy.core._methods', '_std', self, w_axis
+        )
 
     def descr_fill(self, space, w_value):
         concr = self.get_concrete_or_scalar()
@@ -1291,10 +1307,12 @@
     dtype = GetSetProperty(BaseArray.descr_get_dtype),
     shape = GetSetProperty(BaseArray.descr_get_shape,
                            BaseArray.descr_set_shape),
+    strides = GetSetProperty(BaseArray.descr_get_strides),
     size = GetSetProperty(BaseArray.descr_get_size),
     ndim = GetSetProperty(BaseArray.descr_get_ndim),
     itemsize = GetSetProperty(BaseArray.descr_get_itemsize),
     nbytes = GetSetProperty(BaseArray.descr_get_nbytes),
+    ctypes = GetSetProperty(BaseArray.descr_get_ctypes),
 
     T = GetSetProperty(BaseArray.descr_get_transpose),
     transpose = interp2app(BaseArray.descr_get_transpose),
diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py
--- a/pypy/module/micronumpy/test/test_base.py
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -14,7 +14,7 @@
                 import numpy
                 sys.modules['numpypy'] = numpy
                 sys.modules['_numpypy'] = numpy
-        cls.space = gettestobjspace(usemodules=['micronumpy'])
+        cls.space = gettestobjspace(usemodules=['micronumpy', '_ffi', '_rawffi'])
 
 class TestSignature(object):
     def test_binop_signature(self, space):
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -1709,6 +1709,25 @@
         assert (a + a).item(1) == 4
         raises(ValueError, "array(5).item(1)")
 
+    def test_ctypes(self):
+        import gc
+        from _numpypy import array
+
+        a = array([1, 2, 3, 4, 5])
+        assert a.ctypes._data == a.__array_interface__["data"][0]
+        assert a is a.ctypes._arr
+
+        shape = a.ctypes.get_shape()
+        assert len(shape) == 1
+        assert shape[0] == 5
+
+        strides = a.ctypes.get_strides()
+        assert len(strides) == 1
+        assert strides[0] == 1
+
+        a = array(2)
+        raises(TypeError, lambda: a.ctypes)
+
 class AppTestSupport(BaseNumpyAppTest):
     def setup_class(cls):
         import struct


More information about the pypy-commit mailing list