🔍 Code Extractor

function get_server

Maturity: 70

Creates and configures a Bokeh Server instance to serve Panel applications with support for OAuth authentication, static file serving, and session management.

File:
/tf/active/vicechatdev/patches/server.py
Lines:
574 - 757
Complexity:
complex

Purpose

This function is the primary entry point for deploying Panel applications as web servers. It handles the complete server setup including application routing, OAuth configuration, websocket origins, static file directories, and optional auto-start/show functionality. It supports serving single Panel objects, functions that return Panel objects, or multiple applications mapped to different URL slugs. The function also integrates with Flask applications and can serve Python/Jupyter notebook files directly.

Source Code

def get_server(panel, port=0, address=None, websocket_origin=None,
               loop=None, show=False, start=False, title=None,
               verbose=False, location=True, static_dirs={},
               oauth_provider=None, oauth_key=None, oauth_secret=None,
               oauth_extra_params={}, cookie_secret=None,
               oauth_encryption_key=None, session_history=None, **kwargs):
    """
    Returns a Server instance with this panel attached as the root
    app.

    Arguments
    ---------
    panel: Viewable, function or {str: Viewable}
      A Panel object, a function returning a Panel object or a
      dictionary mapping from the URL slug to either.
    port: int (optional, default=0)
      Allows specifying a specific port
    address : str
      The address the server should listen on for HTTP requests.
    websocket_origin: str or list(str) (optional)
      A list of hosts that can connect to the websocket.

      This is typically required when embedding a server app in
      an external web site.

      If None, "localhost" is used.
    loop : tornado.ioloop.IOLoop (optional, default=IOLoop.current())
      The tornado IOLoop to run the Server on.
    show : boolean (optional, default=False)
      Whether to open the server in a new browser tab on start.
    start : boolean(optional, default=False)
      Whether to start the Server.
    title : str or {str: str} (optional, default=None)
      An HTML title for the application or a dictionary mapping
      from the URL slug to a customized title.
    verbose: boolean (optional, default=False)
      Whether to report the address and port.
    location : boolean or panel.io.location.Location
      Whether to create a Location component to observe and
      set the URL location.
    static_dirs: dict (optional, default={})
      A dictionary of routes and local paths to serve as static file
      directories on those routes.
    oauth_provider: str
      One of the available OAuth providers
    oauth_key: str (optional, default=None)
      The public OAuth identifier
    oauth_secret: str (optional, default=None)
      The client secret for the OAuth provider
    oauth_extra_params: dict (optional, default={})
      Additional information for the OAuth provider
    cookie_secret: str (optional, default=None)
      A random secret string to sign cookies (required for OAuth)
    oauth_encryption_key: str (optional, default=False)
      A random encryption key used for encrypting OAuth user
      information and access tokens.
    session_history: int (optional, default=None)
      The amount of session history to accumulate. If set to non-zero
      and non-None value will launch a REST endpoint at
      /rest/session_info, which returns information about the session
      history.
    kwargs: dict
      Additional keyword arguments to pass to Server instance.

    Returns
    -------
    server : bokeh.server.server.Server
      Bokeh Server instance running this panel
    """
    from ..config import config
    from .rest import REST_PROVIDERS

    server_id = kwargs.pop('server_id', uuid.uuid4().hex)
    kwargs['extra_patterns'] = extra_patterns = kwargs.get('extra_patterns', [])
    if isinstance(panel, dict):
        apps = {}
        for slug, app in panel.items():
            if isinstance(title, dict):
                try:
                    title_ = title[slug]
                except KeyError:
                    raise KeyError(
                        "Keys of the title dictionnary and of the apps "
                        f"dictionary must match. No {slug} key found in the "
                        "title dictionary.")
            else:
                title_ = title
            slug = slug if slug.startswith('/') else '/'+slug
            if 'flask' in sys.modules:
                from flask import Flask
                if isinstance(app, Flask):
                    wsgi = WSGIContainer(app)
                    if slug == '/':
                        raise ValueError('Flask apps must be served on a subpath.')
                    if not slug.endswith('/'):
                        slug += '/'
                    extra_patterns.append(('^'+slug+'.*', ProxyFallbackHandler,
                                           dict(fallback=wsgi, proxy=slug)))
                    continue
            if isinstance(app, pathlib.Path):
                app = str(app) # enables serving apps from Paths
            if (isinstance(app, str) and (app.endswith(".py") or app.endswith(".ipynb"))
                and os.path.isfile(app)):
                apps[slug] = build_single_handler_application(app)
            else:
                handler = FunctionHandler(partial(_eval_panel, app, server_id, title_, location))
                apps[slug] = Application(handler)
    else:
        handler = FunctionHandler(partial(_eval_panel, panel, server_id, title, location))
        apps = {'/': Application(handler)}

    extra_patterns += get_static_routes(static_dirs)

    if session_history is not None:
        config.session_history = session_history
    if config.session_history != 0:
        pattern = REST_PROVIDERS['param']([], 'rest')
        extra_patterns.extend(pattern)
        state.publish('session_info', state, ['session_info'])

    opts = dict(kwargs)
    if loop:
        loop.make_current()
        opts['io_loop'] = loop
    elif opts.get('num_procs', 1) == 1:
        opts['io_loop'] = IOLoop.current()

    if 'index' not in opts:
        opts['index'] = INDEX_HTML

    if address is not None:
        opts['address'] = address

    if websocket_origin:
        if not isinstance(websocket_origin, list):
            websocket_origin = [websocket_origin]
        opts['allow_websocket_origin'] = websocket_origin

    # Configure OAuth
    from ..config import config
    if config.oauth_provider:
        from ..auth import OAuthProvider
        opts['auth_provider'] = OAuthProvider()
    if oauth_provider:
        config.oauth_provider = oauth_provider
    if oauth_key:
        config.oauth_key = oauth_key
    if oauth_extra_params:
        config.oauth_extra_params = oauth_extra_params
    if cookie_secret:
        config.cookie_secret = cookie_secret
    opts['cookie_secret'] = config.cookie_secret

    server = Server(apps, port=port, **opts)
    if verbose:
        address = server.address or 'localhost'
        url = f"http://{address}:{server.port}{server.prefix}"
        print(f"Launching server at {url}")

    state._servers[server_id] = (server, panel, [])

    if show:
        def show_callback():
            server.show('/login' if config.oauth_provider else '/')
        server.io_loop.add_callback(show_callback)

    def sig_exit(*args, **kwargs):
        server.io_loop.add_callback_from_signal(do_stop)

    def do_stop(*args, **kwargs):
        server.io_loop.stop()

    try:
        signal.signal(signal.SIGINT, sig_exit)
    except ValueError:
        pass # Can't use signal on a thread

    if start:
        server.start()
        try:
            server.io_loop.start()
        except RuntimeError:
            pass
    return server

