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

Jupyter-server #28

Merged
merged 6 commits into from
Mar 1, 2019
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 216 additions & 0 deletions jupyter-server/jupyter-server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Standalone Jupyter server enhancement proposal [active]

## Problem

There are now multiple frontends that talk to the backend services provided by the notebook server: the legacy Notebook, the dashboards, JupyterLab, standalone widgets and more. The configuration of legacy notebook and the backend server are tightly coupled. As a consequence, the other applications are forced to load the legacy notebook to use the backend server.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add nteract into list of services.


## Proposed Enhancement

Decouple the backend server (and its configuration) from the classic notebook frontend. This will require the following steps:

1. Create `jupyter_server` repository
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hasn't this already been done? https://github.com/jupyter/jupyter_server Or will there be a new_jupyter_server repo?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps instead of steps, provide an overview of key functional components that would be stored in a repo together:

  • backend server which handles services
  • base server extensions provided for access to server information and processes
  • services, built upon base extensions, which can inject dependencies
  • REST API and namespacing of static files
  • configuration for server, base server extensions, and services

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each functional component would then be broken out as its own section to better scope discussion, options, reject alternatives etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hasn't this already been done?

👍 Yes, I am referring to the (already created) jupyter_server repo. This repo was created after the original draft of this proposal (~2 years ago). "Create" was a poor choice of words. It's already been created. They point is to explicitly state that jupyter_server is a product of this proposal.

Perhaps instead of steps, provide an overview of key functional components

👍 That sounds like a good idea. I had organized each item in my mind as a chronological set of steps to implementation, but there is not practical hierarchy to the pieces in this proposal. For the most part, they are separate pieces that with separate discussion.

- Fork of `notebook` repository.
- Pure Python package with notebook backend services.
- `notebook` tornado handlers and frontend logic stay in `notebook` repo.
- Deprecated notebook server APIs do not move to `jupyter_server`.
2. New server extensions mechanism.
- server extensions move to `jupyter_server`.
- new base classes to create applications from server extensions.
- nbextensions stay in `notebook`.
- `jupyter_notebook_config.d` folder becomes `jupyter_server_config.d`
- `notebook` becomes a server extension.
3. Services become server extensions
- Services are just serve extensions with dependencies.
- Add dependency injection system.
5. Namespacing static files and REST API urls.
- Each extension serves static files at the `/static/<extension>` url.
-
6. Migrate configuration.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to be the biggest pain point of this move for users and deployers alike. I suggested some stuff below, but I'll try to pull up a more formal plan for how I could see this going remotely smoothly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mpacer.

I think you're absolutely right. This is an early draft still, so there should be many more iterations to improve this JEP.

- Notebook App configuration stays in `jupyter_notebook_config.py`
- Server and services configurations move to `jupyter_server_config.py`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it have to go in jupyter_server_config.py or can we use the general jupyter_config.py?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it have to go in jupyter_server_config.py or can we use the general jupyter_config.py?
We always can so long as it is a standard JupyterApp also respect the jupyter_config.py, so I imagine this one would as well

However, I don't think that's the right problem. I think what we should do is make a change to JupyterApp from jupyter_core that allows us to declare additional configuration file names that should be picked up. Currently you can only address one app at time (or all apps with jupyter_config.py) based on the value of the app's class attribute name.

Additionally, we could make a Configurable class (NotebookAppConfig) that inherits from the NotebookApp and overwrites all of it's webserver capabilities so that we can continue to get access to the existing NotebookApp.nbserver_extension information. But again… that will be meaningless if we can't read in people's jupyter_notebook_config.py, jupyter_notebook_config.json, and jupyter_notebook_config.d/extension.json.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding on -- with Netflix's current deployments we deploy classic, jupyterlab, and nteract -- we want all of them and in many cases want to share config (so that ContentsManagers are the same and additional server extensions are available for APIs, like with bookstore).

Even if I was elsewhere, I'd still want to have a consistent deterministic config setup even with multiple jupyter apps attached to the server.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @rgbkrk and @mpacer for your comments here.

make a change to JupyterApp from jupyter_core that allows us to declare additional configuration file names

@mpacer this is a good idea--add a trait to the JupyterApp for listing configuration files that should get loaded (and in what order of precedence). That would certainly help with avoiding breaking everyone's configuration system in this transition.

