Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NotebookApp shim layer #7

Merged
merged 13 commits into from
Mar 16, 2020
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# nbclassic: Jupyter Notebook Server Extension
# nbclassic: Jupyter Notebook as a Jupyter Server Extension

**A package that provides a simple transition away from Jupyter Notebook to Jupyter Server.**

This library allows you to install both [jupyter/notebook](http://localhost:8888/tree) and a Jupyter Notebook Server Extension side-by-side (and any other Jupyter Server Frontend).
This library allows you to install both [jupyter/notebook](github.com/jupyter/notebook) and a Jupyter Notebook Server Extension side-by-side (and any other Jupyter Server Frontend).

This helps projects like JupyterLab and nteract_on_jupyter transition from jupyter/notebook to jupyter/jupyter_server for the core Jupyter Tornado Server.

Expand All @@ -17,7 +15,7 @@ Launch with Jupyter Server:
```
jupyter server
```
or directly with
or directly with
```
jupyter nbclassic
```
Expand Down
43 changes: 43 additions & 0 deletions docs/shimming.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

**A story about configuration**

## Trait path

Steps to handling traits during a "Transition and Deprecation Period".

1. If the argument is prefixed with `ServerApp`, pass this trait to `ServerApp`.
Expand All @@ -24,3 +26,44 @@ Steps to handling traits during a "Transition and Deprecation Period".
2. Migrate/write the trait to a new config file if it came from a config file.
2. Pass trait to Step 2 above.
- If the argument is *not* a trait of `ExtensionApp` and not a trait of either `NotebookApp` or `ServerApp`, raise a `"Trait not found."` error.



## How JupyterApp's Parse Config.

**Valid for traitlets 4.3.x**

Here's a snapshot of how JupyterApp's are initialized. The order of operations we care about goes as follows:

1. `argv` is parsed.
2. `parse_command_line()` is called and `argv` is passed to this method.
3. `load_config_file()` is called to load traits from various files.

```python
# Pulled from Traitlets 4.3.2

@catch_config_error
def initialize(self, argv=None):
# don't hook up crash handler before parsing command-line
if argv is None:
argv = sys.argv[1:]
if argv:
subc = self._find_subcommand(argv[0])
if subc:
self.argv = argv
self.subcommand = subc
return
self.parse_command_line(argv)
cl_config = deepcopy(self.config)
if self._dispatching:
return
self.migrate_config()
self.load_config_file()
# enforce cl-opts override configfile opts:
self.update_config(cl_config)
if allow_insecure_writes:
issue_insecure_write_warning()
```

## Where do we add the steps above?

8 changes: 4 additions & 4 deletions nbclassic/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from .notebookapp import NotebookApp

EXTENSION_NAME = "notebook_shim"

def _jupyter_server_extension_paths():
return [{"module": EXTENSION_NAME}]

load_jupyter_server_extension = NotebookApp.load_jupyter_server_extension
return [{
'module': 'nbclassic.notebookapp',
'app': NotebookApp
}]
5 changes: 3 additions & 2 deletions nbclassic/notebook/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
from tornado import web, gen
HTTPError = web.HTTPError

from jupyter_server.base.handlers import JupyterHandler
from jupyter_server.extension.handler import (
ExtensionHandler,
ExtensionHandlerMixin,
ExtensionHandlerJinjaMixin
)
from jupyter_server.base.handlers import path_regex, FilesRedirectHandler
Expand Down Expand Up @@ -75,7 +76,7 @@ def get_frontend_exporters():
return sorted(frontend_exporters)


class NotebookHandler(ExtensionHandlerJinjaMixin, ExtensionHandler):
class NotebookHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler):


@web.authenticated
Expand Down
164 changes: 27 additions & 137 deletions nbclassic/notebookapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
random_ports,
load_handlers
)
from .shimconfig import merge_notebook_configs

#-----------------------------------------------------------------------------
# Module globals
Expand Down Expand Up @@ -93,20 +92,28 @@
'ip': 'ServerApp.ip',
'port': 'ServerApp.port',
'port-retries': 'ServerApp.port_retries',
'transport': 'KernelManager.transport',
'transport': 'ServerApp.KernelManager.transport',
'keyfile': 'ServerApp.keyfile',
'certfile': 'ServerApp.certfile',
'client-ca': 'ServerApp.client_ca',
'notebook-dir': 'ServerApp.notebook_dir',
'browser': 'ServerApp.browser',
'gateway-url': 'GatewayClient.url',
'gateway-url': 'ServerApp.GatewayClient.url',
})

#-----------------------------------------------------------------------------
# NotebookApp
#-----------------------------------------------------------------------------

class NotebookApp(ExtensionAppJinjaMixin, ExtensionApp):
from . import shim
from . import traits

class NotebookApp(
shim.NBClassicConfigShimMixin,
traits.NotebookAppTraits,
ExtensionAppJinjaMixin,
ExtensionApp
):

name = 'jupyter-nbclassic'
version = __version__
Expand All @@ -115,66 +122,8 @@ class NotebookApp(ExtensionAppJinjaMixin, ExtensionApp):
This launches a Tornado based HTML Notebook Server that serves up an HTML5/Javascript Notebook client.""")

extension_name = 'nbclassic'

ignore_minified_js = Bool(False,
config=True,
help=_('Deprecated: Use minified JS file or not, mainly use during dev to avoid JS recompilation'),
)

max_body_size = Integer(512 * 1024 * 1024, config=True,
help="""
Sets the maximum allowed size of the client request body, specified in
the Content-Length request header field. If the size in a request
exceeds the configured value, a malformed HTTP message is returned to
the client.

