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

simple extension example #117

Merged
merged 38 commits into from
Mar 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
d117ca7
simple extension example
echarles Oct 10, 2019
8ea9032
add typescript example
echarles Oct 11, 2019
ec3d196
force pr refresh
echarles Oct 11, 2019
de57ab2
force pr refresh
echarles Oct 11, 2019
51c3a65
2 apps
echarles Oct 12, 2019
c3f9c28
rm print static path
echarles Oct 12, 2019
08c1266
mention https://github.com/markellekelly/jupyter-server-example in th…
echarles Oct 14, 2019
7aa9263
add default redirect
echarles Oct 14, 2019
f6b8d47
migrate make to README + split simple_ext.json
echarles Oct 14, 2019
beff805
relax jupyter_server version
echarles Oct 16, 2019
d92fb55
add -f src
echarles Oct 16, 2019
7181ebb
refactor handlers and add a TODO fix default URL
echarles Oct 19, 2019
b5c3713
be more precise on returned error
echarles Oct 22, 2019
58eb525
Merge branch 'master' into example
echarles Oct 22, 2019
ea0555a
more examples related to settings and extension
echarles Oct 30, 2019
e9d1a69
extension 11 has flags and aliases
echarles Oct 31, 2019
b5f5766
default_url
echarles Oct 31, 2019
201bc07
Merge branch 'master' into example
echarles Nov 5, 2019
0a215bd
more settings example based on flags and file configs
echarles Nov 5, 2019
b462e9d
add a link to static home
echarles Nov 7, 2019
cab94b7
Merge branch 'master' into example
echarles Nov 16, 2019
81e99d8
more details on SimpleExt11 configs
echarles Nov 16, 2019
edc21fc
simple_app11: hello flag set True to hell config
echarles Nov 16, 2019
ae3d27c
add the correct json in setup.py
echarles Nov 22, 2019
651e91c
Merge branch 'master' into example
echarles Dec 3, 2019
f65c74e
more work on settings
echarles Dec 3, 2019
25504c8
add configuration files
echarles Dec 3, 2019
1b58d29
comment logs
echarles Dec 4, 2019
ff341a1
update readme
echarles Dec 4, 2019
cb046b5
Merge branch 'master' into example
echarles Dec 13, 2019
505fafc
Merge branch 'master' into example
echarles Dec 14, 2019
f15e523
Merge branch 'master' into example
echarles Jan 9, 2020
43b7447
rename configs
echarles Jan 9, 2020
295d7c4
typo
echarles Jan 9, 2020
269fc01
add = when passing the SimpleApp1.configA via CLI
echarles Jan 14, 2020
4a64388
use JinjaMixin
echarles Jan 16, 2020
8aca33c
Merge branch 'master' into example
echarles Feb 29, 2020
c3a1940
align examples to mixin
echarles Feb 29, 2020
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ config.rst

package-lock.json
geckodriver.log
yarn.lock
183 changes: 183 additions & 0 deletions examples/simple/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# Jupyter Server Simple Extension Example

This folder contains example of simple extensions on top of Jupyter Server and review configuration aspects.

## Install

You need `python3` to build and run the server extensions.

```bash
# Clone, create a conda env and install from source.
git clone https://github.com/jupyter/jupyter_server && \
cd examples/simple && \
conda create -y -n jupyter-server-example python=3.7 && \
conda activate jupyter-server-example && \
pip install -e .
```

