Repository: dask/dask

Issue:
Array astype breaks when given a type instead of a dtype object
The code below fails in dask 0.9.0, numpy 1.11.0, toolz 0.7.4, Python 2.7:
```py
import numpy as np
import dask.array as da

a = np.arange(5).astype(np.int32)
d = da.from_array(a, (1,))
print(d.dtype)
e = d.astype(np.int16)
print(e.dtype)
print(e.compute())
```
with the exception
```
Traceback (most recent call last):
  File "./dask-astype.py", line 8, in <module>
    e = d.astype(np.int16)
  File "/home/bmerry/work/sdp/env/local/lib/python2.7/site-packages/dask/array/core.py", line 1091, in astype
    return elemwise(_astype, self, dtype, name=name)
  File "/home/bmerry/work/sdp/env/local/lib/python2.7/site-packages/dask/array/core.py", line 2159, in elemwise
    out_ndim = len(broadcast_shapes(*shapes))   # Raises ValueError if dimensions mismatch
  File "/home/bmerry/work/sdp/env/local/lib/python2.7/site-packages/dask/array/core.py", line 2131, in broadcast_shapes
    for sizes in zip_longest(*map(reversed, shapes), fillvalue=1):
TypeError: type object argument after * must be a sequence, not itertools.imap
```
If one passes `np.dtype(np.int16)` instead of just `np.int16`, then it works. The problem seems to be that the `np.int16.shape` attribute exists, but isn't a sequence. Possibly this can be fixed by adding `dtype = np.dtype(dtype) to the start of `Array.astype`.

Discussion:

Patch:
diff --git a/dask/array/core.py b/dask/array/core.py
index a82f73979..2cf8f9573 100644
--- a/dask/array/core.py
+++ b/dask/array/core.py
@@ -2062,7 +2062,7 @@ def asarray(array):
     """
     if not isinstance(array, Array):
         name = 'asarray-' + tokenize(array)
-        if not hasattr(array, 'shape'):
+        if isinstance(getattr(array, 'shape', None), Iterable):
             array = np.asarray(array)
         array = from_array(array, chunks=array.shape, name=name)
     return array
@@ -2103,7 +2103,7 @@ def is_scalar_for_elemwise(arg):
     True
     """
     return (np.isscalar(arg)
-            or not hasattr(arg, 'shape')
+            or not isinstance(getattr(arg, 'shape', None), Iterable)
             or isinstance(arg, np.dtype)
             or (isinstance(arg, np.ndarray) and arg.ndim == 0))
 
@@ -2156,6 +2156,7 @@ def elemwise(op, *args, **kwargs):
             (op.__name__, str(sorted(set(kwargs) - set(['name', 'dtype'])))))
 
     shapes = [getattr(arg, 'shape', ()) for arg in args]
+    shapes = [s if isinstance(s, Iterable) else () for s in shapes]
     out_ndim = len(broadcast_shapes(*shapes))   # Raises ValueError if dimensions mismatch
     expr_inds = tuple(range(out_ndim))[::-1]
 


Test patch:
diff --git a/dask/array/tests/test_array_core.py b/dask/array/tests/test_array_core.py
index 555ca3bfc..989a91ad9 100644
--- a/dask/array/tests/test_array_core.py
+++ b/dask/array/tests/test_array_core.py
@@ -2010,3 +2010,9 @@ def test_copy():
 def test_npartitions():
     assert da.ones(5, chunks=(2,)).npartitions == 3
     assert da.ones((5, 5), chunks=(2, 3)).npartitions == 6
+
+
+def test_astype_gh1151():
+    a = np.arange(5).astype(np.int32)
+    b = da.from_array(a, (1,))
+    assert_eq(a.astype(np.int16), b.astype(np.int16))