We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
save PNG/SVG in Windows
I encountered a problem saving PNG/SVG in Windows. I installed Selenium by 
`
conda install selenium
`
then downloaded chromedriver and put it under the system PATH variable (I think this is working). When I do chart.savechart('test.png'), there's problem message as follows:

```python-traceback
---------------------------------------------------------------------------
PermissionError                           Traceback (most recent call last)
<ipython-input-16-c16ecf6573c1> in <module>()
----> 1 chart.savechart('test.png')

G:\Software\Anaconda2\envs\py36\lib\site-packages\altair\vegalite\v2\api.py in savechart(self, fp, format, **kwargs)
    331             utils.write_file_or_filename(fp, spec_html, mode='w')
    332         elif format in ['png', 'svg']:
--> 333             utils.save_spec(self.to_dict(), fp, format=format, **kwargs)
    334         else:
    335             raise ValueError("unrecognized format: '{0}'".format(format))

G:\Software\Anaconda2\envs\py36\lib\site-packages\altair\utils\headless.py in save_spec(spec, fp, mode, format, driver_timeout)
    136                                                  spec, mode)
    137         finally:
--> 138             os.remove(htmlfile)
    139     finally:
    140         driver.close()

PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\Users\\PAGPI_~1\\AppData\\Local\\Temp\\tmpbyp9uhvp.html'
```

