prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Add Base.to_graphviz
  Add function to return `graphviz` instance created from dask graph for below reasons:
  - When using IPython, `.visualize` outputs unnecessary image file
  - Sometimes we want to modify graphviz instance directly
  
  
  </issue>
  <code>
  [start of dask/dot.py]
  1 from __future__ import absolute_import, division, print_function
  2 
  3 import re
  4 from subprocess import check_call, CalledProcessError
  5 
  6 from graphviz import Digraph
  7 
  8 from .core import istask, get_dependencies, ishashable
  9 
  10 
  11 def task_label(task):
  12     """Label for a task on a dot graph.
  13 
  14     Examples
  15     --------
  16     >>> from operator import add
  17     >>> task_label((add, 1, 2))
  18     'add'
  19     >>> task_label((add, (add, 1, 2), 3))
  20     'add(...)'
  21     """
  22     func = task[0]
  23     if hasattr(func, 'funcs'):
  24         if len(func.funcs) > 1:
  25             return '{0}(...)'.format(funcname(func.funcs[0]))
  26         else:
  27             head = funcname(func.funcs[0])
  28     else:
  29         head = funcname(task[0])
  30     if any(has_sub_tasks(i) for i in task[1:]):
  31         return '{0}(...)'.format(head)
  32     else:
  33         return head
  34 
  35 
  36 def has_sub_tasks(task):
  37     """Returns True if the task has sub tasks"""
  38     if istask(task):
  39         return True
  40     elif isinstance(task, list):
  41         return any(has_sub_tasks(i) for i in task)
  42     else:
  43         return False
  44 
  45 
  46 def funcname(func):
  47     """Get the name of a function."""
  48     while hasattr(func, 'func'):
  49         func = func.func
  50     return func.__name__
  51 
  52 
  53 def name(x):
  54     try:
  55         return str(hash(x))
  56     except TypeError:
  57         return str(hash(str(x)))
  58 
  59 
  60 _HASHPAT = re.compile('([0-9a-z]{32})')
  61 
  62 
  63 def label(x, cache=None):
  64     """
  65 
  66     >>> label('x')
  67     'x'
  68 
  69     >>> label(('x', 1))
  70     "('x', 1)"
  71 
  72     >>> from hashlib import md5
  73     >>> x = 'x-%s-hello' % md5(b'1234').hexdigest()
  74     >>> x
  75     'x-81dc9bdb52d04dc20036dbd8313ed055-hello'
  76 
  77     >>> label(x)
  78     'x-#-hello'
  79     """
  80     s = str(x)
  81     m = re.search(_HASHPAT, s)
  82     if m is not None:
  83         for h in m.groups():
  84             if cache is not None:
  85                 n = cache.get(h, len(cache))
  86                 label = '#{0}'.format(n)
  87                 # cache will be overwritten destructively
  88                 cache[h] = n
  89             else:
  90                 label = '#'
  91             s = s.replace(h, label)
  92     return s
  93 
  94 
  95 def to_graphviz(dsk, data_attributes=None, function_attributes=None):
  96     if data_attributes is None:
  97         data_attributes = {}
  98     if function_attributes is None:
  99         function_attributes = {}
  100 
  101     g = Digraph(graph_attr={'rankdir': 'BT'})
  102 
  103     seen = set()
  104     cache = {}
  105 
  106     for k, v in dsk.items():
  107         k_name = name(k)
  108         if k_name not in seen:
  109             seen.add(k_name)
  110             g.node(k_name, label=label(k, cache=cache), shape='box',
  111                    **data_attributes.get(k, {}))
  112 
  113         if istask(v):
  114             func_name = name((k, 'function'))
  115             if func_name not in seen:
  116                 seen.add(func_name)
  117                 g.node(func_name, label=task_label(v), shape='circle',
  118                        **function_attributes.get(k, {}))
  119             g.edge(func_name, k_name)
  120 
  121             for dep in get_dependencies(dsk, k):
  122                 dep_name = name(dep)
  123                 if dep_name not in seen:
  124                     seen.add(dep_name)
  125                     g.node(dep_name, label=label(dep, cache=cache), shape='box',
  126                            **data_attributes.get(dep, {}))
  127                 g.edge(dep_name, func_name)
  128         elif ishashable(v) and v in dsk:
  129             g.edge(name(v), k_name)
  130     return g
  131 
  132 
  133 def dot_graph(dsk, filename='mydask', **kwargs):
  134     g = to_graphviz(dsk, **kwargs)
  135     g.save(filename + '.dot')
  136 
  137     try:
  138         check_call('dot -Tpdf {0}.dot -o {0}.pdf'.format(filename), shell=True)
  139         check_call('dot -Tpng {0}.dot -o {0}.png'.format(filename), shell=True)
  140     except CalledProcessError:
  141         raise RuntimeError(
  142             "Please install The `dot` utility from graphviz:\n"
  143             "  Debian:  sudo apt-get install graphviz\n"
  144             "  Mac OSX: brew install graphviz\n"
  145             "  Windows: http://www.graphviz.org/Download..php")  # pragma: no cover
  146     try:
  147         from IPython.display import Image
  148         return Image(filename + '.png')
  149     except ImportError:
  150         pass
  151
  [end of dask/dot.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/dask/dot.py b/dask/dot.py
  --- a/dask/dot.py
  +++ b/dask/dot.py
  @@ -6,6 +6,7 @@
   from graphviz import Digraph
   
   from .core import istask, get_dependencies, ishashable
  +from .compatibility import BytesIO
   
   
   def task_label(task):
  @@ -132,19 +133,35 @@
   
   def dot_graph(dsk, filename='mydask', **kwargs):
       g = to_graphviz(dsk, **kwargs)
  -    g.save(filename + '.dot')
   
  -    try:
  -        check_call('dot -Tpdf {0}.dot -o {0}.pdf'.format(filename), shell=True)
  -        check_call('dot -Tpng {0}.dot -o {0}.png'.format(filename), shell=True)
  -    except CalledProcessError:
  -        raise RuntimeError(
  -            "Please install The `dot` utility from graphviz:\n"
  -            "  Debian:  sudo apt-get install graphviz\n"
  -            "  Mac OSX: brew install graphviz\n"
  -            "  Windows: http://www.graphviz.org/Download..php")  # pragma: no cover
  -    try:
  -        from IPython.display import Image
  -        return Image(filename + '.png')
  -    except ImportError:
  -        pass
  +    if filename is not None:
  +        g.save(filename + '.dot')
  +
  +        try:
  +            check_call('dot -Tpdf {0}.dot -o {0}.pdf'.format(filename),
  +                       shell=True)
  +            check_call('dot -Tpng {0}.dot -o {0}.png'.format(filename),
  +                       shell=True)
  +
  +        except CalledProcessError:
  +            msg = ("Please install The `dot` utility from graphviz:\n"
  +                   "  Debian:  sudo apt-get install graphviz\n"
  +                   "  Mac OSX: brew install graphviz\n"
  +                   "  Windows: http://www.graphviz.org/Download..php")
  +            raise RuntimeError(msg)  # pragma: no cover
  +
  +        try:
  +            from IPython.display import Image
  +            return Image(filename + '.png')
  +        except ImportError:
  +            pass
  +
  +    else:
  +        try:
  +            from IPython.display import Image
  +            s = BytesIO()
  +            s.write(g.pipe(format='png'))
  +            s.seek(0)
  +            return Image(s.read())
  +        except ImportError:
  +            pass
  
verification_info: {"golden_diff": "diff --git a/dask/dot.py b/dask/dot.py\n--- a/dask/dot.py\n+++ b/dask/dot.py\n@@ -6,6 +6,7 @@\n from graphviz import Digraph\n \n from .core import istask, get_dependencies, ishashable\n+from .compatibility import BytesIO\n \n \n def task_label(task):\n@@ -132,19 +133,35 @@\n \n def dot_graph(dsk, filename='mydask', **kwargs):\n     g = to_graphviz(dsk, **kwargs)\n-    g.save(filename + '.dot')\n \n-    try:\n-        check_call('dot -Tpdf {0}.dot -o {0}.pdf'.format(filename), shell=True)\n-        check_call('dot -Tpng {0}.dot -o {0}.png'.format(filename), shell=True)\n-    except CalledProcessError:\n-        raise RuntimeError(\n-            \"Please install The `dot` utility from graphviz:\\n\"\n-            \"  Debian:  sudo apt-get install graphviz\\n\"\n-            \"  Mac OSX: brew install graphviz\\n\"\n-            \"  Windows: http://www.graphviz.org/Download..php\")  # pragma: no cover\n-    try:\n-        from IPython.display import Image\n-        return Image(filename + '.png')\n-    except ImportError:\n-        pass\n+    if filename is not None:\n+        g.save(filename + '.dot')\n+\n+        try:\n+            check_call('dot -Tpdf {0}.dot -o {0}.pdf'.format(filename),\n+                       shell=True)\n+            check_call('dot -Tpng {0}.dot -o {0}.png'.format(filename),\n+                       shell=True)\n+\n+        except CalledProcessError:\n+            msg = (\"Please install The `dot` utility from graphviz:\\n\"\n+                   \"  Debian:  sudo apt-get install graphviz\\n\"\n+                   \"  Mac OSX: brew install graphviz\\n\"\n+                   \"  Windows: http://www.graphviz.org/Download..php\")\n+            raise RuntimeError(msg)  # pragma: no cover\n+\n+        try:\n+            from IPython.display import Image\n+            return Image(filename + '.png')\n+        except ImportError:\n+            pass\n+\n+    else:\n+        try:\n+            from IPython.display import Image\n+            s = BytesIO()\n+            s.write(g.pipe(format='png'))\n+            s.seek(0)\n+            return Image(s.read())\n+        except ImportError:\n+            pass\n", "issue": "Add Base.to_graphviz\nAdd function to return `graphviz` instance created from dask graph for below reasons:\n- When using IPython, `.visualize` outputs unnecessary image file\n- Sometimes we want to modify graphviz instance directly\n\n", "before_files": [{"content": "from __future__ import absolute_import, division, print_function\n\nimport re\nfrom subprocess import check_call, CalledProcessError\n\nfrom graphviz import Digraph\n\nfrom .core import istask, get_dependencies, ishashable\n\n\ndef task_label(task):\n    \"\"\"Label for a task on a dot graph.\n\n    Examples\n    --------\n    >>> from operator import add\n    >>> task_label((add, 1, 2))\n    'add'\n    >>> task_label((add, (add, 1, 2), 3))\n    'add(...)'\n    \"\"\"\n    func = task[0]\n    if hasattr(func, 'funcs'):\n        if len(func.funcs) > 1:\n            return '{0}(...)'.format(funcname(func.funcs[0]))\n        else:\n            head = funcname(func.funcs[0])\n    else:\n        head = funcname(task[0])\n    if any(has_sub_tasks(i) for i in task[1:]):\n        return '{0}(...)'.format(head)\n    else:\n        return head\n\n\ndef has_sub_tasks(task):\n    \"\"\"Returns True if the task has sub tasks\"\"\"\n    if istask(task):\n        return True\n    elif isinstance(task, list):\n        return any(has_sub_tasks(i) for i in task)\n    else:\n        return False\n\n\ndef funcname(func):\n    \"\"\"Get the name of a function.\"\"\"\n    while hasattr(func, 'func'):\n        func = func.func\n    return func.__name__\n\n\ndef name(x):\n    try:\n        return str(hash(x))\n    except TypeError:\n        return str(hash(str(x)))\n\n\n_HASHPAT = re.compile('([0-9a-z]{32})')\n\n\ndef label(x, cache=None):\n    \"\"\"\n\n    >>> label('x')\n    'x'\n\n    >>> label(('x', 1))\n    \"('x', 1)\"\n\n    >>> from hashlib import md5\n    >>> x = 'x-%s-hello' % md5(b'1234').hexdigest()\n    >>> x\n    'x-81dc9bdb52d04dc20036dbd8313ed055-hello'\n\n    >>> label(x)\n    'x-#-hello'\n    \"\"\"\n    s = str(x)\n    m = re.search(_HASHPAT, s)\n    if m is not None:\n        for h in m.groups():\n            if cache is not None:\n                n = cache.get(h, len(cache))\n                label = '#{0}'.format(n)\n                # cache will be overwritten destructively\n                cache[h] = n\n            else:\n                label = '#'\n            s = s.replace(h, label)\n    return s\n\n\ndef to_graphviz(dsk, data_attributes=None, function_attributes=None):\n    if data_attributes is None:\n        data_attributes = {}\n    if function_attributes is None:\n        function_attributes = {}\n\n    g = Digraph(graph_attr={'rankdir': 'BT'})\n\n    seen = set()\n    cache = {}\n\n    for k, v in dsk.items():\n        k_name = name(k)\n        if k_name not in seen:\n            seen.add(k_name)\n            g.node(k_name, label=label(k, cache=cache), shape='box',\n                   **data_attributes.get(k, {}))\n\n        if istask(v):\n            func_name = name((k, 'function'))\n            if func_name not in seen:\n                seen.add(func_name)\n                g.node(func_name, label=task_label(v), shape='circle',\n                       **function_attributes.get(k, {}))\n            g.edge(func_name, k_name)\n\n            for dep in get_dependencies(dsk, k):\n                dep_name = name(dep)\n                if dep_name not in seen:\n                    seen.add(dep_name)\n                    g.node(dep_name, label=label(dep, cache=cache), shape='box',\n                           **data_attributes.get(dep, {}))\n                g.edge(dep_name, func_name)\n        elif ishashable(v) and v in dsk:\n            g.edge(name(v), k_name)\n    return g\n\n\ndef dot_graph(dsk, filename='mydask', **kwargs):\n    g = to_graphviz(dsk, **kwargs)\n    g.save(filename + '.dot')\n\n    try:\n        check_call('dot -Tpdf {0}.dot -o {0}.pdf'.format(filename), shell=True)\n        check_call('dot -Tpng {0}.dot -o {0}.png'.format(filename), shell=True)\n    except CalledProcessError:\n        raise RuntimeError(\n            \"Please install The `dot` utility from graphviz:\\n\"\n            \"  Debian:  sudo apt-get install graphviz\\n\"\n            \"  Mac OSX: brew install graphviz\\n\"\n            \"  Windows: http://www.graphviz.org/Download..php\")  # pragma: no cover\n    try:\n        from IPython.display import Image\n        return Image(filename + '.png')\n    except ImportError:\n        pass\n", "path": "dask/dot.py"}]}