[Numpy-discussion] numpy.ctypeslib.ndpointer and the restype attribute [patch]

Thomas Heller theller@ctypes....
Fri Apr 3 14:38:18 CDT 2009


Thomas Heller schrieb:
>> Sturla Molden schrieb:
>>> On 3/26/2009 12:41 PM, Jens Rantil wrote:
>>> 
>>>> Wouldn't my code, or a tweak of it, be a nice feature in
>>>> numpy.ctypeslib? Is this the wrong channel for proposing things like
>>>> this?
>>> 
>>> If you look at
>>> 
>>>     http://svn.scipy.org/svn/numpy/trunk/numpy/ctypeslib.py
>>> 
>>> you will see that it does almost the same. I think it would be better to 
>>> work out why ndpointer fails as restype and patch that.
>> 
> 
> Thomas Heller schrieb:
> 
>> ndpointer(...), which returns an _nptr instance, does not work as restype
>> because neither it is a base class of one of the ctypes base types like
>> ctypes.c_void_p, also it is not callable with one argument.
>> 
>> There are two ways to fix this.  The first one is to make the _nptr callable
> [...]
>> 
>> The other way is to make _nptr a subclass of ctypes.c_void_p,
>> the result that the foreign function call returns will then be
>> an instance of this class.  Unfortunately, ctypes will not call
>> __new__() to create this instance; so a custom __new__() implementation
>> cannot return a numpy array and we are left with the _nptr instance.
>> The only way to create and access the numpy array is to construct
>> and return one from a method call on the _nptr instance, or a property
>> on the _nptr instance.
>> Ok, .errcheck could call that method and return the result.
>> 
> Well, looking into the ctypes sources trying to invent a new protocol for
> the restype attribute I found out that THERE IS ALREADY a mechanism for it,
> but I had totally forgotten that it exists.
> 
> When the .restype attribute of a function is set to a SUBCLASS of a
> ctypes type (c_void_p for example), an instance of this subclass is created.
> After that, if this instance has a _check_retval_ method, this method is called
> and the result of this call is returned.  So, it is indeed possible to create
> a class that can be assigned to .restype, and which can convert the return value
> of a function to whatever we like.
> 
> I will prepare a patch for numpy.ctypeslib.
> 

It seems there isn't much interest in a patch - true?

Anyway, before it gets totally forgotten, here is the patch.
The _ndptr._check_retval_ method should probably be extended
to handle the memory management of the result.

diff -u c:\python25\lib\site-packages\numpy\ctypeslib.py.orig c:\python25\lib\site-packages\numpy\ctypeslib.py.new
--- c:\python25\lib\site-packages\numpy\ctypeslib.py.orig	Fri Apr 03 19:35:10 2009
+++ c:\python25\lib\site-packages\numpy\ctypeslib.py.new	Fri Apr 03 19:35:10 2009
@@ -69,10 +69,12 @@
     as_ctypes = _dummy
     as_array = _dummy
     from numpy import intp as c_intp
+    _ndptr_base = object
 else:
     import numpy.core._internal as nic
     c_intp = nic._getintp_ctype()
     del nic
+    _ndptr_base = ctypes.c_void_p
 
     # Adapted from Albert Strasheim
     def load_library(libname, loader_path):
@@ -130,7 +132,24 @@
     return res
 
 
-class _ndptr(object):
+class _ndptr(_ndptr_base):
+
+    def _check_retval_(self):
+        """This method is called when this class is used as .restype
+        attribute for a dll function.  It constructs a numpy array from
+        a void pointer."""
+        return array(self)
+
+    @property
+    def __array_interface__(self):
+        return {'descr': self._dtype_.descr,
+                '__ref': self,
+                'strides': None,
+                'shape': self._shape_,
+                'version': 3,
+                'typestr': self._dtype_.descr[0][1],
+                'data': (self.value, False),
+                }
 
     def from_param(cls, obj):
         if not isinstance(obj, ndarray):


-- 
Thanks,
Thomas



More information about the Numpy-discussion mailing list