File: handlers.rst

package info (click to toggle)
jupyter-notebook 6.4.13-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 13,860 kB
  • sloc: javascript: 20,765; python: 15,658; makefile: 255; sh: 160
file content (174 lines) | stat: -rw-r--r-- 5,975 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
Custom request handlers
=======================

The notebook webserver can be interacted with using a well `defined
RESTful
API <http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml>`__.
You can define custom RESTful API handlers in addition to the ones
provided by the notebook. As described below, to define a custom handler
you need to first write a notebook server extension. Then, in the
extension, you can register the custom handler.

Writing a notebook server extension
-----------------------------------

The notebook webserver is written in Python, hence your server extension
should be written in Python too. Server extensions, like IPython
extensions, are Python modules that define a specially named load
function, ``load_jupyter_server_extension``. This function is called
when the extension is loaded.

.. code:: python

    def load_jupyter_server_extension(nb_server_app):
        """
        Called when the extension is loaded.

        Args:
            nb_server_app (NotebookWebApplication): handle to the Notebook webserver instance.
        """
        pass

To get the notebook server to load your custom extension, you'll need to
add it to the list of extensions to be loaded. You can do this using the
config system. ``NotebookApp.nbserver_extensions`` is a config variable
which is a dictionary of strings, each a Python module to be imported, mapping
to ``True`` to enable or ``False`` to disable each extension.
Because this variable is notebook config, you can set it two different
ways, using config files or via the command line.

For example, to get your extension to load via the command line add a
double dash before the variable name, and put the Python dictionary in
double quotes. If your package is "mypackage" and module is
"mymodule", this would look like
``jupyter notebook --NotebookApp.nbserver_extensions="{'mypackage.mymodule':True}"``
.
Basically the string should be Python importable.

Alternatively, you can have your extension loaded regardless of the
command line args by setting the variable in the Jupyter config file.
The default location of the Jupyter config file is
``~/.jupyter/jupyter_notebook_config.py`` (see :doc:`/config_overview`). Inside
the config file, you can use Python to set the variable. For example,
the following config does the same as the previous command line example.

.. code:: python

    c = get_config()
    c.NotebookApp.nbserver_extensions = {
        'mypackage.mymodule': True,
    }

Before continuing, it's a good idea to verify that your extension is
being loaded. Use a print statement to print something unique. Launch
the notebook server and you should see your statement printed to the
console.

Registering custom handlers
---------------------------

Once you've defined a server extension, you can register custom handlers
because you have a handle to the Notebook server app instance
(``nb_server_app`` above). However, you first need to define your custom
handler. To declare a custom handler, inherit from
``notebook.base.handlers.IPythonHandler``. The example below[1] is a
Hello World handler:

.. code:: python

    from notebook.base.handlers import IPythonHandler

    class HelloWorldHandler(IPythonHandler):
        def get(self):
            self.finish('Hello, world!')

The Jupyter Notebook server use
`Tornado <http://www.tornadoweb.org/en/stable/>`__ as its web framework.
For more information on how to implement request handlers, refer to the
`Tornado documentation on the
matter <http://www.tornadoweb.org/en/stable/web.html#request-handlers>`__.

After defining the handler, you need to register the handler with the
Notebook server. See the following example:

.. code:: python

    web_app = nb_server_app.web_app
    host_pattern = '.*$'
    route_pattern = url_path_join(web_app.settings['base_url'], '/hello')
    web_app.add_handlers(host_pattern, [(route_pattern, HelloWorldHandler)])

Putting this together with the extension code, the example looks like the
following:

.. code:: python

    from notebook.utils import url_path_join
    from notebook.base.handlers import IPythonHandler

    class HelloWorldHandler(IPythonHandler):
        def get(self):
            self.finish('Hello, world!')

    def load_jupyter_server_extension(nb_server_app):
        """
        Called when the extension is loaded.

        Args:
            nb_server_app (NotebookWebApplication): handle to the Notebook webserver instance.
        """
        web_app = nb_server_app.web_app
        host_pattern = '.*$'
        route_pattern = url_path_join(web_app.settings['base_url'], '/hello')
        web_app.add_handlers(host_pattern, [(route_pattern, HelloWorldHandler)])


Extra Parameters and authentication
===================================

Here is a quick rundown of what you need to know to pass extra parameters to the handler and enable authentication:

 - extra arguments to the ``__init__`` constructor are given in a dictionary after the  handler class in ``add_handlers``:

.. code:: python


    class HelloWorldHandler(IPythonHandler):

        def __init__(self, *args, **kwargs):
            self.extra = kwargs.pop('extra')
            ...

    def load_jupyter_server_extension(nb_server_app):

        ...

        web_app.add_handlers(host_pattern,
            [
               (route_pattern, HelloWorldHandler, {"extra": nb_server_app.extra})
            ])


All handler methods that require authentication _MUST_ be decorated with ``@tornado.web.authenticated``:


.. code:: python

    from tornado import web

    class HelloWorldHandler(IPythonHandler):

        ...

        @web.authenticated
        def  get(self, *args, **kwargs):
             ...

        @web.authenticated
        def  post(self, *args, **kwargs):
             ...


References:

1. `Peter Parente's Mindtrove <https://mindtrove.info/4-ways-to-extend-jupyter-notebook/#nb-server-exts>`__