I suppose the temp html file is somehow being used in Windows so it's better to remove it after the chromedriver is closed? Let me know if you guys need further testing under Win environment

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `altair/utils/headless.py`
Content:
```
1 """
2 Utilities that use selenium + chrome headless to save figures
3 """
4 
5 import base64
6 import io
7 import json
8 import os
9 import tempfile
10 
11 import six
12 
13 from .core import write_file_or_filename
14 
15 try:
16     from selenium import webdriver
17 except ImportError:
18     webdriver = None
19 
20 try:
21     from selenium.webdriver.chrome.options import Options as ChromeOptions
22 except ImportError:
23     ChromeOptions = None
24 
25 
26 HTML_TEMPLATE = """
27 <!DOCTYPE html>
28 <html>
29 <head>
30   <title>Embedding Vega-Lite</title>
31   <script src="https://cdn.jsdelivr.net/npm/vega@{vega_version}"></script>
32   <script src="https://cdn.jsdelivr.net/npm/vega-lite@{vegalite_version}"></script>
33   <script src="https://cdn.jsdelivr.net/npm/vega-embed@{vegaembed_version}"></script>
34 </head>
35 <body>
36   <div id="vis"></div>
37 </body>
38 </html>
39 """
40 
41 EXTRACT_CODE = {
42 'png': """
43         var spec = arguments[0];
44         var mode = arguments[1]
45         var done = arguments[2];
46 
47         if(mode === 'vega-lite'){
48           // compile vega-lite to vega
49           const compiled = vl.compile(spec);
50           spec = compiled.spec;
51         }
52 
53         new vega.View(vega.parse(spec), {
54               loader: vega.loader(),
55               logLevel: vega.Warn,
56               renderer: 'none',
57             })
58             .initialize()
59             .toCanvas()
60             .then(function(canvas){return canvas.toDataURL('image/png');})
61             .then(done)
62             .catch(function(err) { console.error(err); });
63         """,
64 'svg': """
65         var spec = arguments[0];
66         var mode = arguments[1];
67         var done = arguments[2];
68 
69         if(mode === 'vega-lite'){
70           // compile vega-lite to vega
71           const compiled = vl.compile(spec);
72           spec = compiled.spec;
73         }
74 
75         new vega.View(vega.parse(spec), {
76               loader: vega.loader(),
77               logLevel: vega.Warn,
78               renderer: 'none',
79             })
80             .initialize()
81             .toSVG()
82             .then(done)
83             .catch(function(err) { console.error(err); });
84         """}
85 
86 def spec_to_image_mimebundle(spec, format, mode,
87                              vega_version,
88                              vegaembed_version,
89                              vegalite_version=None,
90                              driver_timeout=10):
91     """Conver a vega/vega-lite specification to a PNG/SVG image
92 
93     Parameters
94     ----------
95     spec : dict
96         a dictionary representing a vega-lite plot spec
97     format : string {'png' | 'svg'}
98         the file format to be saved.
99     mode : string {'vega' | 'vega-lite'}
100         The rendering mode.
101     vega_version : string
102         For html output, the version of vega.js to use
103     vegalite_version : string
104         For html output, the version of vegalite.js to use
105     vegaembed_version : string
106         For html output, the version of vegaembed.js to use
107     driver_timeout : int (optional)
108         the number of seconds to wait for page load before raising an
109         error (default: 10)
110 
111     Returns
112     -------
113     output : dict
114         a mime-bundle representing the image
115 
116     Note
117     ----
118     This requires the pillow, selenium, and chrome headless packages to be
119     installed.
120     """
121     # TODO: allow package versions to be specified
122     # TODO: detect & use local Jupyter caches of JS packages?
123     if format not in ['png', 'svg']:
124         raise NotImplementedError("format must be 'svg' and 'png'")
125     if mode not in ['vega', 'vega-lite']:
126         raise ValueError("mode must be 'vega' or 'vega-lite'")
127 
128     if mode == 'vega-lite' and vegalite_version is None:
129         raise ValueError("must specify vega-lite version")
130 
131     if webdriver is None:
132         raise ImportError("selenium package is required for saving chart as {0}".format(format))
133     if ChromeOptions is None:
134         raise ImportError("chromedriver is required for saving chart as {0}".format(format))
135 
136     html = HTML_TEMPLATE.format(vega_version=vega_version,
137                                 vegalite_version=vegalite_version,
138                                 vegaembed_version=vegaembed_version)
139 
140     try:
141         chrome_options = ChromeOptions()
142         chrome_options.add_argument("--headless")
143         if os.geteuid() == 0:
144             chrome_options.add_argument('--no-sandbox')
145 
146         driver = webdriver.Chrome(chrome_options=chrome_options)
147         driver.set_page_load_timeout(driver_timeout)
148 
149         try:
150             fd, htmlfile = tempfile.mkstemp(suffix='.html', text=True)
151             with open(htmlfile, 'w') as f:
152                 f.write(html)
153             driver.get("file://" + htmlfile)
154             online = driver.execute_script("return navigator.onLine")
155             if not online:
156                 raise ValueError("Internet connection required for saving chart as {0}".format(format))
157             render = driver.execute_async_script(EXTRACT_CODE[format],
158                                                  spec, mode)
159         finally:
160             os.remove(htmlfile)
161     finally:
162         driver.close()
163 
164     if format == 'png':
165         return {'image/png': base64.decodebytes(render.split(',', 1)[1].encode())}
166     elif format == 'svg':
167         return {'image/svg+xml': render}
168
```
--- 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/altair/utils/headless.py b/altair/utils/headless.py
--- a/altair/utils/headless.py
+++ b/altair/utils/headless.py
@@ -3,15 +3,10 @@
 """
 
 import base64
-import io
-import json
+import contextlib
 import os
 import tempfile
 
-import six
-
-from .core import write_file_or_filename
-
 try:
     from selenium import webdriver
 except ImportError:
@@ -23,6 +18,25 @@
     ChromeOptions = None
 
 
+@contextlib.contextmanager
+def temporary_filename(**kwargs):
+    """Create and clean-up a temporary file
+
+    Arguments are the same as those passed to tempfile.mkstemp
+
+    We could use tempfile.NamedTemporaryFile here, but that causes issues on
+    windows (see https://bugs.python.org/issue14243).
+    """
+    filedescriptor, filename = tempfile.mkstemp(**kwargs)
+    os.close(filedescriptor)
+
+    try:
+        yield filename
+    finally:
+        if os.path.exists(filename):
+            os.remove(filename)
+
+
 HTML_TEMPLATE = """
 <!DOCTYPE html>
 <html>
@@ -83,6 +97,7 @@
             .catch(function(err) { console.error(err); });
         """}
 
+
 def spec_to_image_mimebundle(spec, format, mode,
                              vega_version,
                              vegaembed_version,
@@ -129,9 +144,11 @@
         raise ValueError("must specify vega-lite version")
 
     if webdriver is None:
-        raise ImportError("selenium package is required for saving chart as {0}".format(format))
+        raise ImportError("selenium package is required "
+                          "for saving chart as {0}".format(format))
     if ChromeOptions is None:
-        raise ImportError("chromedriver is required for saving chart as {0}".format(format))
+        raise ImportError("chromedriver is required "
+                          "for saving chart as {0}".format(format))
 
     html = HTML_TEMPLATE.format(vega_version=vega_version,
                                 vegalite_version=vegalite_version,
@@ -146,18 +163,16 @@
         driver = webdriver.Chrome(chrome_options=chrome_options)
         driver.set_page_load_timeout(driver_timeout)
 
-        try:
-            fd, htmlfile = tempfile.mkstemp(suffix='.html', text=True)
+        with temporary_filename(suffix='.html') as htmlfile:
             with open(htmlfile, 'w') as f:
                 f.write(html)
             driver.get("file://" + htmlfile)
             online = driver.execute_script("return navigator.onLine")
             if not online:
-                raise ValueError("Internet connection required for saving chart as {0}".format(format))
+                raise ValueError("Internet connection required for saving "
+                                 "chart as {0}".format(format))
             render = driver.execute_async_script(EXTRACT_CODE[format],
                                                  spec, mode)
-        finally:
-            os.remove(htmlfile)
     finally:
         driver.close()

{"golden_diff": "diff --git a/altair/utils/headless.py b/altair/utils/headless.py\n--- a/altair/utils/headless.py\n+++ b/altair/utils/headless.py\n@@ -3,15 +3,10 @@\n \"\"\"\n \n import base64\n-import io\n-import json\n+import contextlib\n import os\n import tempfile\n \n-import six\n-\n-from .core import write_file_or_filename\n-\n try:\n     from selenium import webdriver\n except ImportError:\n@@ -23,6 +18,25 @@\n     ChromeOptions = None\n \n \n+@contextlib.contextmanager\n+def temporary_filename(**kwargs):\n+    \"\"\"Create and clean-up a temporary file\n+\n+    Arguments are the same as those passed to tempfile.mkstemp\n+\n+    We could use tempfile.NamedTemporaryFile here, but that causes issues on\n+    windows (see https://bugs.python.org/issue14243).\n+    \"\"\"\n+    filedescriptor, filename = tempfile.mkstemp(**kwargs)\n+    os.close(filedescriptor)\n+\n+    try:\n+        yield filename\n+    finally:\n+        if os.path.exists(filename):\n+            os.remove(filename)\n+\n+\n HTML_TEMPLATE = \"\"\"\n <!DOCTYPE html>\n <html>\n@@ -83,6 +97,7 @@\n             .catch(function(err) { console.error(err); });\n         \"\"\"}\n \n+\n def spec_to_image_mimebundle(spec, format, mode,\n                              vega_version,\n                              vegaembed_version,\n@@ -129,9 +144,11 @@\n         raise ValueError(\"must specify vega-lite version\")\n \n     if webdriver is None:\n-        raise ImportError(\"selenium package is required for saving chart as {0}\".format(format))\n+        raise ImportError(\"selenium package is required \"\n+                          \"for saving chart as {0}\".format(format))\n     if ChromeOptions is None:\n-        raise ImportError(\"chromedriver is required for saving chart as {0}\".format(format))\n+        raise ImportError(\"chromedriver is required \"\n+                          \"for saving chart as {0}\".format(format))\n \n     html = HTML_TEMPLATE.format(vega_version=vega_version,\n                                 vegalite_version=vegalite_version,\n@@ -146,18 +163,16 @@\n         driver = webdriver.Chrome(chrome_options=chrome_options)\n         driver.set_page_load_timeout(driver_timeout)\n \n-        try:\n-            fd, htmlfile = tempfile.mkstemp(suffix='.html', text=True)\n+        with temporary_filename(suffix='.html') as htmlfile:\n             with open(htmlfile, 'w') as f:\n                 f.write(html)\n             driver.get(\"file://\" + htmlfile)\n             online = driver.execute_script(\"return navigator.onLine\")\n             if not online:\n-                raise ValueError(\"Internet connection required for saving chart as {0}\".format(format))\n+                raise ValueError(\"Internet connection required for saving \"\n+                                 \"chart as {0}\".format(format))\n             render = driver.execute_async_script(EXTRACT_CODE[format],\n                                                  spec, mode)\n-        finally:\n-            os.remove(htmlfile)\n     finally:\n         driver.close()\n", "issue": "save PNG/SVG in Windows\nI encountered a problem saving PNG/SVG in Windows. I installed Selenium by \r\n`\r\nconda install selenium\r\n`\r\nthen downloaded chromedriver and put it under the system PATH variable (I think this is working). When I do chart.savechart('test.png'), there's problem message as follows:\r\n\r\n```python-traceback\r\n---------------------------------------------------------------------------\r\nPermissionError                           Traceback (most recent call last)\r\n<ipython-input-16-c16ecf6573c1> in <module>()\r\n----> 1 chart.savechart('test.png')\r\n\r\nG:\\Software\\Anaconda2\\envs\\py36\\lib\\site-packages\\altair\\vegalite\\v2\\api.py in savechart(self, fp, format, **kwargs)\r\n    331             utils.write_file_or_filename(fp, spec_html, mode='w')\r\n    332         elif format in ['png', 'svg']:\r\n--> 333             utils.save_spec(self.to_dict(), fp, format=format, **kwargs)\r\n    334         else:\r\n    335             raise ValueError(\"unrecognized format: '{0}'\".format(format))\r\n\r\nG:\\Software\\Anaconda2\\envs\\py36\\lib\\site-packages\\altair\\utils\\headless.py in save_spec(spec, fp, mode, format, driver_timeout)\r\n    136                                                  spec, mode)\r\n    137         finally:\r\n--> 138             os.remove(htmlfile)\r\n    139     finally:\r\n    140         driver.close()\r\n\r\nPermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\\\Users\\\\PAGPI_~1\\\\AppData\\\\Local\\\\Temp\\\\tmpbyp9uhvp.html'\r\n```\r\n\r\nI suppose the temp html file is somehow being used in Windows so it's better to remove it after the chromedriver is closed? Let me know if you guys need further testing under Win environment\n", "before_files": [{"content": "\"\"\"\nUtilities that use selenium + chrome headless to save figures\n\"\"\"\n\nimport base64\nimport io\nimport json\nimport os\nimport tempfile\n\nimport six\n\nfrom .core import write_file_or_filename\n\ntry:\n    from selenium import webdriver\nexcept ImportError:\n    webdriver = None\n\ntry:\n    from selenium.webdriver.chrome.options import Options as ChromeOptions\nexcept ImportError:\n    ChromeOptions = None\n\n\nHTML_TEMPLATE = \"\"\"\n<!DOCTYPE html>\n<html>\n<head>\n  <title>Embedding Vega-Lite</title>\n  <script src=\"https://cdn.jsdelivr.net/npm/vega@{vega_version}\"></script>\n  <script src=\"https://cdn.jsdelivr.net/npm/vega-lite@{vegalite_version}\"></script>\n  <script src=\"https://cdn.jsdelivr.net/npm/vega-embed@{vegaembed_version}\"></script>\n</head>\n<body>\n  <div id=\"vis\"></div>\n</body>\n</html>\n\"\"\"\n\nEXTRACT_CODE = {\n'png': \"\"\"\n        var spec = arguments[0];\n        var mode = arguments[1]\n        var done = arguments[2];\n\n        if(mode === 'vega-lite'){\n          // compile vega-lite to vega\n          const compiled = vl.compile(spec);\n          spec = compiled.spec;\n        }\n\n        new vega.View(vega.parse(spec), {\n              loader: vega.loader(),\n              logLevel: vega.Warn,\n              renderer: 'none',\n            })\n            .initialize()\n            .toCanvas()\n            .then(function(canvas){return canvas.toDataURL('image/png');})\n            .then(done)\n            .catch(function(err) { console.error(err); });\n        \"\"\",\n'svg': \"\"\"\n        var spec = arguments[0];\n        var mode = arguments[1];\n        var done = arguments[2];\n\n        if(mode === 'vega-lite'){\n          // compile vega-lite to vega\n          const compiled = vl.compile(spec);\n          spec = compiled.spec;\n        }\n\n        new vega.View(vega.parse(spec), {\n              loader: vega.loader(),\n              logLevel: vega.Warn,\n              renderer: 'none',\n            })\n            .initialize()\n            .toSVG()\n            .then(done)\n            .catch(function(err) { console.error(err); });\n        \"\"\"}\n\ndef spec_to_image_mimebundle(spec, format, mode,\n                             vega_version,\n                             vegaembed_version,\n                             vegalite_version=None,\n                             driver_timeout=10):\n    \"\"\"Conver a vega/vega-lite specification to a PNG/SVG image\n\n    Parameters\n    ----------\n    spec : dict\n        a dictionary representing a vega-lite plot spec\n    format : string {'png' | 'svg'}\n        the file format to be saved.\n    mode : string {'vega' | 'vega-lite'}\n        The rendering mode.\n    vega_version : string\n        For html output, the version of vega.js to use\n    vegalite_version : string\n        For html output, the version of vegalite.js to use\n    vegaembed_version : string\n        For html output, the version of vegaembed.js to use\n    driver_timeout : int (optional)\n        the number of seconds to wait for page load before raising an\n        error (default: 10)\n\n    Returns\n    -------\n    output : dict\n        a mime-bundle representing the image\n\n    Note\n    ----\n    This requires the pillow, selenium, and chrome headless packages to be\n    installed.\n    \"\"\"\n    # TODO: allow package versions to be specified\n    # TODO: detect & use local Jupyter caches of JS packages?\n    if format not in ['png', 'svg']:\n        raise NotImplementedError(\"format must be 'svg' and 'png'\")\n    if mode not in ['vega', 'vega-lite']:\n        raise ValueError(\"mode must be 'vega' or 'vega-lite'\")\n\n    if mode == 'vega-lite' and vegalite_version is None:\n        raise ValueError(\"must specify vega-lite version\")\n\n    if webdriver is None:\n        raise ImportError(\"selenium package is required for saving chart as {0}\".format(format))\n    if ChromeOptions is None:\n        raise ImportError(\"chromedriver is required for saving chart as {0}\".format(format))\n\n    html = HTML_TEMPLATE.format(vega_version=vega_version,\n                                vegalite_version=vegalite_version,\n                                vegaembed_version=vegaembed_version)\n\n    try:\n        chrome_options = ChromeOptions()\n        chrome_options.add_argument(\"--headless\")\n        if os.geteuid() == 0:\n            chrome_options.add_argument('--no-sandbox')\n\n        driver = webdriver.Chrome(chrome_options=chrome_options)\n        driver.set_page_load_timeout(driver_timeout)\n\n        try:\n            fd, htmlfile = tempfile.mkstemp(suffix='.html', text=True)\n            with open(htmlfile, 'w') as f:\n                f.write(html)\n            driver.get(\"file://\" + htmlfile)\n            online = driver.execute_script(\"return navigator.onLine\")\n            if not online:\n                raise ValueError(\"Internet connection required for saving chart as {0}\".format(format))\n            render = driver.execute_async_script(EXTRACT_CODE[format],\n                                                 spec, mode)\n        finally:\n            os.remove(htmlfile)\n    finally:\n        driver.close()\n\n    if format == 'png':\n        return {'image/png': base64.decodebytes(render.split(',', 1)[1].encode())}\n    elif format == 'svg':\n        return {'image/svg+xml': render}\n", "path": "altair/utils/headless.py"}], "after_files": [{"content": "\"\"\"\nUtilities that use selenium + chrome headless to save figures\n\"\"\"\n\nimport base64\nimport contextlib\nimport os\nimport tempfile\n\ntry:\n    from selenium import webdriver\nexcept ImportError:\n    webdriver = None\n\ntry:\n    from selenium.webdriver.chrome.options import Options as ChromeOptions\nexcept ImportError:\n    ChromeOptions = None\n\n\n@contextlib.contextmanager\ndef temporary_filename(**kwargs):\n    \"\"\"Create and clean-up a temporary file\n\n    Arguments are the same as those passed to tempfile.mkstemp\n\n    We could use tempfile.NamedTemporaryFile here, but that causes issues on\n    windows (see https://bugs.python.org/issue14243).\n    \"\"\"\n    filedescriptor, filename = tempfile.mkstemp(**kwargs)\n    os.close(filedescriptor)\n\n    try:\n        yield filename\n    finally:\n        if os.path.exists(filename):\n            os.remove(filename)\n\n\nHTML_TEMPLATE = \"\"\"\n<!DOCTYPE html>\n<html>\n<head>\n  <title>Embedding Vega-Lite</title>\n  <script src=\"https://cdn.jsdelivr.net/npm/vega@{vega_version}\"></script>\n  <script src=\"https://cdn.jsdelivr.net/npm/vega-lite@{vegalite_version}\"></script>\n  <script src=\"https://cdn.jsdelivr.net/npm/vega-embed@{vegaembed_version}\"></script>\n</head>\n<body>\n  <div id=\"vis\"></div>\n</body>\n</html>\n\"\"\"\n\nEXTRACT_CODE = {\n'png': \"\"\"\n        var spec = arguments[0];\n        var mode = arguments[1]\n        var done = arguments[2];\n\n        if(mode === 'vega-lite'){\n          // compile vega-lite to vega\n          const compiled = vl.compile(spec);\n          spec = compiled.spec;\n        }\n\n        new vega.View(vega.parse(spec), {\n              loader: vega.loader(),\n              logLevel: vega.Warn,\n              renderer: 'none',\n            })\n            .initialize()\n            .toCanvas()\n            .then(function(canvas){return canvas.toDataURL('image/png');})\n            .then(done)\n            .catch(function(err) { console.error(err); });\n        \"\"\",\n'svg': \"\"\"\n        var spec = arguments[0];\n        var mode = arguments[1];\n        var done = arguments[2];\n\n        if(mode === 'vega-lite'){\n          // compile vega-lite to vega\n          const compiled = vl.compile(spec);\n          spec = compiled.spec;\n        }\n\n        new vega.View(vega.parse(spec), {\n              loader: vega.loader(),\n              logLevel: vega.Warn,\n              renderer: 'none',\n            })\n            .initialize()\n            .toSVG()\n            .then(done)\n            .catch(function(err) { console.error(err); });\n        \"\"\"}\n\n\ndef spec_to_image_mimebundle(spec, format, mode,\n                             vega_version,\n                             vegaembed_version,\n                             vegalite_version=None,\n                             driver_timeout=10):\n    \"\"\"Conver a vega/vega-lite specification to a PNG/SVG image\n\n    Parameters\n    ----------\n    spec : dict\n        a dictionary representing a vega-lite plot spec\n    format : string {'png' | 'svg'}\n        the file format to be saved.\n    mode : string {'vega' | 'vega-lite'}\n        The rendering mode.\n    vega_version : string\n        For html output, the version of vega.js to use\n    vegalite_version : string\n        For html output, the version of vegalite.js to use\n    vegaembed_version : string\n        For html output, the version of vegaembed.js to use\n    driver_timeout : int (optional)\n        the number of seconds to wait for page load before raising an\n        error (default: 10)\n\n    Returns\n    -------\n    output : dict\n        a mime-bundle representing the image\n\n    Note\n    ----\n    This requires the pillow, selenium, and chrome headless packages to be\n    installed.\n    \"\"\"\n    # TODO: allow package versions to be specified\n    # TODO: detect & use local Jupyter caches of JS packages?\n    if format not in ['png', 'svg']:\n        raise NotImplementedError(\"format must be 'svg' and 'png'\")\n    if mode not in ['vega', 'vega-lite']:\n        raise ValueError(\"mode must be 'vega' or 'vega-lite'\")\n\n    if mode == 'vega-lite' and vegalite_version is None:\n        raise ValueError(\"must specify vega-lite version\")\n\n    if webdriver is None:\n        raise ImportError(\"selenium package is required \"\n                          \"for saving chart as {0}\".format(format))\n    if ChromeOptions is None:\n        raise ImportError(\"chromedriver is required \"\n                          \"for saving chart as {0}\".format(format))\n\n    html = HTML_TEMPLATE.format(vega_version=vega_version,\n                                vegalite_version=vegalite_version,\n                                vegaembed_version=vegaembed_version)\n\n    try:\n        chrome_options = ChromeOptions()\n        chrome_options.add_argument(\"--headless\")\n        if os.geteuid() == 0:\n            chrome_options.add_argument('--no-sandbox')\n\n        driver = webdriver.Chrome(chrome_options=chrome_options)\n        driver.set_page_load_timeout(driver_timeout)\n\n        with temporary_filename(suffix='.html') as htmlfile:\n            with open(htmlfile, 'w') as f:\n                f.write(html)\n            driver.get(\"file://\" + htmlfile)\n            online = driver.execute_script(\"return navigator.onLine\")\n            if not online:\n                raise ValueError(\"Internet connection required for saving \"\n                                 \"chart as {0}\".format(format))\n            render = driver.execute_async_script(EXTRACT_CODE[format],\n                                                 spec, mode)\n    finally:\n        driver.close()\n\n    if format == 'png':\n        return {'image/png': base64.decodebytes(render.split(',', 1)[1].encode())}\n    elif format == 'svg':\n        return {'image/svg+xml': render}\n", "path": "altair/utils/headless.py"}]}