🔍 Code Extractor

function modify_document

Maturity: 36

Modifies a Bokeh document by executing a Python script/module within the document's context, with support for autoreload functionality and error handling.

File:
/tf/active/vicechatdev/patches/server.py
Lines:
280 - 355
Complexity:
complex

Purpose

This method is part of a Bokeh application handler that loads and executes Python code to populate a Bokeh document. It handles module creation, document context management, autoreload watching, and error display. The function ensures proper cleanup and error reporting when scripts fail, and supports hot-reloading of code during development.

Source Code

def modify_document(self, doc):
    from bokeh.io.doc import set_curdoc as bk_set_curdoc
    from ..config import config

    if config.autoreload:
        path = self._runner.path
        argv = self._runner._argv
        handler = type(self)(filename=path, argv=argv)
        self._runner = handler._runner

    module = self._runner.new_module()

    # If no module was returned it means the code runner has some permanent
    # unfixable problem, e.g. the configured source code has a syntax error
    if module is None:
        return

    # One reason modules are stored is to prevent the module
    # from being gc'd before the document is. A symptom of a
    # gc'd module is that its globals become None. Additionally
    # stored modules are used to provide correct paths to
    # custom models resolver.
    sys.modules[module.__name__] = module
    doc.modules._modules.append(module)

    try:
        old_doc = curdoc()
    except Exception:
        old_doc=None
    bk_set_curdoc(doc)

    if config.autoreload:
        set_curdoc(doc)
        state.onload(autoreload_watcher)

    try:
        def post_check():
            newdoc = curdoc()
            # Do not let curdoc track modules when autoreload is enabled
            # otherwise it will erroneously complain that there is
            # a memory leak
            if config.autoreload:
                newdoc.modules._modules = []

            # script is supposed to edit the doc not replace it
            if newdoc is not doc:
                raise RuntimeError("%s at '%s' replaced the output document" % (self._origin, self._runner.path))

        def handle_exception(handler, e):
            from bokeh.application.handlers.handler import handle_exception
            from ..pane import HTML

            # Clean up
            del sys.modules[module.__name__]

            if hasattr(doc, 'modules'):
                doc.modules._modules.remove(module)
            else:
                doc._modules.remove(module)
            bokeh.application.handlers.code_runner.handle_exception = handle_exception
            tb = html.escape(traceback.format_exc())

            # Serve error
            HTML(
                f'<b>{type(e).__name__}</b>: {e}</br><pre style="overflow-y: scroll">{tb}</pre>',
                css_classes=['alert', 'alert-danger'], sizing_mode='stretch_width'
            ).servable()

        if config.autoreload:
            bokeh.application.handlers.code_runner.handle_exception = handle_exception
        with _monkeypatch_io(self._loggers):
            with patch_curdoc(doc):
                self._runner.run(module, post_check)
    finally:
        if old_doc!=None:
            bk_set_curdoc(old_doc)

Parameters

Name Type Default Kind
self - - positional_or_keyword
doc - - positional_or_keyword

Parameter Details

self: Instance of the handler class that contains this method. Expected to have attributes: _runner (code runner with path and _argv), _origin (origin identifier), and _loggers (logging configuration).

doc: A Bokeh Document object that will be modified by the executed code. This is the target document where the application's UI components will be added.

Return Value

Returns None implicitly. The function modifies the provided 'doc' parameter in-place by executing code that adds components to it. If the module creation fails (returns None), the function returns early without modifying the document.

Dependencies

  • bokeh
  • param
  • tornado
  • panel
  • flask

Required Imports

import sys
import html
import traceback
import bokeh
import bokeh.application.handlers.code_runner
from bokeh.io import curdoc
from bokeh.application.handlers.code import _monkeypatch_io, patch_curdoc

Conditional/Optional Imports

These imports are only needed under specific conditions:

from bokeh.io.doc import set_curdoc as bk_set_curdoc

Condition: Always imported at function start

Required (conditional)
from ..config import config

Condition: Always imported at function start to check autoreload settings

Required (conditional)
from ..reload import autoreload_watcher

Condition: Only used when config.autoreload is True

Optional
from ..state import state

Condition: Only used when config.autoreload is True

Optional
from bokeh.application.handlers.handler import handle_exception

Condition: Only imported inside exception handler when errors occur

Optional
from ..pane import HTML

Condition: Only imported inside exception handler to display errors

Optional

Usage Example

# This is a method of a handler class, typically used internally by Panel/Bokeh
# Example context where this would be called:

from bokeh.document import Document
from panel.io.handlers import SomeHandler  # Hypothetical handler class

# Create a Bokeh document
doc = Document()

# Create handler instance (with required _runner, _origin, _loggers attributes)
handler = SomeHandler(filename='app.py', argv=[])

# Modify the document by executing the script
handler.modify_document(doc)

# The document is now populated with components from app.py
# If autoreload is enabled, changes to app.py will be detected and reloaded

Best Practices

  • Ensure config.autoreload is properly set before calling this method to control hot-reload behavior
  • The executed script should modify the provided document in-place, not replace it
  • Handle exceptions gracefully as the function includes custom error display using HTML panes
  • Be aware that modules are stored in sys.modules and doc.modules to prevent garbage collection
  • When autoreload is enabled, module tracking is disabled to avoid false memory leak warnings
  • The function manages curdoc() context carefully - ensure proper cleanup in calling code
  • Error messages are displayed as HTML alerts with full tracebacks when execution fails
  • The _runner object must be properly initialized with valid path and argv before calling

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function init_doc 63.7% similar

    Initializes a Bokeh document by registering session information and setting up document lifecycle event handlers for Panel applications.

    From: /tf/active/vicechatdev/patches/server.py
  • function unlocked 61.0% similar

    A context manager that temporarily unlocks a Bokeh Document and dispatches ModelChangedEvents to all connected WebSocket clients during the context execution.

    From: /tf/active/vicechatdev/patches/server.py
  • function autoload_js_script 60.7% similar

    Generates JavaScript code for autoloading a Bokeh document into a web page element, bundling necessary resources and creating render items for embedding.

    From: /tf/active/vicechatdev/patches/server.py
  • function set_curdoc 60.2% similar

    A context manager that temporarily sets the current Bokeh document (curdoc) in the application state, ensuring it is properly cleaned up after use.

    From: /tf/active/vicechatdev/patches/server.py
  • function _eval_panel 59.5% similar

    Evaluates and initializes a panel component (function, template, or panel object) within a Bokeh document context, handling different panel types and modifying the document accordingly.

    From: /tf/active/vicechatdev/patches/server.py
← Back to Browse