#-----------------------------------------------------------------------------# Copyright (c) Anaconda, Inc., and Bokeh Contributors.# All rights reserved.## 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 Applicationfor a new Document to service the session. To do this, the Application firstcreates a new empty Document, then it passes this new Document to the``modify_document`` method of each of its handlers. When all handlers haveupdated the Document, it is used to service the user session.'''#-----------------------------------------------------------------------------# Boilerplate#-----------------------------------------------------------------------------from__future__importannotationsimportlogging# isort:skiplog=logging.getLogger(__name__)#-----------------------------------------------------------------------------# Imports#-----------------------------------------------------------------------------# Standard library importsfromabcimportABCMeta,abstractmethodfromtypingimport(TYPE_CHECKING,Any,Awaitable,Callable,ClassVar,)# Bokeh importsfrom..core.typesimportIDfrom..documentimportDocumentfrom..settingsimportsettingsifTYPE_CHECKING:fromtornado.httputilimportHTTPServerRequestfromtyping_extensionsimportTypeAliasfrom..server.sessionimportServerSessionfrom.handlers.handlerimportHandler#-----------------------------------------------------------------------------# Globals and constants#-----------------------------------------------------------------------------__all__=('Application','ServerContext','SessionContext',)#-----------------------------------------------------------------------------# General API#-----------------------------------------------------------------------------#-----------------------------------------------------------------------------# Dev API#-----------------------------------------------------------------------------Callback:TypeAlias=Callable[[],None]
[docs]classApplication:''' 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:ClassVar[bool]=True_static_path:str|None_handlers:list[Handler]_metadata:dict[str,Any]|None
[docs]def__init__(self,*handlers:Handler,metadata:dict[str,Any]|None=None)->None:''' Application factory. Args: handlers (seq[Handler]): List of handlers to call. The URL is taken from the first one only. Keyword Args: metadata (dict): arbitrary 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. '''self._static_path=Noneself._handlers=[]self._metadata=metadataforhinhandlers:self.add(h)
# Properties --------------------------------------------------------------@propertydefhandlers(self)->tuple[Handler,...]:''' The ordered list of handlers this Application is configured with. '''returntuple(self._handlers)@propertydefmetadata(self)->dict[str,Any]|None:''' Arbitrary user-supplied metadata to associate with this application. '''returnself._metadata@propertydefsafe_to_fork(self)->bool:''' '''returnall(handler.safe_to_forkforhandlerinself._handlers)@propertydefstatic_path(self)->str|None:''' Path to any (optional) static resources specified by handlers. '''returnself._static_path# Public methods ----------------------------------------------------------
[docs]defadd(self,handler:Handler)->None:''' 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 pathstatic_paths={h.static_path()forhinself.handlers}static_paths.discard(None)iflen(static_paths)>1:raiseRuntimeError("More than one static path requested for app: %r"%list(static_paths))eliflen(static_paths)==1:self._static_path=static_paths.pop()else:self._static_path=None
[docs]defcreate_document(self)->Document:''' Creates and initializes a document using the Application's handlers. '''doc=Document()self.initialize_document(doc)returndoc
[docs]definitialize_document(self,doc:Document)->None:''' Fills in a new document using the Application's handlers. '''forhinself._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)ifh.failed:log.error("Error running application handler %r: %s%s ",h,h.error,h.error_detail)ifsettings.perform_document_validation():doc.validate()
[docs]defon_server_loaded(self,server_context:ServerContext)->None:''' 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. '''forhinself._handlers:h.on_server_loaded(server_context)
[docs]defon_server_unloaded(self,server_context:ServerContext)->None:''' 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. '''forhinself._handlers:h.on_server_unloaded(server_context)
[docs]asyncdefon_session_created(self,session_context:SessionContext)->None:''' 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. '''forhinself._handlers:awaith.on_session_created(session_context)returnNone
[docs]asyncdefon_session_destroyed(self,session_context:SessionContext)->None:''' 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``. '''forhinself._handlers:awaith.on_session_destroyed(session_context)returnNone
[docs]defprocess_request(self,request:HTTPServerRequest)->dict[str,Any]:''' Processes incoming HTTP request returning a dictionary of additional data to add to the session_context. Args: request: HTTP request Returns: A dictionary of JSON serializable data to be included on the session context. '''request_data:dict[str,Any]={}forhinself._handlers:request_data.update(h.process_request(request))returnrequest_data
[docs]classServerContext(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 --------------------------------------------------------------@property@abstractmethoddefsessions(self)->list[ServerSession]:''' ``SessionContext`` instances belonging to this application. *Subclasses must implement this method.* '''pass
[docs]classSessionContext(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.* '''_server_context:ServerContext_id:ID
# Properties --------------------------------------------------------------@property@abstractmethoddefdestroyed(self)->bool:''' 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@propertydefid(self)->ID:''' The unique ID for the session associated with this context. '''returnself._id@propertydefserver_context(self)->ServerContext:''' The server context for this session context '''returnself._server_context# Public methods ----------------------------------------------------------
[docs]@abstractmethoddefwith_locked_document(self,func:Callable[[Document],Awaitable[None]])->Awaitable[None]:''' 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