Repository: dask/dask

Issue:
Slicing delayed objects with delayed objects does not work
I'm trying to wrap my code with delayed, using `dask 0.15.0`, `python 3.6.0` and `numpy 1.12.1`, but I stumbled on an exception.
```
from dask import delayed
import numpy as np
a = delayed(np.arange(10))
b = delayed(2)

a[:b].compute()
```
results in: `TypeError: slice indices must be integers or None or have an __index__ method`

```
a[delayed(slice)(None,b)].compute()
```
Works, even only calling `slice(None,b)` gives no error, but then again `a[slice(None,b)]` gives an identical error. Isn't it to be expected that a delayed object would wrap its own slice objects when sliced?








Discussion:
cc @jcrist 

Resolving patch:
diff --git a/dask/delayed.py b/dask/delayed.py
--- a/dask/delayed.py
+++ b/dask/delayed.py
@@ -64,26 +64,33 @@ def to_task_dask(expr):
     """
     if isinstance(expr, Delayed):
         return expr.key, expr.dask
+
     if isinstance(expr, base.Base):
         name = 'finalize-' + tokenize(expr, pure=True)
         keys = expr._keys()
         dsk = expr._optimize(ensure_dict(expr.dask), keys)
         dsk[name] = (expr._finalize, (concrete, keys))
         return name, dsk
-    if isinstance(expr, tuple) and type(expr) != tuple:
-        return expr, {}
-    if isinstance(expr, (Iterator, list, tuple, set)):
+
+    if isinstance(expr, Iterator):
+        expr = list(expr)
+    typ = type(expr)
+
+    if typ in (list, tuple, set):
         args, dasks = unzip((to_task_dask(e) for e in expr), 2)
         args = list(args)
         dsk = sharedict.merge(*dasks)
         # Ensure output type matches input type
-        if isinstance(expr, (tuple, set)):
-            return (type(expr), args), dsk
-        else:
-            return args, dsk
-    if type(expr) is dict:
+        return (args, dsk) if typ is list else ((typ, args), dsk)
+
+    if typ is dict:
         args, dsk = to_task_dask([[k, v] for k, v in expr.items()])
         return (dict, args), dsk
+
+    if typ is slice:
+        args, dsk = to_task_dask([expr.start, expr.stop, expr.step])
+        return (slice,) + tuple(args), dsk
+
     return expr, {}
 
 


Test patch:
diff --git a/dask/tests/test_delayed.py b/dask/tests/test_delayed.py
--- a/dask/tests/test_delayed.py
+++ b/dask/tests/test_delayed.py
@@ -1,4 +1,4 @@
-from collections import Iterator, namedtuple
+from collections import namedtuple
 from operator import add, setitem
 import pickle
 from random import random
@@ -32,6 +32,10 @@ def test_to_task_dask():
     assert task == x
     assert dict(dask) == {}
 
+    task, dask = to_task_dask(slice(a, b, 3))
+    assert task == (slice, 'a', 'b', 3)
+    assert dict(dask) == merge(a.dask, b.dask)
+
     # Issue https://github.com/dask/dask/issues/2107
     class MyClass(dict):
         pass
@@ -58,6 +62,8 @@ def test_operators():
     a = delayed([1, 2, 3])
     assert a[0].compute() == 1
     assert (a + a).compute() == [1, 2, 3, 1, 2, 3]
+    b = delayed(2)
+    assert a[:b].compute() == [1, 2]
 
     a = delayed(10)
     assert (a + 1).compute() == 11
@@ -154,7 +160,6 @@ def test_lists_are_concrete():
     assert c.compute() == 20
 
 
-@pytest.mark.xfail
 def test_iterators():
     a = delayed(1)
     b = delayed(2)
@@ -163,7 +168,6 @@ def test_iterators():
     assert c.compute() == 3
 
     def f(seq):
-        assert isinstance(seq, Iterator)
         return sum(seq)
 
     c = delayed(f)(iter([a, b]))