Skip to content

Commit 22fa24f

Browse files
committed
update extending docs
1 parent 8b070b7 commit 22fa24f

File tree

9 files changed

+299
-511
lines changed

9 files changed

+299
-511
lines changed
Lines changed: 297 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,298 @@
1+
=========================
2+
Jupyter Server Extensions
3+
=========================
4+
5+
A Jupyter Server extension is typically a module or package that extends to Server’s REST API/endpoints—i.e. adds extra request handlers to Server’s Tornado Web Application.
6+
17
Authoring a basic server extension
2-
==================================
8+
==================================
9+
10+
The simplest way to write a Jupyter Server extension is to write an extension module with a ``_load_jupyter_server_extension`` function. This function should take a single argument, an instance of the ``ServerApp``.
11+
12+
13+
.. code-block:: python
14+
15+
def _load_jupyter_server_extension(serverapp):
16+
"""
17+
This function is called when the extension is loaded.
18+
"""
19+
pass
20+
21+
22+
Adding extension endpoints
23+
--------------------------
24+
25+
The easiest way to add endpoints and handle incoming requests is to subclass the ``JupyterHandler`` (which itself is a subclass of Tornado's ``RequestHandler``).
26+
27+
.. code-block:: python
28+
29+
from jupyter_server.base.handlers import JupyterHandler
30+
31+
class MyExtensionHandler(JupyterHandler):
32+
33+
def get(self):
34+
...
35+
36+
def post(self):
37+
...
38+
39+
40+
Then add this handler to Jupyter Server's Web Application through the ``_load_jupyter_server_extension`` function.
41+
42+
.. code-block:: python
43+
44+
def _load_jupyter_server_extension(serverapp):
45+
"""
46+
This function is called when the extension is loaded.
47+
"""
48+
handlers = [
49+
('/myextension/hello', MyExtensionHandler)
50+
]
51+
serverapp.web_app.add_handlers('.*$', handlers)
52+
53+
54+
55+
Making an extension discoverable
56+
--------------------------------
57+
58+
To make this extension discoverable to Jupyter Server, there are two steps. First, the extension module must define a ``_jupyter_server_extension_paths()`` function that returns some metadata about the extension entry-points in the module. This informs Jupyter Server what type of extension is being loaded and where to find the ``_load_jupyter_server_extension``.
59+
60+
.. code-block:: python
61+
62+
def _jupyter_server_extension_paths():
63+
"""
64+
Returns a list of dictionaries with metadata describing
65+
where to find the `_load_jupyter_server_extension` function.
66+
"""
67+
return [
68+
{
69+
"module": "my_extension"
70+
}
71+
]
72+
73+
Second, the extension must be listed in the user’s ``jpserver_extensions`` config trait. This can be manually added by users in their ``jupyter_server_config.py`` file:
74+
75+
.. code-block:: python
76+
77+
c.ServerApp.jpserver_extensions = {
78+
"my_extension": True
79+
}
80+
81+
Alternatively, an extension can automatically enable itself by creating the following JSON in the jupyter_server_config.d directory on installation. See XX for more details.
82+
83+
.. code-block:: python
84+
85+
{
86+
"ServerApp": {
87+
"jpserver_extensions": {
88+
"my_extension": true
89+
}
90+
}
91+
}
92+
93+
94+
Authoring a configurable extension application
95+
==============================================
96+
97+
Some extensions are full-fledged client applications that sit on top of the Jupyter Server. For example, `JupyterLab <https://jupyterlab.readthedocs.io/en/stable/>`_ is a server extension. It can be launched from the command line, configured by CLI or config files, and serves+loads static assets behind the server (i.e. html templates, Javascript, etc.)
98+
99+
Jupyter Server offers a convenient base class, ``ExtensionsApp``, that handles most of the boilerplate code for building such extensions.
100+
101+
Anatomy of an ``ExtensionApp``
102+
------------------------------
103+
104+
An ExtensionApp:
105+
106+
- has traits.
107+
- is configurable (from file or CLI)
108+
- has a name (see the ``extension_name`` trait).
109+
- has an entrypoint, ``jupyter <extension_name>``.
110+
- can server static content from the ``/static/<extension_name>/`` endpoint.
111+
- can add new endpoints to the Jupyter Server.
112+
113+
The basic structure of an ExtensionApp is shown below:
114+
115+
.. code-block:: python
116+
117+
from jupyter_server.extension.application import ExtensionApp
118+
119+
120+
class MyExtensionApp(ExtensionApp):
121+
122+
# -------------- Required traits --------------
123+
extension_name = "myextension"
124+
extension_url = "/myextension"
125+
load_other_extensions = True
126+
127+
# --- ExtensionApp traits you can configure ---
128+
static_paths = [...]
129+
template_paths = [...]
130+
settings = {...}
131+
handlers = [...]
132+
133+
# ----------- add custom traits below ---------
134+
...
135+
136+
def initialize_settings(self):
137+
...
138+
# Update the self.settings trait to pass extra
139+
# settings to the underlying Tornado Web Application.
140+
self.settings.update({'<trait>':...})
141+
142+
def initialize_handlers(self):
143+
...
144+
# Extend the self.handlers trait
145+
self.handlers.extend(...)
146+
147+
def initialize_templates(self):
148+
...
149+
# Change the jinja templating environment
150+
151+
152+
The ``ExtensionApp`` uses the following methods and properties to connect your extension to the Jupyter server. You do no need to define a ``_load_jupyter_server_extension`` function for these apps. Instead, overwrite the pieces below to add your custom settings, handlers and templates:
153+
154+
Methods
155+
156+
* ``initialize_setting()``: adds custom settings to the Tornado Web Application.
157+
* ``initialize_handlers()``: appends handlers to the Tornado Web Application.
158+
* ``initialize_templates()``: initialize the templating engine (e.g. jinja2) for your frontend.
159+
160+
Properties
161+
162+
* ``extension_name``: the name of the extension
163+
* ``extension_url``: the default url for this extension—i.e. the landing page for this extension when launched from the CLI.
164+
* ``load_other_extensions``: a boolean enabling/disabling other extensions when launching this extension directly.
165+
166+
``ExtensionApp`` request handlers
167+
---------------------------------
168+
169+
``ExtensionApp`` Request Handlers have a few extra properties.
170+
171+
* ``config``: the ExtensionApp's config object.
172+
* ``server_config``: the ServerApp's config object.
173+
* ``extension_name``: the name of the extension to which this handler is linked.
174+
* ``static_url()``: a method that returns the url to static files (prefixed with ``/static/<extension_name>``).
175+
176+
Jupyter Server provides a convenient mixin class for adding these properties to any ``JupyterHandler``. For example, the basic server extension handler in the section above becomes:
177+
178+
.. code-block:: python
179+
180+
from jupyter_server.base.handlers import JupyterHandler
181+
from jupyter_server.extension.handler import ExtensionHandlerMixin
182+
183+
184+
class MyExtensionHandler(ExtensionHandlerMixin, JupyterHandler):
185+
186+
def get(self):
187+
...
188+
189+
def post(self):
190+
...
191+
192+
193+
Jinja templating from frontend extensions
194+
-----------------------------------------
195+
196+
Many Jupyter frontend applications use Jinja for basic HTML templating. Since this is common enough, Jupyter Server provides some extra mixin that integrate Jinja with Jupyter server extensions.
197+
198+
Use ``ExtensionAppJinjaMixin`` to automatically add a Jinja templating environment to an ``ExtensionApp``. This adds a ``<extension_name>_jinja2_env`` setting to Tornado Web Server's settings that be be used by request handlers.
199+
200+
.. code-block:: python
201+
202+
203+
from jupyter_server.extension.application import ExtensionApp, ExtensionAppJinjaMixin
204+
205+
206+
class MyExtensionApp(ExtensionAppJinjaMixin, ExtensionApp):
207+
...
208+
209+
210+
Pair the example above with ``ExtensionHandlers`` that also inherit the ``ExtensionHandlerJinjaMixin`` mixin. This will automatically load HTML templates from the Jinja templating environment created by the ``ExtensionApp``.
211+
212+
213+
.. code-block:: python
214+
215+
216+
from jupyter_server.base.handlers import JupyterHandler
217+
from jupyter_server.extension.handler import (
218+
ExtensionHandlerMixin,
219+
ExtensionHandlerJinjaMixin
220+
)
221+
222+
class MyExtensionHandler(
223+
ExtensionHandlerMixin,
224+
ExtensionHandlerJinjaMixin,
225+
JupyterHandler
226+
):
227+
228+
def get(self):
229+
...
230+
231+
def post(self):
232+
...
233+
234+
235+
.. note:: The mixin classes in this example must come before the base classes, ``ExtensionApp`` and ``ExtensionHandler``.
236+
237+
238+
Making an ``ExtensionApp`` discoverable
239+
---------------------------------------
240+
241+
To make an ``ExtensionApp`` discoverable by Jupyter Server, add the ``app`` key+value pair to the ``_jupyter_server_extension_paths()`` function example above:
242+
243+
.. code-block:: python
244+
245+
from myextension import MyExtensionApp
246+
247+
248+
def _jupyter_server_extension_paths():
249+
"""
250+
Returns a list of dictionaries with metadata describing
251+
where to find the `_load_jupyter_server_extension` function.
252+
"""
253+
return [
254+
{
255+
"module": "myextension",
256+
"app": MyExtensionApp
257+
}
258+
]
259+
260+
261+
Launching an ``ExtensionApp``
262+
-----------------------------
263+
264+
To launch the application, simply call the ``ExtensionApp``'s ``launch_instance`` method.
265+
266+
.. code-block:: python
267+
268+
launch_instance = MyFrontend.launch_instance
269+
launch_instance()
270+
271+
272+
To make your extension executable from anywhere on your system, point an entry-point at the ``launch_instance`` method in the extension's ``setup.py``:
273+
274+
.. code-block:: python
275+
276+
from setuptools import setup
277+
278+
279+
setup(
280+
name='myfrontend',
281+
...
282+
entry_points={
283+
'console_scripts': [
284+
'jupyter-myextension = myextension:launch_instance'
285+
]
286+
}
287+
)
288+
289+
Distributing a server extension
290+
===============================
291+
292+
293+
294+
Example Server Extension
295+
========================
296+
297+
You can check some simple example on the `GitHub jupyter_server repository
298+
<https://github.com/jupyter/jupyter_server/tree/master/examples/simple>`_.

docs/source/developers/dependency.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ To pin your jupyter_server install to a specific version:
1818

1919
.. code-block:: console
2020
21-
> pip install jupyter_server==1.0
21+
> pip install jupyter_server==1.0

docs/source/developers/index.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,5 @@ These pages target people writing Jupyter Web applications and server extensions
1010

1111
dependency
1212
basic-extension
13-
configurable-extension
1413
rest-api
1514
../other/changelog

0 commit comments

Comments
 (0)