Note: max_body_size is applied even in streaming mode.
"""
)

max_buffer_size = Integer(512 * 1024 * 1024, config=True,
help="""
Gets or sets the maximum amount of memory, in bytes, that is allocated
for use by the buffer manager.
"""
)

jinja_environment_options = Dict(config=True,
help=_("Supply extra arguments that will be passed to Jinja environment."))

jinja_template_vars = Dict(
config=True,
help=_("Extra variables to supply to jinja templates when rendering."),
)

enable_mathjax = Bool(True, config=True,
help="""Whether to enable MathJax for typesetting math/TeX

MathJax is the javascript library Jupyter uses to render math/LaTeX. It is
very large, so you may want to disable it if you have a slow internet
connection, or for offline use of the notebook.

When disabled, equations etc. will appear as their untransformed TeX source.
"""
)

@observe('enable_mathjax')
def _update_enable_mathjax(self, change):
"""set mathjax url to empty if mathjax is disabled"""
if not change['new']:
self.mathjax_url = u''

extra_static_paths = List(Unicode(), config=True,
help="""Extra paths to search for serving static files.

This allows adding javascript/css to be available from the notebook server machine,
or overriding individual files in the IPython"""
)

@property
def static_file_path(self):
"""return extra paths + the default location"""
return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
aliases = aliases
flags = flags

static_custom_path = List(Unicode(),
help=_("""Path to search for custom.js, css""")
Expand All @@ -188,25 +137,10 @@ def _default_static_custom_path(self):
DEFAULT_STATIC_FILES_PATH)
]

extra_template_paths = List(Unicode(), config=True,
help=_("""Extra paths to search for serving jinja templates.

Can be used to override templates from notebook.templates.""")
)

@property
def template_file_path(self):
"""return extra paths + the default locations"""
return self.extra_template_paths + DEFAULT_TEMPLATE_PATH_LIST

extra_nbextensions_path = List(Unicode(), config=True,
help=_("""extra paths to look for Javascript notebook extensions""")
)

extra_services = List(Unicode(), config=True,
help=_("""handlers that should be loaded at higher priority than the default services""")
)

@property
def nbextensions_path(self):
"""The path to look for Javascript notebook extensions"""
Expand All @@ -220,53 +154,6 @@ def nbextensions_path(self):
path.append(os.path.join(get_ipython_dir(), 'nbextensions'))
return path

mathjax_url = Unicode("", config=True,
help="""A custom url for MathJax.js.
Should be in the form of a case-sensitive url to MathJax,
for example: /static/components/MathJax/MathJax.js
"""
)

@property
def static_url_prefix(self):
"""Get the static url prefix for serving static files."""
return super(NotebookApp, self).static_url_prefix

@default('mathjax_url')
def _default_mathjax_url(self):
if not self.enable_mathjax:
return u''
static_url_prefix = self.static_url_prefix
return url_path_join(static_url_prefix, 'components', 'MathJax', 'MathJax.js')

@observe('mathjax_url')
def _update_mathjax_url(self, change):
new = change['new']
if new and not self.enable_mathjax:
# enable_mathjax=False overrides mathjax_url
self.mathjax_url = u''
else:
self.log.info(_("Using MathJax: %s"), new)

mathjax_config = Unicode("TeX-AMS-MML_HTMLorMML-full,Safe", config=True,
help=_("""The MathJax.js configuration file that is to be used.""")
)

@observe('mathjax_config')
def _update_mathjax_config(self, change):
self.log.info(_("Using MathJax configuration file: %s"), change['new'])

quit_button = Bool(True, config=True,
help="""If True, display a button in the dashboard to quit
(shutdown the notebook server)."""
)

# ------------------------------------------------------------------------
# traits and methods for Jupyter Server
# ------------------------------------------------------------------------

default_url = Unicode("/tree", config=True)

@property
def static_paths(self):
"""Rename trait in jupyter_server."""
Expand All @@ -277,8 +164,8 @@ def template_paths(self):
"""Rename trait for Jupyter Server."""
return self.template_file_path

def initialize_templates(self):
super(NotebookApp, self).initialize_templates()
def _prepare_templates(self):
super(NotebookApp, self)._prepare_templates()

# Get translations from notebook package.
base_dir = os.path.dirname(notebook.__file__)
Expand All @@ -294,21 +181,25 @@ def initialize_settings(self):
warnings.warn(_("The `ignore_minified_js` flag is deprecated and will be removed in Notebook 6.0"), DeprecationWarning)

settings = dict(
static_custom_path=self.static_custom_path,
static_handler_args = {
# don't cache custom.js
'no_cache_paths': [
url_path_join(
self.serverapp.base_url,
'static',
self.extension_name,
'custom'
)
],
},
ignore_minified_js=self.ignore_minified_js,
mathjax_url=self.mathjax_url,
mathjax_config=self.mathjax_config,
nbextensions_path=self.nbextensions_path,
)
self.settings.update(**settings)

merged_config = merge_notebook_configs(
notebook_config_name = 'jupyter_notebook',
server_config_name = 'jupyter_server',
other_config_name = 'jupyter_nbclassic',
argv = sys.argv
)
self.settings['ServerApp'] = merged_config['ServerApp']

def initialize_handlers(self):
"""Load the (URL pattern, handler) tuples for each component."""
# Order matters. The first handler to match the URL will handle the request.
Expand Down Expand Up @@ -336,7 +227,6 @@ def initialize_handlers(self):
# Add new handlers to Jupyter server handlers.
self.handlers.extend(handlers)


#-----------------------------------------------------------------------------
# Main entry point
#-----------------------------------------------------------------------------
Expand Down
Loading