holoviz / panel
1 0
from urllib.parse import urljoin
2

3 0
import tornado
4

5 0
from bokeh.command.util import build_single_handler_application
6 0
from bokeh.embed.bundle import extension_dirs
7 0
from bokeh.embed.server import server_html_page_for_session
8 0
from bokeh.protocol import Protocol
9 0
from bokeh.protocol.exceptions import ProtocolError
10 0
from bokeh.protocol.receiver import Receiver
11 0
from bokeh.server.connection import ServerConnection
12 0
from bokeh.server.contexts import ApplicationContext
13 0
from bokeh.server.protocol_handler import ProtocolHandler
14 0
from bokeh.server.views.doc_handler import DocHandler
15 0
from bokeh.server.views.multi_root_static_handler import MultiRootStaticHandler
16 0
from bokeh.server.views.static_handler import StaticHandler
17 0
from bokeh.server.views.ws import WSHandler
18 0
from bokeh.server.auth_provider import NullAuth
19 0
from bokeh.util.token import get_session_id
20 0
from tornado.web import StaticFileHandler
21

22 0
from ..config import config
23 0
from ..util import edit_readonly
24 0
from .state import state
25 0
from .resources import DIST_DIR, Resources
26

27 0
_RESOURCES = None
28

29 0
_APPS = {
30

31
}
32

33

34 0
class ServerApplicationProxy:
35
    """
36
    A wrapper around the jupyter_server.serverapp.ServerWebApplication
37
    to make it compatible with the expected BokehTornado application
38
    API.
39
    """
40

41 0
    auth_provider = NullAuth()
42 0
    generate_session_ids = True
43 0
    sign_sessions = False
44 0
    include_headers = None
45 0
    include_cookies = None
46 0
    exclude_headers = None
47 0
    exclude_cookies = None
48 0
    session_token_expiration = 300
49 0
    secret_key = None
50 0
    websocket_origins = '*'
51

52 0
    def __init__(self, app, **kw):
53 0
        self._app = app
54

55 0
    def __getattr__(self, key):
56 0
        return getattr(self._app, key)
57

58

59 0
class PanelHandler(DocHandler):
60

61 0
    def __init__(self, app, request, *args, **kw):
62 0
        kw['application_context'] = None
63 0
        kw['bokeh_websocket_path'] = None
64 0
        proxy = ServerApplicationProxy(app)
65 0
        super().__init__(proxy, request, *args, **kw)
66

67 0
    def initialize(self, *args, **kws):
68 0
        pass
69

70 0
    async def get(self, path, *args, **kwargs):
71 0
        if path in _APPS:
72 0
            app, context = _APPS[path]
73
        else:
74 0
            if path.endswith('yml') or path.endswith('.yaml'):
75 0
                from lumen.config import config
76 0
                from lumen.command import build_single_handler_application as build_lumen
77 0
                config.dev = True
78 0
                app = build_lumen(path, argv=None)
79
            else:
80 0
                app = build_single_handler_application(path)
81 0
            context = ApplicationContext(app, url=path)
82 0
            context._loop = tornado.ioloop.IOLoop.current()
83 0
            _APPS[path] = (app, context)
84

85 0
        self.application_context = context
86

87 0
        session = await self.get_session()
88

89 0
        page = server_html_page_for_session(
90
            session,
91
            resources=RESOURCES,
92
            title=session.document.title,
93
            template=session.document.template,
94
            template_variables=session.document.template_variables
95
        )
96

97 0
        self.set_header("Content-Type", 'text/html')
98 0
        self.write(page)
99

100

101 0
class PanelWSHandler(WSHandler):
102

103 0
    def __init__(self, app, request, *args, **kw):
104 0
        kw['application_context'] = None
105 0
        proxy = ServerApplicationProxy(app)
106 0
        super().__init__(proxy, request, *args, **kw)
107

108 0
    def initialize(self, *args, **kwargs):
109 0
        pass
110

111 0
    async def open(self, path, *args, **kwargs):
112 0
        _, context = _APPS[path]
113

114 0
        token = self._token
115 0
        if self.selected_subprotocol != 'bokeh':
116 0
            self.close()
117 0
            raise ProtocolError("Subprotocol header is not 'bokeh'")
118 0
        elif token is None:
119 0
            self.close()
120 0
            raise ProtocolError("No token received in subprotocol header")
121

122 0
        session_id = get_session_id(token)
123

124 0
        await context.create_session_if_needed(session_id, self.request, token)
125 0
        session = context.get_session(session_id)
126

127 0
        try:
128 0
            protocol = Protocol()
129 0
            self.receiver = Receiver(protocol)
130 0
            self.handler = ProtocolHandler()
131 0
            self.connection = self.new_connection(protocol, context, session)
132 0
        except ProtocolError as e:
133 0
            self.close()
134 0
            raise e
135

136 0
        msg = self.connection.protocol.create('ACK')
137 0
        await self.send_message(msg)
138

139 0
    def new_connection(self, protocol, application_context, session):
140 0
        connection = ServerConnection(protocol, self, application_context, session)
141 0
        return connection
142

143 0
    def on_close(self):
144 0
        if self.connection is not None:
145 0
            self.connection.detach_session()
146

147

148 0
def _load_jupyter_server_extension(notebook_app):
149
    global RESOURCES
150

151 0
    base_url = notebook_app.web_app.settings["base_url"]
152

153
    # Configure Panel
154 0
    RESOURCES = Resources(
155
        mode="server", root_url=urljoin(base_url, 'panel-preview'),
156
        path_versioner=StaticHandler.append_version
157
    )
158 0
    config.autoreload = True
159 0
    with edit_readonly(state):
160 0
        state.base_url = '/panel-preview/'
161 0
        state.rel_path = '/panel-preview'
162

163
    # Set up handlers
164 0
    notebook_app.web_app.add_handlers(
165
        host_pattern=r".*$",
166
        host_handlers=[
167
            (urljoin(base_url, r"panel-preview/static/extensions/(.*)"),
168
             MultiRootStaticHandler, dict(root=extension_dirs)),
169
            (urljoin(base_url, r"panel-preview/static/(.*)"),
170
             StaticHandler),
171
            (urljoin(base_url, r"panel-preview/render/(.*)/ws"),
172
             PanelWSHandler),
173
            (urljoin(base_url, r"panel-preview/render/(.*)"),
174
             PanelHandler, {}),
175
            (urljoin(base_url, r"panel_dist/(.*)"),
176
             StaticFileHandler, dict(path=DIST_DIR))
177
        ]
178
    )
179

180

181
# compat for older versions of Jupyter
182 0
load_jupyter_server_extension = _load_jupyter_server_extension

Read our documentation on viewing source code .

Loading