I missed jupyter/notebook#4376 when trying to research all the threads around configuration. Sorry about that! I'll need to think about this a bit more for a new draft. (I'm working on adding flow diagram/visualizations showing the proposed configuration models to this proposal to help others follow the conversation as well).

That said, I know that jupyterlab has moved towards a configuration model where each extension has its own config file a conf.d. I was modeling the jupyter server (and its extensions) after this model. But, this conversation has made me realize this needs a lot more thought. Specifically, I need to think a lot more about Netflix's use-case here... thanks for sharing @rgbkrk

- Add a `migrate` application to automate this migration.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be non-trivial and buggy. I think is a suboptimal approach compared to not breaking currently working infrastructure.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair critique. First and foremost, it sounds like I need to rethink the configuration model and flesh out the details. Perhaps we can reach a solution without requiring a migration.

7. Add necessary documentation to notebook and jupyter_server repos.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the jupyter_server repo would benefit from a history doc to explain why some of the complexity is in place as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


## Detailed Explanation

### Create a `jupyter_server` repository

The first thing to do is fork `notebook`. A new `jupyter_server` repo will keep the server specific logic and remove:
1. the notebook frontend code,
2. deprecated notebook server APIs, and
3. tornado handlers to the classic notebook interface. These pieces will stay in the `notebook` repository.

Things that stay in notebook:

- `edit` module: the handlers for the classic notebook text editor.
- `templates` directory: all html templates for the classic notebook
- `terminal` module: handlers for the classic notebook terminal application.
- `view` module: handlers for file viewer component.
- `static` directory: all js and style sheets for notebook frontend.
- `tree` module: a classic notebook file browser+handlers.
- `auth` module? *(Should this move to jupyter_server?)*

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like auth should probably be the new server, but potentially have a more pluggable design. Security should be pretty hard-nosed by default, e.g. base handlers that already have @web.authenticated on, etc. with it being an explicit decision for some new handler to not be authenticated.


Things that move to jupyter_server:
- `services` module: all jupyter server services, managers, and handlers
- `bundler`: handlers for building download bundles
- `files`: handlers for serving files from contents manager.
- `kernelspec`: handler for getting kernelspec
- `base`: base handler for jupyter apps.
- `i18n`: module for internationalizing the jupyter server


Preliminary work resides in [jupyter_server](https://github.com/jupyter/jupyter_server).

### Server Extensions

The extension mechanism for the *jupyter server* will be the main area where server extensions differ from notebook's server extensions.

Enabled server extensions will still be loaded using the `load_jupyter_server_extension` approach when the jupyter server is started.

**Server extensions as applications**

In the proposed jupyter_server, extension developers may also create an application from their extension, using a new `JupyterServerExtensionApp` class. Extension developers can subclass the new base class to make server extensions into Jupyter applications (configurable and launchable from the commmand line). This new class loads extension config from file and parses configuration set from the command line.

For example, the legacy notebook could be started: 1) as an enabled extension or 2) by running the traitlets application from the command line.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be 100% clear you mean the JupyterApp application?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, the language is a bit sloppy.

The idea here is to make server extensions that can behave like stand alone applications. You can load them by launching jupyter server and listing them as an extension or you can call jupyter <my_extension> from the command line (and pass configurable traits to that extension at the CLI).

The example I mention is a "classic notebook" extension, which launches the classic notebook frontend. You would be able run the notebook application by launching jupyter server and loading the notebook extension or calling the extension directly from the CLI (i.e. jupyter classic-notebook or maybe jupyter notebook).

This would be made possible by a JupyterServerExtensionApp class (which inherit JupyterApp). An extension that inherit this class behaves like a JupyterApp that starts a jupyter server and appends the extension to the server.

As a prototype, checkout out jupyter_server_extension.

Does that make sense?


Example extension:
```python
from .extension import load_jupyter_server_extension

class NotebookApp(JupyterServerExtensionApp):

name = 'notebook'
description = 'NotebookApp as a server extension.'
load_jupyter_server_extension = staticmethod(load_jupyter_server_extension)
```

`JupyterServerExtensionApp` subclasses are configurable using Jupyter's configuration system. Users can generate config files for each extension in the Jupyter config path (see `jupyter --paths`). Each extension's configuration is loaded when the server is initialized or the extension application is launched.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be a proper JupyterApp as well or only a Configurable?

