Skip to content

Improving 4.x nbextensions #878

Closed
Closed
@ellisonbg

Description

@ellisonbg

@fperez @damianavila @bollwyvl @sccolbert teoliphant @minrk @takluyver @ijstokes

I have been having a lot of on- and off-line discussion this week about the current state of nbextensions in 4.x. For a long time, we (at least this was my own logic) have hesitated to make any significant changes to how 4.x nbextensions are installed/loaded/packaged, because we know that much bigger changes are on the way in 5.0. After these recent conversations, I am convinced that we need to improve the existing 4.x nbextension architecture in the meantime. The current situation in 4.x is causing way to many problems for users and devs.

This goal of this issue is to 1) raise our community awareness that we need to do something about this and 2) come up with a concrete proposal for moving forward.

Current pain points of 4.x nbextensions

nbextensions can be installed in the following locations:

In [2]: paths.jupyter_path('nbextensions')
Out[2]: 
['/Users/bgranger/Library/Jupyter/nbextensions',
 '/Users/bgranger/anaconda/envs/python34/share/jupyter/nbextensions',
 '/usr/local/share/jupyter/nbextensions',
 '/usr/share/jupyter/nbextensions']

Config can be loaded from the following locations:

In [4]: paths.jupyter_config_path()
Out[4]: 
['/Users/bgranger/.jupyter',
 '/Users/bgranger/anaconda/envs/python34/etc/jupyter',
 '/usr/local/etc/jupyter',
 '/etc/jupyter']

By default, installed extensions are not loaded, until activated. The only place extensions can be activated is in the users config directory (~/.jupyter/nbconfig/notebook|notebook.json):

In [13]: cat /Users/bgranger/.jupyter/nbconfig/notebook.json
{
  "load_extensions": {
    "widgets/notebook/js/extension": true,
    "create_assignment/main": true,
    "nbgrader/create_assignment": true
  }
}

Pain Point #1: even though nbextensions and config can be installed in system, sys.prefix or user paths, the list of extensions to activate is only loaded from the user config. Thus, there is no way of activating nbextensions at the system or sys.prefix level.

  • Example 1a: Because of this a JupyterHub deployment can't enable the various nbgrader extensions at the system level - each user has to do it.
  • Example 1b: Continuum can't enable extensions on a conda env basis, even though they can install them there.

Point Point #2: There is no standard package format for nbextensions (other than a directory of stuff) and no standard way of copying an nbextension into place. Because of this, there are multiple, separate hacky ways of packaging and installing nbextensions.

  • Example 2a: nbgrader has created custom subcommands, such as nbgrader extension install and nbgrader extensions activate.
  • Example 2b: Continuum is starting a couple of new projects to try to solve these issues in the conda context.
  • Example 2c: We ourselves, just gave up and hardcoded the ipywidgets nbextensionss in the frontend code.
  • Example 2d: Projects like https://github.com/takluyver/cite2c have a separate install.py script that installs and activate its extension.
  • Example 2e: @minrk recommends just using ls -n to "install" his nbextensions here: https://github.com/minrk/ipython_extensions

Proposal for addressing these pain points.

Here is the overall approach:

  • Solve the above pain points in a full backwards compatible manner.
  • Release the fixes quickly in a 4.2 release.
  • In 5.x on the exiting pages we have (notebook/tree): formally deprecate the 4.x approach to loading/installing nbextensions, our existing JS APIs and CSS classes.
  • In 5.x on the new JupyterLab page: only use new APIs and the new npm based plugin approach.

Here are the technical details of the proposal:

Pain Point 1

@takluyver has made an excellent point that the "nbconfig" frontend configuration system deliberately only loads from the users config (~/.jupyter) because these are really mean to only be "user preferences". I completely agree with this and others I have spoken to also concur. So we can't make that part of our app start to load system or sys.prefix based config.

I propose to start to load nbextension activation config from all config paths (system, sys.prefix and user) always, but do that instead by throwing that data into the page.html template itself, rather than loading later using the nbconfig web service. This would allow us to keep system data out of the user level app-preferences but still load config for nbextensions from all locations. This is not difficult to implement and is fully backwards compatible.

Pain Point 2

This one is more difficult and my proposal will be more controversial. Today, in many cases, people are shipping JS code in Python packages. For 5.0 we are going to stop doing that and embrace npm as our package format and manager, but that would require breaking changes in 4.x, so is not on the table.

I propose, that for 4.2+ we embrace putting nbextensions into Python packages:

  • Don't standardize specifically where in the python package they are. This allows existing packages such as nbgrader to not have to change anything.
  • Instead, 1) provide metadata in setup.py that gives the package relative paths of those assets and 2) provide that same metadata in __init__.py to enable runtime inspection. Something like this:
>>> import nbgrader
>>> nbgrader._jupyter_nbextension_paths
['nbextensions/assignment_list', 'nbextensions/create_assigment']
  • Using this simple convention, we could then improve the existing jupyter nbextension command line tool to work with python packages: jupyter nbextension install nbgrader and jupyter nbextension enable nbgrader. We could also include flags the target installation/config to the system, sys.prefix and user directories. This would again be fully backwards compatible.
  • Using this simple convension, Continuum can build conda installers for nbextensions with almost no effort.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions