1import functools
2import warnings
3from distutils.version import LooseVersion
4
5import bokeh
6from bokeh.application import Application
7from bokeh.application.handlers.function import FunctionHandler
8from bokeh.server.server import BokehTornado
9
10try:
11    from bokeh.server.util import create_hosts_allowlist
12except ImportError:
13    from bokeh.server.util import create_hosts_whitelist as create_hosts_allowlist
14
15import dask
16
17if LooseVersion(bokeh.__version__) < LooseVersion("1.0.0"):
18    warnings.warn(
19        "\nDask needs bokeh >= 1.0 for the dashboard."
20        "\nContinuing without the dashboard."
21    )
22    raise ImportError("Dask needs bokeh >= 1.0")
23
24
25def BokehApplication(applications, server, prefix="/", template_variables={}):
26    prefix = "/" + prefix.strip("/") + "/" if prefix else "/"
27
28    extra = {"prefix": prefix, **template_variables}
29
30    funcs = {k: functools.partial(v, server, extra) for k, v in applications.items()}
31    apps = {k: Application(FunctionHandler(v)) for k, v in funcs.items()}
32
33    kwargs = dask.config.get("distributed.scheduler.dashboard.bokeh-application").copy()
34    extra_websocket_origins = create_hosts_allowlist(
35        kwargs.pop("allow_websocket_origin"), server.http_server.port
36    )
37
38    return BokehTornado(
39        apps,
40        prefix=prefix,
41        use_index=False,
42        extra_websocket_origins=extra_websocket_origins,
43        **kwargs,
44    )
45