Repository: mars-project/mars

Issue:
[BUG] Failed to fetch the result of Series.sum
<!--
Thank you for your contribution!

Please review https://github.com/mars-project/mars/blob/master/CONTRIBUTING.rst before opening an issue.
-->

**Describe the bug**
A clear and concise description of what the bug is.

first generate a series of numpy.array, then sum the series

dataframe[some_col].map(gen_numpy_array, dtype=type(np.ones([3]))).sum() failed to get desired output.

produce following error....

**To Reproduce**
To help us reproducing this bug, please provide information below:
1. Your Python version: **Python 3.6.9**
2. The version of Mars you use: **pymars==0.5.1**
3. Versions of crucial packages, such as numpy, scipy and protobuf: **numpy==1.16.6**
4. Full stack of the error.
```
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/.local/lib/python3.6/site-packages/IPython/core/formatters.py in __call__(self, obj)
    700                 type_pprinters=self.type_printers,
    701                 deferred_pprinters=self.deferred_printers)
--> 702             printer.pretty(obj)
    703             printer.flush()
    704             return stream.getvalue()

~/.local/lib/python3.6/site-packages/IPython/lib/pretty.py in pretty(self, obj)
    392                         if cls is not object \
    393                                 and callable(cls.__dict__.get('__repr__')):
--> 394                             return _repr_pprint(obj, self, cycle)
    395 
    396             return _default_pprint(obj, self, cycle)

~/.local/lib/python3.6/site-packages/IPython/lib/pretty.py in _repr_pprint(obj, p, cycle)
    682     """A pprint that just redirects to the normal repr function."""
    683     # Find newlines and replace them with p.break_()
--> 684     output = repr(obj)
    685     lines = output.splitlines()
    686     with p.group():

~/.local/lib/python3.6/site-packages/mars/core.py in __repr__(self)
    127 
    128     def __repr__(self):
--> 129         return self._data.__repr__()
    130 
    131     def _check_data(self, data):

~/.local/lib/python3.6/site-packages/mars/tensor/core.py in __repr__(self)
    177 
    178     def __repr__(self):
--> 179         return self._to_str(representation=True)
    180 
    181     @property

~/.local/lib/python3.6/site-packages/mars/tensor/core.py in _to_str(self, representation)
    165             threshold = print_options['threshold']
    166 
--> 167             corner_data = fetch_corner_data(self, session=self._executed_sessions[-1])
    168             # if less than default threshold, just set it as default,
    169             # if not, set to corner_data.size - 1 make sure ... exists in repr

~/.local/lib/python3.6/site-packages/mars/tensor/utils.py in fetch_corner_data(tensor, session)
    824         return np.block(corners.tolist())
    825     else:
--> 826         return tensor.fetch(session=session)

~/.local/lib/python3.6/site-packages/mars/core.py in fetch(self, session, **kw)
    373         if session is None:
    374             session = Session.default_or_local()
--> 375         return session.fetch(self, **kw)
    376 
    377     def _attach_session(self, session):

~/.local/lib/python3.6/site-packages/mars/session.py in fetch(self, *tileables, **kw)
    494         for r, t in zip(result, tileables):
    495             if hasattr(t, 'isscalar') and t.isscalar() and hasattr(r, 'item'):
--> 496                 ret.append(r.item())
    497             else:
    498                 ret.append(r)

ValueError: can only convert an array of size 1 to a Python scalar
```

5. Minimized code to reproduce the error.

sample data is below:
```
col1,col2,col3
1,xx,yy
2,xx,yy
3,xx,yy
```

```python
import mars.dataframe as pd
```


```python
df = pd.read_csv('sample.txt', sep=",")
```


```python
import numpy as np
```


```python
def gen_array(e):
    return np.ones([3])
```


```python
from mars.config import options
options.eager_mode = True
```


```python
df['col2'].map(gen_array, dtype=type(np.ones([3])))
```




    0    [1.0, 1.0, 1.0]
    1    [1.0, 1.0, 1.0]
    2    [1.0, 1.0, 1.0]
    Name: col2, dtype: object