Parameters

Name Type Default Kind
panel - - positional_or_keyword
port - 0 positional_or_keyword
address - None positional_or_keyword
websocket_origin - None positional_or_keyword
loop - None positional_or_keyword
show - False positional_or_keyword
start - False positional_or_keyword
title - None positional_or_keyword
verbose - False positional_or_keyword
location - True positional_or_keyword
static_dirs - {} positional_or_keyword
oauth_provider - None positional_or_keyword
oauth_key - None positional_or_keyword
oauth_secret - None positional_or_keyword
oauth_extra_params - {} positional_or_keyword
cookie_secret - None positional_or_keyword
oauth_encryption_key - None positional_or_keyword
session_history - None positional_or_keyword
**kwargs - - var_keyword

Parameter Details

panel: The Panel application to serve. Can be a Viewable object, a function returning a Viewable, a dictionary mapping URL slugs to Viewables/functions, a Flask app, or a path to a .py/.ipynb file.

port: TCP port number for the server to listen on. Default 0 means the OS will assign an available port automatically.

address: Network address/hostname for the server to bind to (e.g., 'localhost', '0.0.0.0'). None uses Bokeh's default.

websocket_origin: Allowed origins for websocket connections. Required when embedding the app in external sites. Can be a string or list of strings. None defaults to 'localhost'.

loop: Tornado IOLoop instance to run the server on. If None, uses IOLoop.current().

show: If True, automatically opens the server URL in a new browser tab when started.

start: If True, starts the server immediately and blocks until stopped. If False, returns the server instance without starting.

title: HTML page title. Can be a string for single apps or a dictionary mapping URL slugs to titles for multi-app setups.

verbose: If True, prints the server address and port to console when launching.

