We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
webdriver failing to find installed firefox/geckodriver
Can't get export examples running on binder even though everything is installed and on the path:

<img width="1130" alt="Screen Shot 2020-06-02 at 8 23 16 PM" src="https://user-images.githubusercontent.com/1078448/83592297-e9459c80-a50e-11ea-90d1-7189fcc93af0.png">



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bokeh/io/webdriver.py`
Content:
```
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2012 - 2020, Anaconda, Inc., and Bokeh Contributors.
3 # All rights reserved.
4 #
5 # The full license is in the file LICENSE.txt, distributed with this software.
6 #-----------------------------------------------------------------------------
7 '''
8 
9 '''
10 
11 #-----------------------------------------------------------------------------
12 # Boilerplate
13 #-----------------------------------------------------------------------------
14 import logging # isort:skip
15 log = logging.getLogger(__name__)
16 
17 #-----------------------------------------------------------------------------
18 # Imports
19 #-----------------------------------------------------------------------------
20 
21 from ..util.dependencies import import_required # isort:skip
22 import_required("selenium.webdriver",
23                 "To use bokeh.io image export functions you need selenium "
24                 "('conda install selenium' or 'pip install selenium')")
25 
26 # Standard library imports
27 import atexit
28 import shutil
29 from os.path import devnull
30 from typing import List, Optional
31 
32 # External imports
33 from selenium import webdriver
34 from selenium.webdriver.remote.webdriver import WebDriver
35 from typing_extensions import Literal
36 
37 #-----------------------------------------------------------------------------
38 # Globals and constants
39 #-----------------------------------------------------------------------------
40 
41 DriverKind = Literal["firefox", "chromium"]
42 
43 __all__ = (
44     'webdriver_control',
45 )
46 
47 #-----------------------------------------------------------------------------
48 # General API
49 #-----------------------------------------------------------------------------
50 
51 #-----------------------------------------------------------------------------
52 # Dev API
53 #-----------------------------------------------------------------------------
54 
55 def create_firefox_webdriver() -> WebDriver:
56     from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
57     binary = FirefoxBinary(_detect("firefox"))
58     options = webdriver.firefox.options.Options()
59     options.add_argument("--headless")
60     return webdriver.Firefox(firefox_binary=binary, options=options, service_log_path=devnull)
61 
62 def create_chromium_webdriver() -> WebDriver:
63     options = webdriver.chrome.options.Options()
64     options.add_argument("--headless")
65     options.add_argument("--hide-scrollbars")
66     options.add_argument("--force-device-scale-factor=1")
67     options.add_argument("--force-color-profile=srgb")
68     return webdriver.Chrome(options=options)
69 
70 #-----------------------------------------------------------------------------
71 # Private API
72 #-----------------------------------------------------------------------------
73 
74 def _detect(executable: str) -> Optional[str]:
75     return shutil.which(executable)
76 
77 def _try_create_firefox_webdriver() -> Optional[WebDriver]:
78     try:
79         return create_firefox_webdriver()
80     except Exception:
81         return None
82 
83 def _try_create_chromium_webdriver() -> Optional[WebDriver]:
84     try:
85         return create_chromium_webdriver()
86     except Exception:
87         return None
88 
89 class _WebdriverState:
90     '''
91 
92     '''
93 
94     reuse: bool
95     kind: Optional[DriverKind]
96 
97     current: Optional[WebDriver]
98     _drivers: List[WebDriver]
99 
100     def __init__(self, *, kind: Optional[DriverKind] = None, reuse: bool = True):
101         self.kind = kind
102         self.reuse = reuse
103         self.current = None
104         self._drivers = set()
105 
106     def terminate(self, driver: WebDriver) -> None:
107         self._drivers.remove(driver)
108         driver.quit()
109 
110     def reset(self) -> None:
111         if self.current is not None:
112             self.terminate(self.current)
113             self.current = None
114 
115     def get(self) -> WebDriver:
116         if not self.reuse or self.current is None:
117             self.reset()
118             self.current = self.create()
119         return self.current
120 
121     def create(self, kind: Optional[DriverKind] = None) -> WebDriver:
122         driver = self._create(kind)
123         self._drivers.add(driver)
124         return driver
125 
126     def _create(self, kind: Optional[DriverKind]) -> WebDriver:
127         driver_kind = kind or self.kind
128 
129         if driver_kind is None:
130             driver = _try_create_chromium_webdriver()
131             if driver is not None:
132                 self.kind = "chromium"
133                 return driver
134 
135             driver = _try_create_firefox_webdriver()
136             if driver is not None:
137                 self.kind = "firefox"
138                 return driver
139 
140             raise RuntimeError("Neither firefox and geckodriver nor a variant of chromium browser and " \
141                                "chromedriver are available on system PATH. You can install the former " \
142                                "with 'conda install -c conda-forge firefox geckodriver'.")
143         elif driver_kind == "chromium":
144             return create_chromium_webdriver()
145         elif driver_kind == "firefox":
146             return create_firefox_webdriver()
147         else:
148             raise ValueError(f"'{driver_kind}' is not a recognized webdriver kind")
149 
150     def cleanup(self) -> None:
151         self.reset()
152         for driver in list(self._drivers):
153             self.terminate(driver)
154 
155 #-----------------------------------------------------------------------------
156 # Code
157 #-----------------------------------------------------------------------------
158 
159 webdriver_control = _WebdriverState()
160 
161 atexit.register(lambda: webdriver_control.cleanup())
162
```
--- 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/bokeh/io/webdriver.py b/bokeh/io/webdriver.py
--- a/bokeh/io/webdriver.py
+++ b/bokeh/io/webdriver.py
@@ -25,8 +25,9 @@
 
 # Standard library imports
 import atexit
-import shutil
-from os.path import devnull
+import os
+from os.path import devnull, dirname, isfile, join
+from shutil import which
 from typing import List, Optional
 
 # External imports
@@ -53,11 +54,38 @@
 #-----------------------------------------------------------------------------
 
 def create_firefox_webdriver() -> WebDriver:
+    firefox = which("firefox")
+    if firefox is None:
+        raise RuntimeError("firefox is not installed or not present on PATH")
+
+    geckodriver = which("geckodriver")
+    if geckodriver is None:
+        raise RuntimeError("geckodriver is not installed or not present on PATH")
+
+    firefox_paths = [
+        join(dirname(firefox), "FirefoxApp", "firefox"),
+        join(dirname(firefox), "FirefoxApp", "Contents", "MacOS", "firefox"),
+    ]
+
+    for firefox_path in firefox_paths:
+        if _is_executable(firefox_path):
+            binary_path = firefox_path
+            break
+    else:
+        binary_path = firefox
+
     from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
-    binary = FirefoxBinary(_detect("firefox"))
+    binary = FirefoxBinary(binary_path)
+
     options = webdriver.firefox.options.Options()
     options.add_argument("--headless")
-    return webdriver.Firefox(firefox_binary=binary, options=options, service_log_path=devnull)
+
+    return webdriver.Firefox(
+        options=options,
+        firefox_binary=binary,
+        executable_path=geckodriver,
+        service_log_path=devnull,
+    )
 
 def create_chromium_webdriver() -> WebDriver:
     options = webdriver.chrome.options.Options()
@@ -71,8 +99,8 @@
 # Private API
 #-----------------------------------------------------------------------------
 
-def _detect(executable: str) -> Optional[str]:
-    return shutil.which(executable)
+def _is_executable(path: str) -> bool:
+    return isfile(path) and os.access(path, os.X_OK)
 
 def _try_create_firefox_webdriver() -> Optional[WebDriver]:
     try:

{"golden_diff": "diff --git a/bokeh/io/webdriver.py b/bokeh/io/webdriver.py\n--- a/bokeh/io/webdriver.py\n+++ b/bokeh/io/webdriver.py\n@@ -25,8 +25,9 @@\n \n # Standard library imports\n import atexit\n-import shutil\n-from os.path import devnull\n+import os\n+from os.path import devnull, dirname, isfile, join\n+from shutil import which\n from typing import List, Optional\n \n # External imports\n@@ -53,11 +54,38 @@\n #-----------------------------------------------------------------------------\n \n def create_firefox_webdriver() -> WebDriver:\n+    firefox = which(\"firefox\")\n+    if firefox is None:\n+        raise RuntimeError(\"firefox is not installed or not present on PATH\")\n+\n+    geckodriver = which(\"geckodriver\")\n+    if geckodriver is None:\n+        raise RuntimeError(\"geckodriver is not installed or not present on PATH\")\n+\n+    firefox_paths = [\n+        join(dirname(firefox), \"FirefoxApp\", \"firefox\"),\n+        join(dirname(firefox), \"FirefoxApp\", \"Contents\", \"MacOS\", \"firefox\"),\n+    ]\n+\n+    for firefox_path in firefox_paths:\n+        if _is_executable(firefox_path):\n+            binary_path = firefox_path\n+            break\n+    else:\n+        binary_path = firefox\n+\n     from selenium.webdriver.firefox.firefox_binary import FirefoxBinary\n-    binary = FirefoxBinary(_detect(\"firefox\"))\n+    binary = FirefoxBinary(binary_path)\n+\n     options = webdriver.firefox.options.Options()\n     options.add_argument(\"--headless\")\n-    return webdriver.Firefox(firefox_binary=binary, options=options, service_log_path=devnull)\n+\n+    return webdriver.Firefox(\n+        options=options,\n+        firefox_binary=binary,\n+        executable_path=geckodriver,\n+        service_log_path=devnull,\n+    )\n \n def create_chromium_webdriver() -> WebDriver:\n     options = webdriver.chrome.options.Options()\n@@ -71,8 +99,8 @@\n # Private API\n #-----------------------------------------------------------------------------\n \n-def _detect(executable: str) -> Optional[str]:\n-    return shutil.which(executable)\n+def _is_executable(path: str) -> bool:\n+    return isfile(path) and os.access(path, os.X_OK)\n \n def _try_create_firefox_webdriver() -> Optional[WebDriver]:\n     try:\n", "issue": "webdriver failing to find installed firefox/geckodriver\nCan't get export examples running on binder even though everything is installed and on the path:\r\n\r\n<img width=\"1130\" alt=\"Screen Shot 2020-06-02 at 8 23 16 PM\" src=\"https://user-images.githubusercontent.com/1078448/83592297-e9459c80-a50e-11ea-90d1-7189fcc93af0.png\">\r\n\r\n\n", "before_files": [{"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2012 - 2020, Anaconda, Inc., and Bokeh Contributors.\n# All rights reserved.\n#\n# The full license is in the file LICENSE.txt, distributed with this software.\n#-----------------------------------------------------------------------------\n'''\n\n'''\n\n#-----------------------------------------------------------------------------\n# Boilerplate\n#-----------------------------------------------------------------------------\nimport logging # isort:skip\nlog = logging.getLogger(__name__)\n\n#-----------------------------------------------------------------------------\n# Imports\n#-----------------------------------------------------------------------------\n\nfrom ..util.dependencies import import_required # isort:skip\nimport_required(\"selenium.webdriver\",\n                \"To use bokeh.io image export functions you need selenium \"\n                \"('conda install selenium' or 'pip install selenium')\")\n\n# Standard library imports\nimport atexit\nimport shutil\nfrom os.path import devnull\nfrom typing import List, Optional\n\n# External imports\nfrom selenium import webdriver\nfrom selenium.webdriver.remote.webdriver import WebDriver\nfrom typing_extensions import Literal\n\n#-----------------------------------------------------------------------------\n# Globals and constants\n#-----------------------------------------------------------------------------\n\nDriverKind = Literal[\"firefox\", \"chromium\"]\n\n__all__ = (\n    'webdriver_control',\n)\n\n#-----------------------------------------------------------------------------\n# General API\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Dev API\n#-----------------------------------------------------------------------------\n\ndef create_firefox_webdriver() -> WebDriver:\n    from selenium.webdriver.firefox.firefox_binary import FirefoxBinary\n    binary = FirefoxBinary(_detect(\"firefox\"))\n    options = webdriver.firefox.options.Options()\n    options.add_argument(\"--headless\")\n    return webdriver.Firefox(firefox_binary=binary, options=options, service_log_path=devnull)\n\ndef create_chromium_webdriver() -> WebDriver:\n    options = webdriver.chrome.options.Options()\n    options.add_argument(\"--headless\")\n    options.add_argument(\"--hide-scrollbars\")\n    options.add_argument(\"--force-device-scale-factor=1\")\n    options.add_argument(\"--force-color-profile=srgb\")\n    return webdriver.Chrome(options=options)\n\n#-----------------------------------------------------------------------------\n# Private API\n#-----------------------------------------------------------------------------\n\ndef _detect(executable: str) -> Optional[str]:\n    return shutil.which(executable)\n\ndef _try_create_firefox_webdriver() -> Optional[WebDriver]:\n    try:\n        return create_firefox_webdriver()\n    except Exception:\n        return None\n\ndef _try_create_chromium_webdriver() -> Optional[WebDriver]:\n    try:\n        return create_chromium_webdriver()\n    except Exception:\n        return None\n\nclass _WebdriverState:\n    '''\n\n    '''\n\n    reuse: bool\n    kind: Optional[DriverKind]\n\n    current: Optional[WebDriver]\n    _drivers: List[WebDriver]\n\n    def __init__(self, *, kind: Optional[DriverKind] = None, reuse: bool = True):\n        self.kind = kind\n        self.reuse = reuse\n        self.current = None\n        self._drivers = set()\n\n    def terminate(self, driver: WebDriver) -> None:\n        self._drivers.remove(driver)\n        driver.quit()\n\n    def reset(self) -> None:\n        if self.current is not None:\n            self.terminate(self.current)\n            self.current = None\n\n    def get(self) -> WebDriver:\n        if not self.reuse or self.current is None:\n            self.reset()\n            self.current = self.create()\n        return self.current\n\n    def create(self, kind: Optional[DriverKind] = None) -> WebDriver:\n        driver = self._create(kind)\n        self._drivers.add(driver)\n        return driver\n\n    def _create(self, kind: Optional[DriverKind]) -> WebDriver:\n        driver_kind = kind or self.kind\n\n        if driver_kind is None:\n            driver = _try_create_chromium_webdriver()\n            if driver is not None:\n                self.kind = \"chromium\"\n                return driver\n\n            driver = _try_create_firefox_webdriver()\n            if driver is not None:\n                self.kind = \"firefox\"\n                return driver\n\n            raise RuntimeError(\"Neither firefox and geckodriver nor a variant of chromium browser and \" \\\n                               \"chromedriver are available on system PATH. You can install the former \" \\\n                               \"with 'conda install -c conda-forge firefox geckodriver'.\")\n        elif driver_kind == \"chromium\":\n            return create_chromium_webdriver()\n        elif driver_kind == \"firefox\":\n            return create_firefox_webdriver()\n        else:\n            raise ValueError(f\"'{driver_kind}' is not a recognized webdriver kind\")\n\n    def cleanup(self) -> None:\n        self.reset()\n        for driver in list(self._drivers):\n            self.terminate(driver)\n\n#-----------------------------------------------------------------------------\n# Code\n#-----------------------------------------------------------------------------\n\nwebdriver_control = _WebdriverState()\n\natexit.register(lambda: webdriver_control.cleanup())\n", "path": "bokeh/io/webdriver.py"}], "after_files": [{"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2012 - 2020, Anaconda, Inc., and Bokeh Contributors.\n# All rights reserved.\n#\n# The full license is in the file LICENSE.txt, distributed with this software.\n#-----------------------------------------------------------------------------\n'''\n\n'''\n\n#-----------------------------------------------------------------------------\n# Boilerplate\n#-----------------------------------------------------------------------------\nimport logging # isort:skip\nlog = logging.getLogger(__name__)\n\n#-----------------------------------------------------------------------------\n# Imports\n#-----------------------------------------------------------------------------\n\nfrom ..util.dependencies import import_required # isort:skip\nimport_required(\"selenium.webdriver\",\n                \"To use bokeh.io image export functions you need selenium \"\n                \"('conda install selenium' or 'pip install selenium')\")\n\n# Standard library imports\nimport atexit\nimport os\nfrom os.path import devnull, dirname, isfile, join\nfrom shutil import which\nfrom typing import List, Optional\n\n# External imports\nfrom selenium import webdriver\nfrom selenium.webdriver.remote.webdriver import WebDriver\nfrom typing_extensions import Literal\n\n#-----------------------------------------------------------------------------\n# Globals and constants\n#-----------------------------------------------------------------------------\n\nDriverKind = Literal[\"firefox\", \"chromium\"]\n\n__all__ = (\n    'webdriver_control',\n)\n\n#-----------------------------------------------------------------------------\n# General API\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Dev API\n#-----------------------------------------------------------------------------\n\ndef create_firefox_webdriver() -> WebDriver:\n    firefox = which(\"firefox\")\n    if firefox is None:\n        raise RuntimeError(\"firefox is not installed or not present on PATH\")\n\n    geckodriver = which(\"geckodriver\")\n    if geckodriver is None:\n        raise RuntimeError(\"geckodriver is not installed or not present on PATH\")\n\n    firefox_paths = [\n        join(dirname(firefox), \"FirefoxApp\", \"firefox\"),\n        join(dirname(firefox), \"FirefoxApp\", \"Contents\", \"MacOS\", \"firefox\"),\n    ]\n\n    for firefox_path in firefox_paths:\n        if _is_executable(firefox_path):\n            binary_path = firefox_path\n            break\n    else:\n        binary_path = firefox\n\n    from selenium.webdriver.firefox.firefox_binary import FirefoxBinary\n    binary = FirefoxBinary(binary_path)\n\n    options = webdriver.firefox.options.Options()\n    options.add_argument(\"--headless\")\n\n    return webdriver.Firefox(\n        options=options,\n        firefox_binary=binary,\n        executable_path=geckodriver,\n        service_log_path=devnull,\n    )\n\ndef create_chromium_webdriver() -> WebDriver:\n    options = webdriver.chrome.options.Options()\n    options.add_argument(\"--headless\")\n    options.add_argument(\"--hide-scrollbars\")\n    options.add_argument(\"--force-device-scale-factor=1\")\n    options.add_argument(\"--force-color-profile=srgb\")\n    return webdriver.Chrome(options=options)\n\n#-----------------------------------------------------------------------------\n# Private API\n#-----------------------------------------------------------------------------\n\ndef _is_executable(path: str) -> bool:\n    return isfile(path) and os.access(path, os.X_OK)\n\ndef _try_create_firefox_webdriver() -> Optional[WebDriver]:\n    try:\n        return create_firefox_webdriver()\n    except Exception:\n        return None\n\ndef _try_create_chromium_webdriver() -> Optional[WebDriver]:\n    try:\n        return create_chromium_webdriver()\n    except Exception:\n        return None\n\nclass _WebdriverState:\n    '''\n\n    '''\n\n    reuse: bool\n    kind: Optional[DriverKind]\n\n    current: Optional[WebDriver]\n    _drivers: List[WebDriver]\n\n    def __init__(self, *, kind: Optional[DriverKind] = None, reuse: bool = True):\n        self.kind = kind\n        self.reuse = reuse\n        self.current = None\n        self._drivers = set()\n\n    def terminate(self, driver: WebDriver) -> None:\n        self._drivers.remove(driver)\n        driver.quit()\n\n    def reset(self) -> None:\n        if self.current is not None:\n            self.terminate(self.current)\n            self.current = None\n\n    def get(self) -> WebDriver:\n        if not self.reuse or self.current is None:\n            self.reset()\n            self.current = self.create()\n        return self.current\n\n    def create(self, kind: Optional[DriverKind] = None) -> WebDriver:\n        driver = self._create(kind)\n        self._drivers.add(driver)\n        return driver\n\n    def _create(self, kind: Optional[DriverKind]) -> WebDriver:\n        driver_kind = kind or self.kind\n\n        if driver_kind is None:\n            driver = _try_create_chromium_webdriver()\n            if driver is not None:\n                self.kind = \"chromium\"\n                return driver\n\n            driver = _try_create_firefox_webdriver()\n            if driver is not None:\n                self.kind = \"firefox\"\n                return driver\n\n            raise RuntimeError(\"Neither firefox and geckodriver nor a variant of chromium browser and \" \\\n                               \"chromedriver are available on system PATH. You can install the former \" \\\n                               \"with 'conda install -c conda-forge firefox geckodriver'.\")\n        elif driver_kind == \"chromium\":\n            return create_chromium_webdriver()\n        elif driver_kind == \"firefox\":\n            return create_firefox_webdriver()\n        else:\n            raise ValueError(f\"'{driver_kind}' is not a recognized webdriver kind\")\n\n    def cleanup(self) -> None:\n        self.reset()\n        for driver in list(self._drivers):\n            self.terminate(driver)\n\n#-----------------------------------------------------------------------------\n# Code\n#-----------------------------------------------------------------------------\n\nwebdriver_control = _WebdriverState()\n\natexit.register(lambda: webdriver_control.cleanup())\n", "path": "bokeh/io/webdriver.py"}]}