Source code for bokeh.command.util

''' Provide utility functions for implementing the ``bokeh`` command.

'''
from __future__ import print_function

import contextlib
import errno
import logging
import os
import sys
import warnings

from bokeh.application import Application
from bokeh.application.handlers import ScriptHandler, DirectoryHandler, NotebookHandler


log = logging.getLogger(__name__)


[docs]def die(message, status=1): ''' Print an error message and exit. This function will call ``sys.exit`` with the given ``status`` and the process will terminate. Args: message (str) : error message to print status (int) : the exit status to pass to ``sys.exit`` ''' print(message, file=sys.stderr) sys.exit(status)
DIRSTYLE_MAIN_WARNING = """ It looks like you might be running the main.py of a directory app directly. If this is the case, to enable the features of directory style apps, you must call "bokeh serve" on the directory instead. For example: bokeh serve my_app_dir/ If this is not the case, renaming main.py will supress this warning. """
[docs]def build_single_handler_application(path, argv=None): ''' Return a Bokeh application built using a single handler for a script, notebook, or directory. In general a Bokeh :class:`~bokeh.application.application.Application` may have any number of handlers to initialize :class:`~bokeh.document.Document` objects for new client sessions. However, in many cases only a single handler is needed. This function examines the ``path`` provided, and returns an ``Application`` initialized with one of the following handlers: * :class:`~bokeh.application.handlers.script.ScriptHandler` when ``path`` is to a ``.py`` script. * :class:`~bokeh.application.handlers.notebook.NotebookHandler` when ``path`` is to an ``.ipynb`` Jupyter notebook. * :class:`~bokeh.application.handlers.directory.DirectoryHandler` when ``path`` is to a directory containing a ``main.py`` script. Args: path (str) : path to a file or directory for creating a Bokeh application. argv (seq[str], optional) : command line arguments to pass to the application handler Returns: :class:`~bokeh.application.application.Application` Raises: RuntimeError Notes: If ``path`` ends with a file ``main.py`` then a warning will be printed regarding running directory-style apps by passing the directory instead. ''' argv = argv or [] path = os.path.abspath(path) if os.path.isdir(path): handler = DirectoryHandler(filename=path, argv=argv) else: if path.endswith(".ipynb"): handler = NotebookHandler(filename=path, argv=argv) elif path.endswith(".py"): if path.endswith("main.py"): warnings.warn(DIRSTYLE_MAIN_WARNING) handler = ScriptHandler(filename=path, argv=argv) else: raise ValueError("Expected a '.py' script or '.ipynb' notebook, got: '%s'" % path) if handler.failed: raise RuntimeError("Error loading %s:\n\n%s\n%s " % (path, handler.error, handler.error_detail)) application = Application(handler) return application
[docs]def build_single_handler_applications(paths, argvs=None): ''' Return a dictionary mapping routes to Bokeh applications built using single handlers, for specified files or directories. This function iterates over ``paths`` and ``argvs`` and calls :func:`~bokeh.command.util.build_single_handler_application` on each to generate the mapping. Args: path (seq[str]) : paths to files or directories for creating Bokeh applications. argvs (dict[str, list[str]], optional) : mapping of paths to command line arguments to pass to the handler for each path Returns: dict[str, Application] Raises: RuntimeError ''' applications = {} argvs = {} or argvs for path in paths: application = build_single_handler_application(path, argvs.get(path, [])) route = application.handlers[0].url_path() if not route: if '/' in applications: raise RuntimeError("Don't know the URL path to use for %s" % (path)) route = '/' applications[route] = application return applications
[docs]@contextlib.contextmanager def report_server_init_errors(address=None, port=None, **kwargs): ''' A context manager to help print more informative error messages when a ``Server`` cannot be started due to a network problem. Args: address (str) : network address that the server will be listening on port (int) : network address that the server will be listening on Example: .. code-block:: python with report_server_init_errors(**server_kwargs): server = Server(applications, **server_kwargs) If there are any errors (e.g. port or address in already in use) then a critical error will be logged and the process will terminate with a call to ``sys.exit(1)`` ''' try: yield except EnvironmentError as e: if e.errno == errno.EADDRINUSE: log.critical("Cannot start Bokeh server, port %s is already in use", port) elif e.errno == errno.EADDRNOTAVAIL: log.critical("Cannot start Bokeh server, address '%s' not available", address) else: codename = errno.errorcode[e.errno] log.critical("Cannot start Bokeh server [%s]: %r", codename, e) sys.exit(1)