location: Whether to create a Location component for URL observation and manipulation. Can be boolean or a Location instance.

static_dirs: Dictionary mapping URL routes to local filesystem paths for serving static files (e.g., {'/static': '/path/to/files'}).

oauth_provider: Name of OAuth provider to use for authentication (e.g., 'github', 'google', 'azure').

oauth_key: OAuth client ID/public identifier from the OAuth provider.

oauth_secret: OAuth client secret from the OAuth provider. Required for OAuth authentication.

oauth_extra_params: Additional provider-specific OAuth parameters as a dictionary.

cookie_secret: Secret string for signing secure cookies. Required when using OAuth. Should be a random, hard-to-guess string.

oauth_encryption_key: Encryption key for securing OAuth tokens and user information. Should be a random string.

session_history: Number of session history entries to track. If non-zero/non-None, enables a REST endpoint at /rest/session_info for session data.

kwargs: Additional keyword arguments passed directly to the Bokeh Server constructor (e.g., 'num_procs', 'index', 'extra_patterns').

Return Value

Returns a bokeh.server.server.Server instance configured with the specified Panel application(s). The server may or may not be started depending on the 'start' parameter. The server object can be used to control the server lifecycle (start, stop) and access server properties (port, address, io_loop).

Dependencies

  • panel
  • bokeh
  • tornado
  • param
  • flask
  • uuid
  • signal
  • pathlib
  • functools
  • sys
  • os

Required Imports

from panel.io.server import get_server

Conditional/Optional Imports

These imports are only needed under specific conditions:

from flask import Flask

Condition: only if serving Flask applications within the panel dictionary

Optional
from tornado.ioloop import IOLoop

Condition: only if providing a custom event loop via the 'loop' parameter

Optional
from panel.auth import OAuthProvider

Condition: only if using OAuth authentication (oauth_provider parameter)

Optional

Usage Example

import panel as pn
from panel.io.server import get_server

# Simple example with a single Panel object
def create_app():
    return pn.Column(
        pn.pane.Markdown('# My Panel App'),
        pn.widgets.Button(name='Click me')
    )

# Start server on port 5006 and open in browser
server = get_server(
    panel=create_app,
    port=5006,
    show=True,
    start=False,
    title='My Panel Application',
    verbose=True
)

# Multi-app example with different routes
apps = {
    '/': create_app,
    '/dashboard': lambda: pn.pane.Markdown('Dashboard'),
    '/admin': lambda: pn.pane.Markdown('Admin Panel')
}

server = get_server(
    panel=apps,
    port=5007,
    title={'/' : 'Home', '/dashboard': 'Dashboard', '/admin': 'Admin'},
    websocket_origin=['localhost:5007', 'myapp.com'],
    static_dirs={'/static': './static_files'},
    verbose=True
)

# Start the server
server.start()
server.io_loop.start()

Best Practices

  • Always use a secure random string for cookie_secret in production, especially when using OAuth
  • Set websocket_origin when embedding the app in external websites to prevent CORS issues
  • Use verbose=True during development to easily see the server URL
  • For production, set start=False and manage the server lifecycle manually for better control
  • When serving multiple apps, ensure title dictionary keys match the panel dictionary keys
  • Flask apps must be served on a subpath (not '/') and the slug will automatically get a trailing slash
  • Use session_history cautiously as it stores session data in memory
  • Consider using num_procs parameter in kwargs for multi-process deployments
  • The server_id is automatically generated but can be overridden via kwargs for tracking purposes
  • Signal handlers (SIGINT) are registered automatically but may not work in threaded contexts

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function serve 84.3% similar

    Serves one or more Panel objects on a single web server, allowing interactive dashboards and applications to be deployed locally or remotely with configurable networking and threading options.

    From: /tf/active/vicechatdev/patches/server.py
  • function init_doc 53.5% 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
  • class Application 53.1% similar

    A custom Bokeh Application subclass that extends BkApplication to integrate with Panel's state management system, handling session creation callbacks and document initialization with templates.

    From: /tf/active/vicechatdev/patches/server.py
  • function server_html_page_for_session 52.2% similar

    Generates a complete HTML page for a Bokeh server session by bundling resources and rendering document roots with session token.

    From: /tf/active/vicechatdev/patches/server.py
  • function _eval_panel 52.0% 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