I think this configuration problem is going to be more challenging than this proposal suggests. See the conversation on jupyter/notebook#4376 for an example of how the current server has issues with its configuration setup.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In which repo would the JupyterServerExtensionApp live?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be a proper JupyterApp as well or only a Configurable?

It would be a JupyterApp.

In which repo would the JupyterServerExtensionApp live?

I'm not sure quite yet. Maybe inside the jupyter_server repo? Or it could live as a small side repo.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name is java-like in length... perhaps jupyter_server.ExtensionApp?


As will all jupyter applications, users can autogenerate a configuration file for their extension using `jupyter my_extension --generate-config`.

Initial experimental work resides in [`jupyter_server_extension`](https://github.com/Zsailer/jupyter_server_extension).

**Classic notebook server extension**

The classic `NotebookApp` will become a server extension. It will inherit `JupyterServerExtensionApp`. Users can enable the notebook using the extension install/enable mechanism or enable the `notebook` in their `jupyter_server_config.py` file:
```python
c.ServerApp.jpserver_extensions = {
'notebook': True
}
```
Users can also launch the notebook application using the (usual)`jupyter notebook` command line interface.

**Extension installing/enabling mechanism**

The new extension mechanism in the *jupyter server* will differ from notebook's server extensions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we are going to make these changes this should occur before or after the refactor. I fear this will be too many moving parts if we try to do it all at the same time.


* The `--sys-prefix` installation would become the default. (Users are confused when enabling an extension requires more permissions than the installation of the package). Installation in system-wide directories would be done with the `--system` option.
* Installing an extension will include the addition of a 'manifest' file into a conf.d directory (under one of the Jupyter configuration directories, `user / sys-prefix / system`). The placement of such an extension manifest provided by a Python package can be done with `jupyter server extension install --py packagename [--user / --system / --sys-prefix]`. Packages (conda or wheels) carrying server extensions could place such manifests in the sys-prefix path by default effectively installing them. Development installations would also require the call to the installation command.

* Enabling an extension is separate from the installation. Multiple scenarios are possible:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enabling an extension at installation point is why the jupyter_notebook_config.d system was created. It seems like a regression to remove this functionality.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, *_config.d was a big step forward, making it far easier to use standard tooling (pip, conda). As the trend continues more towards ease-of-installation, I'd really not like to see us go back to a two-step process.

- enabling an extension at the same level (user / sys-prefix / system) as where it was installed, or at a higher level (user for sys-prefix and system, or sys-prefix for system).
- forcibly disabling an extension that was enabled at a lower level of precedence.
- forcibly enabling an extension that was disabled at a lower level of precedence.
This would be done via two `conf.d` configuration directories managing a list of disabled extensions and list of enabled extensions in the form of empty files having the name of the corresponding extension. If an extension is both disabled and enabled at the same level of precedence, disabling has precedence. Packages (conda or wheels) could place such a enabler file in the sys-prefix path by default. The `jupyter server extension enable` command would be required for development installations.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where would these conf.d configuration directories live?

I feel like it's a mistake to allow serverextensions packages to automatically disable other serverextensions on install and that would be possible with this behaviour.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These conf.d configuration files would live in PREFIX/etc/jupyter/server/.

@mpacer what do you mean about allowing server extension packages to automatically disable other server extensions?


(Possibly) when an extension is enabled at a given precedence level, it may only look for the version of the extension installed at the same or lower precedence level. For example, if an extension `foobar` is installed and enabled system wide, but a user installs a version with `--user`, this version will only be picked up if the user also enables it with `--user`.

### Services become server extensions (with dependency injection)

Right now, there are two ways to extend and customize the jupyter server: services and server extensions. This is a bit confusing for new contributors. The main difference is that services often (but not always) **depend on other services**.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are the docs describing how to use services as a way to customize the jupyter server. As far as I can tell searching through the readthedocs page we have only traitlets documentation and one changelog mentioning anything about services.

From my perspective the lack of documentation is likely far more confusing for new contributors. That documentation needs to be addressed before I feel comfortable with us moving forward with a proposal like this.


On example is the `sessions` service, which depends on the `kernels` and `kernelspec` services. Without these two services, the `sessions` service doesn't work (or even make sense).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Core services should stick around, otherwise I think we're going to end up further in this diaspora of endpoints with no concrete aim of what makes up the core of jupyter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're going to end up further in this diaspora of endpoints with no concrete aim of what makes up the core of jupyter.

That's a great point. Thanks, Kyle.

My original motivation for exploring the idea of merging services and extensions came from projects like kernel_gateway and enterprise_gateway. These projects only provide kernels as a service and drop the other services. My thought was that we could make "which services are provided" a configurable option.

By doing this though, I recognize that I'm approaching a point where the jupyter server is just a configurable tornado server. Perhaps this is the wrong move.

Maybe we need to define what the core jupyter server is--and maybe that's what we have already (minus the notebook). Or maybe "kernels as a service" is the smallest "jupyter unit", and other services should be extensions?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd think kernels and kernelspecs at the very least, as well as sessions.

I understand not having contents be part of this core service, though maybe that makes sessions non-functional(?).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Zsailer - thank you for writing this proposal and starting this great discussion!

@rgbkrk - I totally agree with the notion that kernel management (which needs to include kernelspecs or providers, etc. as you noted) are the root of what "a jupyter server" provides. It's not clear to me what sessions actually provide from a server perspective since clients of the gateways don't need them to spawn kernels.

Although I'm biased, I believe the ability to optionally (and easily) route the kernel management to another node is crucial for multi-tenant capabilities and achieves a natural separation of user data from computation. I can't think of good reasons to necessarily separate out other pieces but that could be due to my lack of experience outside of the gateways. I'm not saying that jupyter_server should solely consist of kernel management - not at all. Just that the "server" should be able to optionally remote certain services. One service that makes sense for this is kernel management (and by association kernelspec management).

@lresende fyi


We could reduce complexity around `jupyter_server` by making *everything* a server extension. We would need to add a **dependency injection** system to allow extensions to depend on other extensions. Some good options are [pyinject](https://github.com/google/pinject) or [python-dependency-injector](https://github.com/ets-labs/python-dependency-injector).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused. We already have an example of an extension depending on another extension using standard python dependency management: bookstore and the nteract_on_jupyter extensions (see a WIP PR for making this work nteract/nteract#4144; it would be much easier if we had our configuration setup in the notebook working correctly jupyter/notebook#4376).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the intent is for an extension to depend on some implementation of a feature provided by a serverextension that you might not know the name of, so can't look for and/or import? I suppose you could walk all of the serverextensions and see if they have the function you want...

serverextension config issues aside (which will be good to fix, good show!) I think the closest thing we have today are the various *_managers, but first-party code is littered with use of private methods of specific implementations, which extensions see and replicate. However, I don't know if we should be looking to find more dependencies to solve these problems: I'd love to have this server end up with fewer. entry_points of course come to mind, but with conf.d we've mostly solved the discoverability need, but maybe we just need more/different named extension points with tighter contracts than here's the whole app, don't break anything!

However, at the same time, a lot of the by-inheritance or replacement patterns we have make it hard to compose behaviors. For example, I would like a ContentsManager that offered a route scheme, such that I could have, say, /contents/local/index.ipynb and /contents/github/jupyter/notebook/index.ipynb, that the frontend and other services would transparently work with, but it's either git or local unless I want to write my own ecosystem. Kernelspecs are much the same way: nb_conda_kernels still confuses the hell out of people, but is actually a pretty sane way to work on multiple notebook-driven projects, but can't be easily composed with, say, a docker provider and remote provider. @takluyver has made significant strides towards this with the KernelFinder pattern, but we'd need lots more: ContentsFinder, AuthFinder, SessionFinder.


To port a service, it will need to be refactored using extension mechanism mentioned above.

### Add namespacing to `static` endpoints and REST API urls.

Currently, the notebook tornado application serves all static files underneath the `/static/` prefix. Jupyter server will add namespacing under the static url and extension REST API urls. Each extension will serve their static files under the `/static/<extension-name>` prefix and their API handlers behind a `/extension/api/<extension-name>` prefix.

For example, the classic notebook server extension will add static handlers that reroute requests to the `/static/notebook/` endpoints.

The jupyter_server will provide a new `JupyterExtensionHandler` base class that reroute requests to the extension's namespaced static and REST API endpoints.

Preliminary experimental work resides in the [`jupyter_server_extension`](https://github.com/Zsailer/jupyter_server_extension) repository.

### Configuration System

The configuration of the server and the legacy notebook are currently tightly coupled in a single NotebookApp configurable. The proposed jupyter server has server-specific configurations in a separate config system from the classic notebook (and jupyterlab) application configurations.

The table below show all the classic notebook traits and where they will live after migration.

**Overview of configuration structure**

The notebook and server configuration both live in the `jupyter_notebook_config.py` file. Extensions are configured in separate files (named after the extension) in the `jupyter_notebook_config.d` directory:
```
~/.jupyter/
├── jupyter_notebook_config.py
└── jupyter_notebook_config.d
└── my_extension.json
```

**New proposed configuration structure**

The jupyter_server configuration lives in the `jupyter_server_config.py` file. Extensios are configured in separate files in the `jupyter_server_config.d` folder. The notebook configuration is stored in a `notebook.py` file, just like other extensions.
```
~/.jupyter/
├── jupyter_server_config.py
└── jupyter_server_config.d
├── notebook.py|json
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was discussion specifically around not allowing .py files in the jupyter_server_config.d setup.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hear, hear!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you point me to this discussion? There are many threads, so it's easy to get lost.

I'm coming to jupyter server conversation/topic very late in the game... so I'm working hard to get up to speed, but I'm definitely going to miss key conversations. Its helping me a ton to compile all that information here.

Copy link
Member

@rgbkrk rgbkrk Feb 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure where the thread is, but I'd expect jupyter_*_.d to not be dynamic config, only static json.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure where the thread is, but I'd expect jupyter_*_.d to not be dynamic config, only static json.

I would agree with that

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks everyone. I've adjusted this in the new draft of the proposal.

├── lab.py|json
└── my_extension.py|json
```

**Migration application**

To make migration easier on users, the jupyter server will include a `migrate` application to split notebook and server configurations into their appropriate locations (listed above). This application will find any `jupyter_notebook_config.py|json` files in `jupyter --paths`, read configured traits, sort server vs. notebook traits, and write them to the appropriate `jupyter_server_config.py|json` and `jupyter_notebook_config.py|json` files.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fear this is likely to be brittle and cause a lot of headaches given how complicated our configuration system is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair point. Perhaps this will go away after I rethink this proposal some more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am am also doubtful about an auto-migration tool. It might be better to merely document the migration.



### How this effects other projects

[**Classic notebook**]()
In short, the classic notebook will become a server extension application. The rest of this proposal describes the details behind what will change in the notebook repo.
[`JupyterServerExtensionApp`]().

[**Jupyter Lab**]()
Jupyter lab will also become a server extension application. The new classes described above should simplify the way JupyterLab interfaces with the server.

[**Kernel Gateway**]()
Kernel Gateway writes custom `kernel` and `kernelmanager` services and load them as server extensions.

[**Kernel Nanny**]()

## Pros and Cons

**Pros** associated with this implementation include

* Allow various frontends to use the backend services of the jupyter server.
* Provides base classes for extension developers writing server extension applications and handlers.
* Reduce complexity when extending the server by making everything a server extension.
* Organizes the configuration for server and extension in a sane and logical manner (`conf.d` approach).

**Cons** associated with this implementation include:

* Break the classic notebook in a backwards incompatible way.
* Affects many projects. The transition may be painful?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any transition difficulties that we can plan for?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a great question.

I think we should start listing specific transition difficulties and how to move foward here. I was kind of getting at that in the "How this effects other projects" section, but it needs to be fleshed out a lot more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if it makes sense to provide tool for the transition, which may end up being harder to use and maintain than doing the change manually.

* Adding a dependency injection system adds new complexity.

## Relevent Issues, PRs, and discussion

Moving to a `conf.d` approach.
* PR [3116](https://github.com/jupyter/notebook/pull/3116), `jupyter/notebook`: extension config in `config.d` directory.
* PR [3782](https://github.com/jupyter/notebook/issues/3782), `jupyter/notebook`: server extension use `conf.d` approach
* PR [2063](https://github.com/jupyter/notebook/issues/2063), `jupyter/notebook`: config merging problems.

Conversation on server/notebook extensions:
* PR [1706](https://github.com/jupyter/notebook/issues/1706), `jupyter/notebook`: proposal to improve server/notebook extensions
* PR [2824](https://github.com/jupyter/notebook/issues/2824), `jupyter/notebook`: enable nbextensions by default

Static Namespace:
* PR [21](https://github.com/jupyter/enhancement-proposals/pull/21#issuecomment-248647152)`jupyter/enhancement-proposals`: mention namespacing.

## Interested

@Zsailer, @SylvainCorlay, @ellisonbg, @blink1073, @kevin-bates