**OPTIONAL** If you want to build the Typescript code, you need [npm](https://www.npmjs.com) on your local environement. Compiled javascript is provided as artifact in this repository, so this Typescript build step is optional. The Typescript source and configuration have been taken from https://github.com/markellekelly/jupyter-server-example.

```bash
npm install && \
npm run build
```
Zsailer marked this conversation as resolved.
Show resolved Hide resolved

## No Extension

Ensure Jupyter Server is starting without any extension enabled.

```bash
# Run this command from a shell.
jupyter server
```

Browse the default home page, it should show a white page in your browser with the following content: `A Jupyter Server is running.`

```bash
# Jupyter Server default Home Page.
open http://localhost:8888
```

## Extension 1

```bash
# Start the jupyter server activating simple_ext1 extension.
jupyter server --ServerApp.jpserver_extensions="{'simple_ext1': True}"
```

Now you can render `Extension 1` Server content in your browser.

```bash
# Home page as defined by default_url = '/default'.
open http://localhost:8888/simple_ext1/default
# HTML static page.
open http://localhost:8888/static/simple_ext1/home.html
open http://localhost:8888/static/simple_ext1/test.html
# Content from Handlers.
open http://localhost:8888/simple_ext1/params/test?var1=foo
# Content from Template.
open http://localhost:8888/simple_ext1/template1/test
# Content from Template with Typescript.
open http://localhost:8888/simple_ext1/typescript
# Error content.
open http://localhost:8888/simple_ext1/nope
# Redirect.
open http://localhost:8888/simple_ext1/redirect
# Favicon static content.
open http://localhost:8888/static/simple_ext1/favicon.ico
```

## Extension 1 and Extension 2

The following command starts both the `simple_ext1` and `simple_ext2` extensions.

```bash
# Start the jupyter server, it will load both simple_ext1 and simple_ext2 based on the provided trait.
jupyter server --ServerApp.jpserver_extensions="{'simple_ext1': True, 'simple_ext2': True}"
```

Check that the previous `Extension 1` content is still available ant that you can also render `Extension 2` Server content in your browser.

```bash
# HTML static page.
open http://localhost:8888/static/simple_ext2/test.html
# Content from Handlers.
open http://localhost:8888/simple_ext2/params/test?var1=foo
```

## Work with Entrypoints

Optionally, you can copy `simple_ext1.json` and `simple_ext2.json` configuration to your env `etc` folder and start only Extension 1, which will also start Extension 2.

```bash
pip uninstall -y jupyter_simple_ext && \
python setup.py install && \
cp -r ./etc $(dirname $(which jupyter))/..
# Start the jupyter server extension simple_ext1, it will also load simple_ext2 because of load_other_extensions = True..
# When you invoke with the entrypoint, the default url will be opened in your browser.
jupyter simple-ext1
```

## Configuration

Stop any running server (with `CTRL+C`) and start with additional configuration on the command line.

The provided settings via CLI will override the configuration that reside in the files (`jupyter_simple_ext1_config.py`...)

```bash
jupyter simple-ext1 --SimpleApp1.configA="ConfigA from command line"
```

Check the log, it should return on startup something like the following base on the trait you have defined in the CLI and in the `jupyter_simple_ext1_config.py`.

```
[SimpleApp1] Config {'SimpleApp1': {'configA': 'ConfigA from file', 'configB': 'ConfigB from file', 'configC': 'ConfigC from file'}}
[SimpleApp1] Config {'SimpleApp1': {'configA': 'ConfigA from file', 'configB': 'ConfigB from file', 'configC': 'ConfigC from file'}}
[SimpleApp2] WARNING | Config option `configD` not recognized by `SimpleApp2`. Did you mean `config_file`?
[SimpleApp2] Config {'SimpleApp2': {'configD': 'ConfigD from file'}}
[SimpleApp1] Config {'SimpleApp1': {'configA': 'ConfigA from command line', 'configB': 'ConfigB from file', 'configC': 'ConfigC from file'}}
```

## Only Extension 2

Now stop agin the server and start with only `Extension 2`.

```bash
# Start the jupyter server extension simple_ext2, it will NOT load simple_ext1 because of load_other_extensions = False.
jupyter simple-ext2
```

Try with the above links to check that only Extension 2 is responding (Extension 1 URLs should give you an 404 error).

## Extension 11 extends Extension 1

`Extension 11` extends `Extension 1` and brings a few more configs.

Run `jupyter simple-ext11 --generate-config && vi ~/.jupyter/jupyter_config.py`.

> TODO `--generate-config` returns an exception `"The ExtensionApp has not ServerApp "`

The generated configuration should contains the following.

```bash
TBD
```

The `hello`, `ignore_js` and `simple11_dir` are traits defined on the SimpleApp11 class.

It also implements additional flags and aliases for these traits.

+ The `--hello` flag will log on startup `Hello Simple11 - You have provided the --hello flag or defined a c.SimpleApp1.hello == True`.
+ The `--simple11-dir` alias will set `SimpleExt11.simple11_dir` settings.

Stop any running server and then start the simple-ext11.

```bash
jupyter simple-ext11 --hello --simple11-dir any_folder
# TODO FIX the following command, simple11 does not work launching with jpserver_extensions parameter.
jupyter server --ServerApp.jpserver_extensions="{'simple_ext11': True}" --hello --simple11-dir any_folder
```

Ensure the following URLs respond correctly.

```bash
# Jupyter Server Home Page.
open http://localhost:8888/
# TODO Fix Default URL, it does not show on startup.
# Home page as defined by default_url = '/default'.
open http://localhost:8888/simple_ext11/default
# HTML static page.
open http://localhost:8888/static/simple_ext11/test.html
# Content from Handlers.
open http://localhost:8888/simple_ext11/params/test?var1=foo
# Content from Template.
open http://localhost:8888/simple_ext11/template1/test
# Content from Template with Typescript.
open http://localhost:8888/simple_ext11/typescript
# Error content.
open http://localhost:8888/simple_ext11/nope
# Redirect.
open http://localhost:8888/simple_ext11/redirect
# Favicon static content.
open http://localhost:8888/static/simple_ext11/favicon.ico
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"ServerApp": {
"jpserver_extensions": {
"simple_ext1": true
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"ServerApp": {
"jpserver_extensions": {
"simple_ext11": true
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"ServerApp": {
"jpserver_extensions": {
"simple_ext2": true
}
}
}
8 changes: 8 additions & 0 deletions examples/simple/jupyter_server_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Configuration file for jupyter-server extensions.

#------------------------------------------------------------------------------
# Application(SingletonConfigurable) configuration
#------------------------------------------------------------------------------

## The date format used by logging formatters for %(asctime)s
c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S Simple_Extensions_Example'
1 change: 1 addition & 0 deletions examples/simple/jupyter_simple_ext11_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c.SimpleApp11.ignore_js = True
3 changes: 3 additions & 0 deletions examples/simple/jupyter_simple_ext1_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
c.SimpleApp1.configA = 'ConfigA from file'
c.SimpleApp1.configB = 'ConfigB from file'
c.SimpleApp1.configC = 'ConfigC from file'
1 change: 1 addition & 0 deletions examples/simple/jupyter_simple_ext2_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c.SimpleApp2.configD = 'ConfigD from file'
18 changes: 18 additions & 0 deletions examples/simple/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "jupyter-simple-ext",
"version": "0.0.1",
"private": true,
"scripts": {
"build": "tsc -p src && webpack",
"clean": "rimraf build",
"prepublishOnly": "npm run build"
},
"dependencies": {},
"devDependencies": {
"rifraf": "2.0.3",
"webpack": "~4.29.6",
"webpack-cli": "^3.3.0",
"whatwg-fetch": "~2.0.3",
"typescript": "3.6.4"
}
}
50 changes: 50 additions & 0 deletions examples/simple/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import os, setuptools
from setuptools import find_packages

VERSION = '0.0.1'

def get_data_files():
"""Get the data files for the package.
"""
data_files = [
('etc/jupyter/jupyter_server_config.d', ['etc/jupyter/jupyter_server_config.d/simple_ext1.json']),
('etc/jupyter/jupyter_server_config.d', ['etc/jupyter/jupyter_server_config.d/simple_ext2.json']),
('etc/jupyter/jupyter_server_config.d', ['etc/jupyter/jupyter_server_config.d/simple_ext11.json']),
]
def add_data_files(path):
for (dirpath, dirnames, filenames) in os.walk(path):
if filenames:
data_files.append((dirpath, [os.path.join(dirpath, filename) for filename in filenames]))
# Add all static and templates folders.
add_data_files('simple_ext1/static')
add_data_files('simple_ext1/templates')
add_data_files('simple_ext2/static')
add_data_files('simple_ext2/templates')
return data_files

setuptools.setup(
name = 'jupyter_simple_ext',
version = VERSION,
description = 'Jupyter Simple Extension',
long_description = open('README.md').read(),
packages = find_packages(),
python_requires = '>=3.5',
install_requires = [
'jupyter_server',
'jinja2',
],
tests_requires = [
'pytest',
'pytest-cov',
'pylint',
],
include_package_data=True,
data_files = get_data_files(),
entry_points = {
'console_scripts': [
'jupyter-simple-ext1 = simple_ext1.application:main',
'jupyter-simple-ext11 = simple_ext11.application:main',
'jupyter-simple-ext2 = simple_ext2.application:main'
]
},
)
8 changes: 8 additions & 0 deletions examples/simple/simple_ext1/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from .application import SimpleApp1

def _jupyter_server_extension_paths():
return [
{'module': 'simple_ext1'}
]

load_jupyter_server_extension = SimpleApp1.load_jupyter_server_extension
63 changes: 63 additions & 0 deletions examples/simple/simple_ext1/application.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import os, jinja2
from traitlets import Unicode
from jupyter_server.extension.application import ExtensionApp, ExtensionAppJinjaMixin
from .handlers import (DefaultHandler, RedirectHandler,
ParameterHandler, TemplateHandler, TypescriptHandler, ErrorHandler)

DEFAULT_STATIC_FILES_PATH = os.path.join(os.path.dirname(__file__), "static")
DEFAULT_TEMPLATE_FILES_PATH = os.path.join(os.path.dirname(__file__), "templates")

class SimpleApp1(ExtensionAppJinjaMixin, ExtensionApp):

# The name of the extension.
extension_name = "simple_ext1"

# Te url that your extension will serve its homepage.
default_url = '/simple_ext1/default'

# Should your extension expose other server extensions when launched directly?
load_other_extensions = True

# Local path to static files directory.
static_paths = [
DEFAULT_STATIC_FILES_PATH
]

# Local path to templates directory.
template_paths = [
DEFAULT_TEMPLATE_FILES_PATH
]

configA = Unicode('',
config=True,
help='Config A example.'
)

configB = Unicode('',
config=True,
help='Config B example.'
)

configC = Unicode('',
config=True,
help='Config C example.'
)

def initialize_handlers(self):
self.handlers.extend([
(r'/{}/default'.format(self.extension_name), DefaultHandler),
(r'/{}/params/(.+)$'.format(self.extension_name), ParameterHandler),
(r'/{}/template1/(.*)$'.format(self.extension_name), TemplateHandler),
(r'/{}/redirect'.format(self.extension_name), RedirectHandler),
(r'/{}/typescript/?'.format(self.extension_name), TypescriptHandler),
(r'/{}/(.*)', ErrorHandler)
])

def initialize_settings(self):
self.log.info('Config {}'.format(self.config))

#-----------------------------------------------------------------------------
# Main entry point
#-----------------------------------------------------------------------------

main = launch_new_instance = SimpleApp1.launch_instance
Loading