```python
df['col2'].map(gen_array, dtype=type(np.ones([3]))).sum()
```


    ---------------------------------------------------------------------------

    ValueError                                Traceback (most recent call last)

    ~/.local/lib/python3.6/site-packages/IPython/core/formatters.py in __call__(self, obj)
        700                 type_pprinters=self.type_printers,
        701                 deferred_pprinters=self.deferred_printers)
    --> 702             printer.pretty(obj)
        703             printer.flush()
        704             return stream.getvalue()


    ~/.local/lib/python3.6/site-packages/IPython/lib/pretty.py in pretty(self, obj)
        392                         if cls is not object \
        393                                 and callable(cls.__dict__.get('__repr__')):
    --> 394                             return _repr_pprint(obj, self, cycle)
        395 
        396             return _default_pprint(obj, self, cycle)


    ~/.local/lib/python3.6/site-packages/IPython/lib/pretty.py in _repr_pprint(obj, p, cycle)
        682     """A pprint that just redirects to the normal repr function."""
        683     # Find newlines and replace them with p.break_()
    --> 684     output = repr(obj)
        685     lines = output.splitlines()
        686     with p.group():


    ~/.local/lib/python3.6/site-packages/mars/core.py in __repr__(self)
        127 
        128     def __repr__(self):
    --> 129         return self._data.__repr__()
        130 
        131     def _check_data(self, data):


    ~/.local/lib/python3.6/site-packages/mars/tensor/core.py in __repr__(self)
        177 
        178     def __repr__(self):
    --> 179         return self._to_str(representation=True)
        180 
        181     @property


    ~/.local/lib/python3.6/site-packages/mars/tensor/core.py in _to_str(self, representation)
        165             threshold = print_options['threshold']
        166 
    --> 167             corner_data = fetch_corner_data(self, session=self._executed_sessions[-1])
        168             # if less than default threshold, just set it as default,
        169             # if not, set to corner_data.size - 1 make sure ... exists in repr


    ~/.local/lib/python3.6/site-packages/mars/tensor/utils.py in fetch_corner_data(tensor, session)
        824         return np.block(corners.tolist())
        825     else:
    --> 826         return tensor.fetch(session=session)
    

    ~/.local/lib/python3.6/site-packages/mars/core.py in fetch(self, session, **kw)
        373         if session is None:
        374             session = Session.default_or_local()
    --> 375         return session.fetch(self, **kw)
        376 
        377     def _attach_session(self, session):


    ~/.local/lib/python3.6/site-packages/mars/session.py in fetch(self, *tileables, **kw)
        494         for r, t in zip(result, tileables):
        495             if hasattr(t, 'isscalar') and t.isscalar() and hasattr(r, 'item'):
    --> 496                 ret.append(r.item())
        497             else:
        498                 ret.append(r)


    ValueError: can only convert an array of size 1 to a Python scalar



```python

```


**Expected behavior**
A clear and concise description of what you expected to happen.

array([3., 3., 3.])

**Additional context**
Add any other context about the problem here.



Discussion:

Resolving patch:
diff --git a/mars/session.py b/mars/session.py
--- a/mars/session.py
+++ b/mars/session.py
@@ -530,7 +530,7 @@ def fetch(self, *tileables, **kw):
 
         ret = []
         for r, t in zip(result, tileables):
-            if hasattr(t, 'isscalar') and t.isscalar() and hasattr(r, 'item'):
+            if hasattr(t, 'isscalar') and t.isscalar() and getattr(r, 'size', None) == 1:
                 ret.append(r.item())
             else:
                 ret.append(r)


Test patch:
diff --git a/mars/tests/test_session.py b/mars/tests/test_session.py
--- a/mars/tests/test_session.py
+++ b/mars/tests/test_session.py
@@ -299,6 +299,11 @@ def testFetch(self):
         r6 = sess.run(arr2 + 1)
         np.testing.assert_array_equal(r6[:3, :3], np.ones((3, 3)) * 3)
 
+        df = md.DataFrame(np.random.rand(10, 2), columns=list('ab'))
+        s = df['a'].map(lambda x: np.ones((3, 3)), dtype='object').sum()
+
+        np.testing.assert_array_equal(s.execute().fetch(), np.ones((3, 3)) * 10)
+
         # test fetch multiple tensors
         raw = np.random.rand(5, 10)
         arr1 = mt.ones((5, 10), chunk_size=5)