We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
compute node names within delayed functions
I love using `dask.imperative.delayed` as a decorator to hide the daskyness from the driver code, but the names generated for `dask.dot.dot_graph` leave something to be desired.  Its often easy to compute unique names within the delayed function, e.g.:

```
@delayed
def run(config):
    __task_name = "run_" + config["job_name"]
    res = do_stuff(config)
    return res
```

which can be done with a wrapper:

```
def run(config):
    task_name = "run_" + config["job_name"]
    return delayed(_run, name=task_name)(config)

def _run(config)
    res = do_stuff(config)
    return res
```

Any way to get rid of the wrapper step?


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `dask/dot.py`
Content:
```
1 from __future__ import absolute_import, division, print_function
2 
3 import re
4 from functools import partial
5 
6 from graphviz import Digraph
7 
8 from .core import istask, get_dependencies, ishashable
9 from .utils import funcname
10 
11 
12 def task_label(task):
13     """Label for a task on a dot graph.
14 
15     Examples
16     --------
17     >>> from operator import add
18     >>> task_label((add, 1, 2))
19     'add'
20     >>> task_label((add, (add, 1, 2), 3))
21     'add(...)'
22     """
23     func = task[0]
24     if hasattr(func, 'funcs'):
25         if len(func.funcs) > 1:
26             return '{0}(...)'.format(funcname(func.funcs[0]))
27         else:
28             head = funcname(func.funcs[0])
29     else:
30         head = funcname(task[0])
31     if any(has_sub_tasks(i) for i in task[1:]):
32         return '{0}(...)'.format(head)
33     else:
34         return head
35 
36 
37 def has_sub_tasks(task):
38     """Returns True if the task has sub tasks"""
39     if istask(task):
40         return True
41     elif isinstance(task, list):
42         return any(has_sub_tasks(i) for i in task)
43     else:
44         return False
45 
46 
47 def name(x):
48     try:
49         return str(hash(x))
50     except TypeError:
51         return str(hash(str(x)))
52 
53 
54 _HASHPAT = re.compile('([0-9a-z]{32})')
55 
56 
57 def label(x, cache=None):
58     """
59 
60     >>> label('x')
61     'x'
62 
63     >>> label(('x', 1))
64     "('x', 1)"
65 
66     >>> from hashlib import md5
67     >>> x = 'x-%s-hello' % md5(b'1234').hexdigest()
68     >>> x
69     'x-81dc9bdb52d04dc20036dbd8313ed055-hello'
70 
71     >>> label(x)
72     'x-#-hello'
73     """
74     s = str(x)
75     m = re.search(_HASHPAT, s)
76     if m is not None:
77         for h in m.groups():
78             if cache is not None:
79                 n = cache.get(h, len(cache))
80                 label = '#{0}'.format(n)
81                 # cache will be overwritten destructively
82                 cache[h] = n
83             else:
84                 label = '#'
85             s = s.replace(h, label)
86     return s
87 
88 
89 def to_graphviz(dsk, data_attributes=None, function_attributes=None, **kwargs):
90     if data_attributes is None:
91         data_attributes = {}
92     if function_attributes is None:
93         function_attributes = {}
94 
95     attributes = {'rankdir': 'BT'}
96     attributes.update(kwargs)
97     g = Digraph(graph_attr=attributes)
98 
99     seen = set()
100     cache = {}
101 
102     for k, v in dsk.items():
103         k_name = name(k)
104         if k_name not in seen:
105             seen.add(k_name)
106             g.node(k_name, label=label(k, cache=cache), shape='box',
107                    **data_attributes.get(k, {}))
108 
109         if istask(v):
110             func_name = name((k, 'function'))
111             if func_name not in seen:
112                 seen.add(func_name)
113                 g.node(func_name, label=task_label(v), shape='circle',
114                        **function_attributes.get(k, {}))
115             g.edge(func_name, k_name)
116 
117             for dep in get_dependencies(dsk, k):
118                 dep_name = name(dep)
119                 if dep_name not in seen:
120                     seen.add(dep_name)
121                     g.node(dep_name, label=label(dep, cache=cache), shape='box',
122                            **data_attributes.get(dep, {}))
123                 g.edge(dep_name, func_name)
124         elif ishashable(v) and v in dsk:
125             g.edge(name(v), k_name)
126     return g
127 
128 
129 IPYTHON_IMAGE_FORMATS = frozenset(['jpeg', 'png'])
130 IPYTHON_NO_DISPLAY_FORMATS = frozenset(['dot', 'pdf'])
131 
132 
133 def _get_display_cls(format):
134     """
135     Get the appropriate IPython display class for `format`.
136 
137     Returns `IPython.display.SVG` if format=='svg', otherwise
138     `IPython.display.Image`.
139 
140     If IPython is not importable, return dummy function that swallows its
141     arguments and returns None.
142     """
143     dummy = lambda *args, **kwargs: None
144     try:
145         import IPython.display as display
146     except ImportError:
147         # Can't return a display object if no IPython.
148         return dummy
149 
150     if format in IPYTHON_NO_DISPLAY_FORMATS:
151         # IPython can't display this format natively, so just return None.
152         return dummy
153     elif format in IPYTHON_IMAGE_FORMATS:
154         # Partially apply `format` so that `Image` and `SVG` supply a uniform
155         # interface to the caller.
156         return partial(display.Image, format=format)
157     elif format == 'svg':
158         return display.SVG
159     else:
160         raise ValueError("Unknown format '%s' passed to `dot_graph`" % format)
161 
162 
163 def dot_graph(dsk, filename='mydask', format=None, **kwargs):
164     """
165     Render a task graph using dot.
166 
167     If `filename` is not None, write a file to disk with that name in the
168     format specified by `format`.  `filename` should not include an extension.
169 
170     Parameters
171     ----------
172     dsk : dict
173         The graph to display.
174     filename : str or None, optional
175         The name (without an extension) of the file to write to disk.  If
176         `filename` is None, no file will be written, and we communicate with
177         dot using only pipes.  Default is 'mydask'.
178     format : {'png', 'pdf', 'dot', 'svg', 'jpeg', 'jpg'}, optional
179         Format in which to write output file.  Default is 'png'.
180     **kwargs
181         Additional keyword arguments to forward to `to_graphviz`.
182 
183     Returns
184     -------
185     result : None or IPython.display.Image or IPython.display.SVG  (See below.)
186 
187     Notes
188     -----
189     If IPython is installed, we return an IPython.display object in the
190     requested format.  If IPython is not installed, we just return None.
191 
192     We always return None if format is 'pdf' or 'dot', because IPython can't
193     display these formats natively. Passing these formats with filename=None
194     will not produce any useful output.
195 
196     See Also
197     --------
198     dask.dot.to_graphviz
199     """
200     g = to_graphviz(dsk, **kwargs)
201 
202     fmts = ['.png', '.pdf', '.dot', '.svg', '.jpeg', '.jpg']
203     if format is None and any(filename.lower().endswith(fmt) for fmt in fmts):
204         format = filename.lower().split('.')[-1]
205         filename = filename.rsplit('.')[0]
206 
207     if format is None:
208         format = 'png'
209 
210     data = g.pipe(format=format)
211     if not data:
212         raise RuntimeError("Graphviz failed to properly produce an image. "
213                            "This probably means your installation of graphviz "
214                            "is missing png support. See: "
215                            "https://github.com/ContinuumIO/anaconda-issues/"
216                            "issues/485 for more information.")
217 
218     display_cls = _get_display_cls(format)
219 
220     if not filename:
221         return display_cls(data=data)
222 
223     full_filename = '.'.join([filename, format])
224     with open(full_filename, 'wb') as f:
225         f.write(data)
226 
227     return display_cls(filename=full_filename)
228
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/dask/dot.py b/dask/dot.py
--- a/dask/dot.py
+++ b/dask/dot.py
@@ -52,6 +52,7 @@
 
 
 _HASHPAT = re.compile('([0-9a-z]{32})')
+_UUIDPAT = re.compile('([0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12})')
 
 
 def label(x, cache=None):
@@ -68,21 +69,30 @@
     >>> x
     'x-81dc9bdb52d04dc20036dbd8313ed055-hello'
 
+    >>> label(x)
+    'x-#-hello'
+
+    >>> from uuid import uuid1
+    >>> x = 'x-%s-hello' % uuid1()
+    >>> x  # doctest: +SKIP
+    'x-4c1a3d7e-0b45-11e6-8334-54ee75105593-hello'
+
     >>> label(x)
     'x-#-hello'
     """
     s = str(x)
-    m = re.search(_HASHPAT, s)
-    if m is not None:
-        for h in m.groups():
-            if cache is not None:
-                n = cache.get(h, len(cache))
-                label = '#{0}'.format(n)
-                # cache will be overwritten destructively
-                cache[h] = n
-            else:
-                label = '#'
-            s = s.replace(h, label)
+    for pattern in (_HASHPAT, _UUIDPAT):
+        m = re.search(pattern, s)
+        if m is not None:
+            for h in m.groups():
+                if cache is not None:
+                    n = cache.get(h, len(cache))
+                    label = '#{0}'.format(n)
+                    # cache will be overwritten destructively
+                    cache[h] = n
+                else:
+                    label = '#'
+                s = s.replace(h, label)
     return s

{"golden_diff": "diff --git a/dask/dot.py b/dask/dot.py\n--- a/dask/dot.py\n+++ b/dask/dot.py\n@@ -52,6 +52,7 @@\n \n \n _HASHPAT = re.compile('([0-9a-z]{32})')\n+_UUIDPAT = re.compile('([0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12})')\n \n \n def label(x, cache=None):\n@@ -68,21 +69,30 @@\n     >>> x\n     'x-81dc9bdb52d04dc20036dbd8313ed055-hello'\n \n+    >>> label(x)\n+    'x-#-hello'\n+\n+    >>> from uuid import uuid1\n+    >>> x = 'x-%s-hello' % uuid1()\n+    >>> x  # doctest: +SKIP\n+    'x-4c1a3d7e-0b45-11e6-8334-54ee75105593-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+    for pattern in (_HASHPAT, _UUIDPAT):\n+        m = re.search(pattern, 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", "issue": "compute node names within delayed functions\nI love using `dask.imperative.delayed` as a decorator to hide the daskyness from the driver code, but the names generated for `dask.dot.dot_graph` leave something to be desired.  Its often easy to compute unique names within the delayed function, e.g.:\n\n```\n@delayed\ndef run(config):\n    __task_name = \"run_\" + config[\"job_name\"]\n    res = do_stuff(config)\n    return res\n```\n\nwhich can be done with a wrapper:\n\n```\ndef run(config):\n    task_name = \"run_\" + config[\"job_name\"]\n    return delayed(_run, name=task_name)(config)\n\ndef _run(config)\n    res = do_stuff(config)\n    return res\n```\n\nAny way to get rid of the wrapper step?\n\n", "before_files": [{"content": "from __future__ import absolute_import, division, print_function\n\nimport re\nfrom functools import partial\n\nfrom graphviz import Digraph\n\nfrom .core import istask, get_dependencies, ishashable\nfrom .utils import funcname\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 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, **kwargs):\n    if data_attributes is None:\n        data_attributes = {}\n    if function_attributes is None:\n        function_attributes = {}\n\n    attributes = {'rankdir': 'BT'}\n    attributes.update(kwargs)\n    g = Digraph(graph_attr=attributes)\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\nIPYTHON_IMAGE_FORMATS = frozenset(['jpeg', 'png'])\nIPYTHON_NO_DISPLAY_FORMATS = frozenset(['dot', 'pdf'])\n\n\ndef _get_display_cls(format):\n    \"\"\"\n    Get the appropriate IPython display class for `format`.\n\n    Returns `IPython.display.SVG` if format=='svg', otherwise\n    `IPython.display.Image`.\n\n    If IPython is not importable, return dummy function that swallows its\n    arguments and returns None.\n    \"\"\"\n    dummy = lambda *args, **kwargs: None\n    try:\n        import IPython.display as display\n    except ImportError:\n        # Can't return a display object if no IPython.\n        return dummy\n\n    if format in IPYTHON_NO_DISPLAY_FORMATS:\n        # IPython can't display this format natively, so just return None.\n        return dummy\n    elif format in IPYTHON_IMAGE_FORMATS:\n        # Partially apply `format` so that `Image` and `SVG` supply a uniform\n        # interface to the caller.\n        return partial(display.Image, format=format)\n    elif format == 'svg':\n        return display.SVG\n    else:\n        raise ValueError(\"Unknown format '%s' passed to `dot_graph`\" % format)\n\n\ndef dot_graph(dsk, filename='mydask', format=None, **kwargs):\n    \"\"\"\n    Render a task graph using dot.\n\n    If `filename` is not None, write a file to disk with that name in the\n    format specified by `format`.  `filename` should not include an extension.\n\n    Parameters\n    ----------\n    dsk : dict\n        The graph to display.\n    filename : str or None, optional\n        The name (without an extension) of the file to write to disk.  If\n        `filename` is None, no file will be written, and we communicate with\n        dot using only pipes.  Default is 'mydask'.\n    format : {'png', 'pdf', 'dot', 'svg', 'jpeg', 'jpg'}, optional\n        Format in which to write output file.  Default is 'png'.\n    **kwargs\n        Additional keyword arguments to forward to `to_graphviz`.\n\n    Returns\n    -------\n    result : None or IPython.display.Image or IPython.display.SVG  (See below.)\n\n    Notes\n    -----\n    If IPython is installed, we return an IPython.display object in the\n    requested format.  If IPython is not installed, we just return None.\n\n    We always return None if format is 'pdf' or 'dot', because IPython can't\n    display these formats natively. Passing these formats with filename=None\n    will not produce any useful output.\n\n    See Also\n    --------\n    dask.dot.to_graphviz\n    \"\"\"\n    g = to_graphviz(dsk, **kwargs)\n\n    fmts = ['.png', '.pdf', '.dot', '.svg', '.jpeg', '.jpg']\n    if format is None and any(filename.lower().endswith(fmt) for fmt in fmts):\n        format = filename.lower().split('.')[-1]\n        filename = filename.rsplit('.')[0]\n\n    if format is None:\n        format = 'png'\n\n    data = g.pipe(format=format)\n    if not data:\n        raise RuntimeError(\"Graphviz failed to properly produce an image. \"\n                           \"This probably means your installation of graphviz \"\n                           \"is missing png support. See: \"\n                           \"https://github.com/ContinuumIO/anaconda-issues/\"\n                           \"issues/485 for more information.\")\n\n    display_cls = _get_display_cls(format)\n\n    if not filename:\n        return display_cls(data=data)\n\n    full_filename = '.'.join([filename, format])\n    with open(full_filename, 'wb') as f:\n        f.write(data)\n\n    return display_cls(filename=full_filename)\n", "path": "dask/dot.py"}], "after_files": [{"content": "from __future__ import absolute_import, division, print_function\n\nimport re\nfrom functools import partial\n\nfrom graphviz import Digraph\n\nfrom .core import istask, get_dependencies, ishashable\nfrom .utils import funcname\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 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_UUIDPAT = re.compile('([0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12})')\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    >>> from uuid import uuid1\n    >>> x = 'x-%s-hello' % uuid1()\n    >>> x  # doctest: +SKIP\n    'x-4c1a3d7e-0b45-11e6-8334-54ee75105593-hello'\n\n    >>> label(x)\n    'x-#-hello'\n    \"\"\"\n    s = str(x)\n    for pattern in (_HASHPAT, _UUIDPAT):\n        m = re.search(pattern, 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, **kwargs):\n    if data_attributes is None:\n        data_attributes = {}\n    if function_attributes is None:\n        function_attributes = {}\n\n    attributes = {'rankdir': 'BT'}\n    attributes.update(kwargs)\n    g = Digraph(graph_attr=attributes)\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\nIPYTHON_IMAGE_FORMATS = frozenset(['jpeg', 'png'])\nIPYTHON_NO_DISPLAY_FORMATS = frozenset(['dot', 'pdf'])\n\n\ndef _get_display_cls(format):\n    \"\"\"\n    Get the appropriate IPython display class for `format`.\n\n    Returns `IPython.display.SVG` if format=='svg', otherwise\n    `IPython.display.Image`.\n\n    If IPython is not importable, return dummy function that swallows its\n    arguments and returns None.\n    \"\"\"\n    dummy = lambda *args, **kwargs: None\n    try:\n        import IPython.display as display\n    except ImportError:\n        # Can't return a display object if no IPython.\n        return dummy\n\n    if format in IPYTHON_NO_DISPLAY_FORMATS:\n        # IPython can't display this format natively, so just return None.\n        return dummy\n    elif format in IPYTHON_IMAGE_FORMATS:\n        # Partially apply `format` so that `Image` and `SVG` supply a uniform\n        # interface to the caller.\n        return partial(display.Image, format=format)\n    elif format == 'svg':\n        return display.SVG\n    else:\n        raise ValueError(\"Unknown format '%s' passed to `dot_graph`\" % format)\n\n\ndef dot_graph(dsk, filename='mydask', format=None, **kwargs):\n    \"\"\"\n    Render a task graph using dot.\n\n    If `filename` is not None, write a file to disk with that name in the\n    format specified by `format`.  `filename` should not include an extension.\n\n    Parameters\n    ----------\n    dsk : dict\n        The graph to display.\n    filename : str or None, optional\n        The name (without an extension) of the file to write to disk.  If\n        `filename` is None, no file will be written, and we communicate with\n        dot using only pipes.  Default is 'mydask'.\n    format : {'png', 'pdf', 'dot', 'svg', 'jpeg', 'jpg'}, optional\n        Format in which to write output file.  Default is 'png'.\n    **kwargs\n        Additional keyword arguments to forward to `to_graphviz`.\n\n    Returns\n    -------\n    result : None or IPython.display.Image or IPython.display.SVG  (See below.)\n\n    Notes\n    -----\n    If IPython is installed, we return an IPython.display object in the\n    requested format.  If IPython is not installed, we just return None.\n\n    We always return None if format is 'pdf' or 'dot', because IPython can't\n    display these formats natively. Passing these formats with filename=None\n    will not produce any useful output.\n\n    See Also\n    --------\n    dask.dot.to_graphviz\n    \"\"\"\n    g = to_graphviz(dsk, **kwargs)\n\n    fmts = ['.png', '.pdf', '.dot', '.svg', '.jpeg', '.jpg']\n    if format is None and any(filename.lower().endswith(fmt) for fmt in fmts):\n        format = filename.lower().split('.')[-1]\n        filename = filename.rsplit('.')[0]\n\n    if format is None:\n        format = 'png'\n\n    data = g.pipe(format=format)\n    if not data:\n        raise RuntimeError(\"Graphviz failed to properly produce an image. \"\n                           \"This probably means your installation of graphviz \"\n                           \"is missing png support. See: \"\n                           \"https://github.com/ContinuumIO/anaconda-issues/\"\n                           \"issues/485 for more information.\")\n\n    display_cls = _get_display_cls(format)\n\n    if not filename:\n        return display_cls(data=data)\n\n    full_filename = '.'.join([filename, format])\n    with open(full_filename, 'wb') as f:\n        f.write(data)\n\n    return display_cls(filename=full_filename)\n", "path": "dask/dot.py"}]}