This docs on this page refers to a PREVIOUS VERSION. For the latest stable release, go to https://docs.bokeh.org/

Archived docs for versions <= 1.0.4 have had to be modified from their original published configuration, and may be missing some features (e.g. source listing)

All users are encourage to update to version 1.1 or later, as soon as they are able.

bokeh.application.application — Bokeh 0.12.14 documentation

Source code for bokeh.application.application

#-----------------------------------------------------------------------------
# Copyright (c) 2012 - 2017, Anaconda, Inc. All rights reserved.
#
# Powered by the Bokeh Development Team.
#
# The full license is in the file LICENSE.txt, distributed with this software.
#-----------------------------------------------------------------------------
''' Provide the ``Application`` class.

Application instances are factories for creating new Bokeh Documents.

When a Bokeh server session is initiated, the Bokeh server asks the Application
for a new Document to service the session. To do this, the Application first
creates a new empty Document, then it passes this new Document to the
``modify_document`` method of each of its handlers. When all handlers have
updated the Document, it is used to service the user session.

'''

#-----------------------------------------------------------------------------
# Boilerplate
#-----------------------------------------------------------------------------
from __future__ import absolute_import, division, print_function, unicode_literals

import logging
log = logging.getLogger(__name__)

from bokeh.util.api import general, dev ; general, dev

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------

# Standard library imports
from abc import ABCMeta, abstractmethod, abstractproperty

# External imports
from tornado import gen

# Bokeh imports
from ..document import Document
from ..settings import settings
from ..util.future import with_metaclass
from ..util.tornado import yield_for_all_futures

#-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------

#-----------------------------------------------------------------------------
# General API
#-----------------------------------------------------------------------------

