Repository: ipython/ipython

Issue:
numpy arrays cannot be used with View.apply() in Python 3
In Python 3, numpy arrays cannot be passed to `apply()`, due to explicit use of `buffer` instead of `memoryview`.

Tested on:
Python 3.2.1 (default, Jul 18 2011, 16:24:40) [GCC]
IPython 0.13.dev, 0.12

``` python
from IPython.parallel import Client
import numpy

def test(arr):
    return arr[0]

if __name__ == '__main__':
    dview = Client(profile = 'local')
    arr = numpy.arange(10)

    res = dview[0].apply(test, arr)
    print(res.get())
```

The following error occurs:

``` python
Traceback (most recent call last):
  File "/home/aver/git/sdp/test(emd).py", line 21, in <module>
    res = call_emd(lst, parallel_profile = 'local')
  File "/home/aver/git/sdp/sdp/decorator/parallel.py", line 16, in wrapper
    async_result.append(engines_view.apply_sync(func, i, **kwargs))
  File "<string>", line 2, in apply_sync
  File "/usr/local/lib/python3.2/site-packages/ipython-0.13.dev-py3.2.egg/IPython/parallel/client/view.py", line 70, in spin_after
    ret = f(self, *args, **kwargs)
  File "/usr/local/lib/python3.2/site-packages/ipython-0.13.dev-py3.2.egg/IPython/parallel/client/view.py", line 227, in apply_sync
    return self._really_apply(f, args, kwargs, block=True)
  File "<string>", line 2, in _really_apply
  File "/usr/local/lib/python3.2/site-packages/ipython-0.13.dev-py3.2.egg/IPython/parallel/client/view.py", line 59, in sync_results
    ret = f(self, *args, **kwargs)
  File "<string>", line 2, in _really_apply
  File "/usr/local/lib/python3.2/site-packages/ipython-0.13.dev-py3.2.egg/IPython/parallel/client/view.py", line 48, in save_ids
    ret = f(self, *args, **kwargs)
  File "/usr/local/lib/python3.2/site-packages/ipython-0.13.dev-py3.2.egg/IPython/parallel/client/view.py", line 997, in _really_apply
    return ar.get()
  File "/usr/local/lib/python3.2/site-packages/ipython-0.13.dev-py3.2.egg/IPython/parallel/client/asyncresult.py", line 104, in get
    raise self._exception
  File "/usr/local/lib/python3.2/site-packages/ipython-0.13.dev-py3.2.egg/IPython/parallel/client/asyncresult.py", line 129, in wait
    raise r
IPython.parallel.error.RemoteError: NameError(global name 'buffer' is not defined)
Traceback (most recent call last):
  File "/usr/local/lib/python3.2/site-packages/ipython-0.13.dev-py3.2.egg/IPython/parallel/engine/streamkernel.py", line 320, in apply_request
    f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
  File "/usr/local/lib/python3.2/site-packages/ipython-0.13.dev-py3.2.egg/IPython/parallel/util.py", line 305, in unpack_apply_message
    sa.data = buffer(m)
NameError: global name 'buffer' is not defined
```



Discussion:
Thanks for posting this, I'll keep track of it.  If anyone wants to dig in, it shouldn't be too complicated to do the right thing with memoryviews on Python 3.

I edited the description to make it a bit more clear that this only affects Python 3.


Resolving patch:
diff --git a/IPython/parallel/util.py b/IPython/parallel/util.py
--- a/IPython/parallel/util.py
+++ b/IPython/parallel/util.py
@@ -41,10 +41,14 @@
 
 # IPython imports
 from IPython.config.application import Application
+from IPython.utils import py3compat
 from IPython.utils.pickleutil import can, uncan, canSequence, uncanSequence
 from IPython.utils.newserialized import serialize, unserialize
 from IPython.zmq.log import EnginePUBHandler
 
+if py3compat.PY3:
+    buffer = memoryview
+
 #-----------------------------------------------------------------------------
 # Classes
 #-----------------------------------------------------------------------------


Test patch:
diff --git a/IPython/parallel/tests/test_view.py b/IPython/parallel/tests/test_view.py
--- a/IPython/parallel/tests/test_view.py
+++ b/IPython/parallel/tests/test_view.py
@@ -234,6 +234,19 @@ def test_scatter_gather_numpy(self):
         b = view.gather('a', block=True)
         assert_array_equal(b, a)
     
+    @skip_without('numpy')
+    def test_apply_numpy(self):
+        """view.apply(f, ndarray)"""
+        import numpy
+        from numpy.testing.utils import assert_array_equal, assert_array_almost_equal
+        
+        A = numpy.random.random((100,100))
+        view = self.client[-1]
+        for dt in [ 'int32', 'uint8', 'float32', 'float64' ]:
+            B = A.astype(dt)
+            C = view.apply_sync(lambda x:x, B)
+            assert_array_equal(B,C)
+    
     def test_map(self):
         view = self.client[:]
         def f(x):