Repository: ipython/ipython

Issue:
map_sync over empty list raises IndexError
This behavior seems unfortunate to me:

``` python
In [15]: res = view.map_sync(lambda x: x**2,[])
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-15-749102f7b79b> in <module>()
----> 1 res = view.map_sync(lambda x: x**2,[])

/Users/james/.virtualenvs/dish/lib/python2.7/site-packages/ipython-2.0.0-py2.7.egg/IPython/parallel/client/view.pyc in map_sync(self, f, *sequences, **kwargs)
    364             raise TypeError("map_sync doesn't take a `block` keyword argument.")
    365         kwargs['block'] = True
--> 366         return self.map(f,*sequences,**kwargs)
    367
    368     def imap(self, f, *sequences, **kwargs):

/Users/james/.virtualenvs/dish/lib/python2.7/site-packages/ipython-2.0.0-py2.7.egg/IPython/parallel/client/view.pyc in map(self, f, *sequences, **kwargs)

/Users/james/.virtualenvs/dish/lib/python2.7/site-packages/ipython-2.0.0-py2.7.egg/IPython/parallel/client/view.pyc in sync_results(f, self, *args, **kwargs)
     64     self._in_sync_results = True
     65     try:
---> 66         ret = f(self, *args, **kwargs)
     67     finally:
     68         self._in_sync_results = False

/Users/james/.virtualenvs/dish/lib/python2.7/site-packages/ipython-2.0.0-py2.7.egg/IPython/parallel/client/view.pyc in map(self, f, *sequences, **kwargs)

/Users/james/.virtualenvs/dish/lib/python2.7/site-packages/ipython-2.0.0-py2.7.egg/IPython/parallel/client/view.pyc in save_ids(f, self, *args, **kwargs)
     49     n_previous = len(self.client.history)
     50     try:
---> 51         ret = f(self, *args, **kwargs)
     52     finally:
     53         nmsgs = len(self.client.history) - n_previous

/Users/james/.virtualenvs/dish/lib/python2.7/site-packages/ipython-2.0.0-py2.7.egg/IPython/parallel/client/view.pyc in map(self, f, *sequences, **kwargs)
   1121
   1122         pf = ParallelFunction(self, f, block=block, chunksize=chunksize, ordered=ordered)
-> 1123         return pf.map(*sequences)
   1124
   1125 __all__ = ['LoadBalancedView', 'DirectView']

/Users/james/.virtualenvs/dish/lib/python2.7/site-packages/ipython-2.0.0-py2.7.egg/IPython/parallel/client/remotefunction.pyc in map(self, *sequences)
    278         self._mapping = True
    279         try:
--> 280             ret = self(*sequences)
    281         finally:
    282             self._mapping = False

/Users/james/.virtualenvs/dish/lib/python2.7/site-packages/ipython-2.0.0-py2.7.egg/IPython/parallel/client/remotefunction.pyc in __call__(self, *sequences)

/Users/james/.virtualenvs/dish/lib/python2.7/site-packages/ipython-2.0.0-py2.7.egg/IPython/parallel/client/remotefunction.pyc in sync_view_results(f, self, *args, **kwargs)
     89     view = self.view
     90     if view._in_sync_results:
---> 91         return f(self, *args, **kwargs)
     92     view._in_sync_results = True
     93     try:

/Users/james/.virtualenvs/dish/lib/python2.7/site-packages/ipython-2.0.0-py2.7.egg/IPython/parallel/client/remotefunction.pyc in __call__(self, *sequences)
    261         if self.block:
    262             try:
--> 263                 return r.get()
    264             except KeyboardInterrupt:
    265                 return r

/Users/james/.virtualenvs/dish/lib/python2.7/site-packages/ipython-2.0.0-py2.7.egg/IPython/parallel/client/asyncresult.pyc in get(self, timeout)
    116                 return self._result
    117             else:
--> 118                 raise self._exception
    119         else:
    120             raise error.TimeoutError("Result not ready.")

IndexError: list index out of range

In [16]:
```

imho mapping over the empty list should give the empty list. Is there a reason for it to be this way?



Discussion:

Resolving patch:
diff --git a/IPython/parallel/client/remotefunction.py b/IPython/parallel/client/remotefunction.py
--- a/IPython/parallel/client/remotefunction.py
+++ b/IPython/parallel/client/remotefunction.py
@@ -1,20 +1,7 @@
-"""Remote Functions and decorators for Views.
+"""Remote Functions and decorators for Views."""
 
-Authors:
-
-* Brian Granger
-* Min RK
-"""
-#-----------------------------------------------------------------------------
-#  Copyright (C) 2010-2011  The IPython Development Team
-#
-#  Distributed under the terms of the BSD License.  The full license is in
-#  the file COPYING, distributed as part of this software.
-#-----------------------------------------------------------------------------
-
-#-----------------------------------------------------------------------------
-# Imports
-#-----------------------------------------------------------------------------
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
 
 from __future__ import division
 
@@ -203,6 +190,10 @@ def __call__(self, *sequences):
                 minlen = n
             lens.append(n)
         
+        if maxlen == 0:
+            # nothing to iterate over
+            return []
+        
         # check that the length of sequences match
         if not self._mapping and minlen != maxlen:
             msg = 'all sequences must have equal length, but have %s' % lens


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
@@ -1,20 +1,8 @@
 # -*- coding: utf-8 -*-
-"""test View objects
+"""test View objects"""
 
-Authors:
-
-* Min RK
-"""
-#-------------------------------------------------------------------------------
-#  Copyright (C) 2011  The IPython Development Team
-#
-#  Distributed under the terms of the BSD License.  The full license is in
-#  the file COPYING, distributed as part of this software.
-#-------------------------------------------------------------------------------
-
-#-------------------------------------------------------------------------------
-# Imports
-#-------------------------------------------------------------------------------
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
 
 import base64
 import sys
@@ -347,6 +335,11 @@ def f(x):
         r = view.map_sync(f, data)
         self.assertEqual(r, list(map(f, data)))
     
+    def test_map_empty_sequence(self):
+        view = self.client[:]
+        r = view.map_sync(lambda x: x, [])
+        self.assertEqual(r, [])
+    
     def test_map_iterable(self):
         """test map on iterables (direct)"""
         view = self.client[:]