@general((1,0,0))
[docs]class Application(object): ''' An Application is a factory for Document instances. ''' # This is so that bokeh.io.show can check if a passed in object is an # Application without having to import Application directly. This module # depends on tornado and we have made a commitment that "basic" modules # will function without bringing in tornado. _is_a_bokeh_application_class = True
[docs] def __init__(self, *handlers, **kwargs): ''' Application factory. Args: handlers (seq[Handler]): List of handlers to call. The URL is taken from the first one only. Keyword Args: metadata (dict): abitrary user-supplied JSON data to make available with the application. The server will provide a URL ``http://applicationurl/metadata`` which returns a JSON blob of the form: .. code-block:: json { "data": { "hi": "hi", "there": "there" }, "url": "/myapp" } The user-supplied metadata is returned as-is under the ``"data"`` key in the blob. ''' metadata = kwargs.pop('metadata', None) if kwargs: raise TypeError("Invalid keyword argument: %s" % kwargs.keys()[0]) self._static_path = None self._handlers = [] self._metadata = metadata for h in handlers: self.add(h)
# Properties -------------------------------------------------------------- @property @general((1,0,0)) def handlers(self): ''' The ordered list of handlers this Application is configured with. ''' return tuple(self._handlers) @property @general((1,0,0)) def metadata(self): ''' Arbitrary user-supplied metadata to associate with this application. ''' return self._metadata @property @general((1,0,0)) def safe_to_fork(self): ''' ''' return all(handler.safe_to_fork for handler in self._handlers) @property @general((1,0,0)) def static_path(self): ''' Path to any (optional) static resources specified by handlers. ''' return self._static_path # Public methods ---------------------------------------------------------- @general((1,0,0))
[docs] def add(self, handler): ''' Add a handler to the pipeline used to initialize new documents. Args: handler (Handler) : a handler for this Application to use to process Documents ''' self._handlers.append(handler) # make sure there is at most one static path static_paths = set(h.static_path() for h in self.handlers) static_paths.discard(None) if len(static_paths) > 1: raise RuntimeError("More than one static path requested for app: %r" % list(static_paths)) elif len(static_paths) == 1: self._static_path = static_paths.pop() else: self._static_path = None
@general((1,0,0))
[docs] def create_document(self): ''' Creates and initializes a document using the Application's handlers. ''' doc = Document() self.initialize_document(doc) return doc
@general((1,0,0))
[docs] def initialize_document(self, doc): ''' Fills in a new document using the Application's handlers. ''' for h in self._handlers: # TODO (havocp) we need to check the 'failed' flag on each handler # and build a composite error display. In develop mode, we want to # somehow get these errors to the client. h.modify_document(doc) if h.failed: log.error("Error running application handler %r: %s %s ", h, h.error, h.error_detail) if settings.perform_document_validation(): doc.validate()
@dev((1,0,0))
[docs] def on_server_loaded(self, server_context): ''' Invoked to execute code when a new session is created. This method calls ``on_server_loaded`` on each handler, in order, with the server context passed as the only argument. ''' for h in self._handlers: h.on_server_loaded(server_context)
@dev((1,0,0))
[docs] def on_server_unloaded(self, server_context): ''' Invoked to execute code when the server cleanly exits. (Before stopping the server's ``IOLoop``.) This method calls ``on_server_unloaded`` on each handler, in order, with the server context passed as the only argument. .. warning:: In practice this code may not run, since servers are often killed by a signal. ''' for h in self._handlers: h.on_server_unloaded(server_context)
@gen.coroutine @dev((1,0,0))
[docs] def on_session_created(self, session_context): ''' Invoked to execute code when a new session is created. This method calls ``on_session_created`` on each handler, in order, with the session context passed as the only argument. May return a ``Future`` which will delay session creation until the ``Future`` completes. ''' for h in self._handlers: result = h.on_session_created(session_context) yield yield_for_all_futures(result) raise gen.Return(None)
@gen.coroutine @dev((1,0,0))
[docs] def on_session_destroyed(self, session_context): ''' Invoked to execute code when a session is destroyed. This method calls ``on_session_destroyed`` on each handler, in order, with the session context passed as the only argument. Afterwards, ``session_context.destroyed`` will be ``True``. ''' for h in self._handlers: result = h.on_session_destroyed(session_context) yield yield_for_all_futures(result) raise gen.Return(None)
#----------------------------------------------------------------------------- # Dev API #----------------------------------------------------------------------------- @dev((1,0,0))
[docs]class ServerContext(with_metaclass(ABCMeta)): ''' A harness for server-specific information and tasks related to collections of Bokeh sessions. *This base class is probably not of interest to general users.* ''' # Properties -------------------------------------------------------------- @abstractproperty @dev((1,0,0)) def sessions(self): ''' SessionContext instances belonging to this application. *Subclasses must implement this method.* ''' pass # Public methods ---------------------------------------------------------- @abstractmethod @dev((1,0,0))
[docs] def add_next_tick_callback(self, callback): ''' Add a callback to be run on the next tick of the event loop. *Subclasses must implement this method.* Args: callback (callable) : a callback to add The callback will execute on the next tick of the event loop, and should have the form ``def callback()`` (i.e. it should not accept any arguments) ''' pass
@abstractmethod @dev((1,0,0))
[docs] def add_periodic_callback(self, callback, period_milliseconds): ''' Add a callback to be run periodically until it is removed. *Subclasses must implement this method.* Args: callback (callable) : a callback to add The callback will execute periodically on the event loop as specified, and should have the form ``def callback()`` (i.e. it should not accept any arguments) period_milliseconds (int) : number of milliseconds to wait between executing the callback. ''' pass
@abstractmethod @dev((1,0,0))
[docs] def add_timeout_callback(self, callback, timeout_milliseconds): ''' Add a callback to be run once after timeout_milliseconds. *Subclasses must implement this method.* Args: callback (callable) : a callback to add The callback will execute once on the event loop after the timeout has passed, and should have the form ``def callback()`` (i.e. it should not accept any arguments) timeout_milliseconds (int) : number of milliseconds to wait before executing the callback. ''' pass
@abstractmethod @dev((1,0,0))
[docs] def remove_next_tick_callback(self, callback): ''' Remove a callback added with ``add_next_tick_callback``, before it runs. *Subclasses must implement this method.* Args: callback (callable) : the callback to remove ''' pass
@abstractmethod @dev((1,0,0))
[docs] def remove_periodic_callback(self, callback): ''' Removes a callback added with ``add_periodic_callback``. *Subclasses must implement this method.* Args: callback (callable) : the callback to remove ''' pass
@abstractmethod @dev((1,0,0))
[docs] def remove_timeout_callback(self, callback): ''' Remove a callback added with ``add_timeout_callback``, before it runs. *Subclasses must implement this method.* Args: callback (callable) : the callback to remove ''' pass
@dev((1,0,0))
[docs]class SessionContext(with_metaclass(ABCMeta)): ''' A harness for server-specific information and tasks related to Bokeh sessions. *This base class is probably not of interest to general users.* '''
[docs] def __init__(self, server_context, session_id): ''' ''' self._server_context = server_context self._id = session_id
# Properties -------------------------------------------------------------- @abstractproperty @dev((1,0,0)) def destroyed(self): ''' If ``True``, the session has been discarded and cannot be used. A new session with the same ID could be created later but this instance will not come back to life. ''' pass @property @dev((1,0,0)) def id(self): ''' The unique ID for the session associated with this context. ''' return self._id @property @dev((1,0,0)) def server_context(self): ''' The server context for this session context ''' return self._server_context # Public methods ---------------------------------------------------------- @abstractmethod @dev((1,0,0))
[docs] def with_locked_document(self, func): ''' Runs a function with the document lock held, passing the document to the function. *Subclasses must implement this method.* Args: func (callable): function that takes a single parameter (the Document) and returns ``None`` or a ``Future`` Returns: a ``Future`` containing the result of the function ''' pass
#----------------------------------------------------------------------------- # Private API #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Code #-----------------------------------------------------------------------------