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

Enable ServerApp to discover ExtensionApps (and their config). #180

Merged
merged 33 commits into from
Apr 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4666461
enable extensionapp config to be discoverable from serveapp
Zsailer Feb 28, 2020
f4e6c41
add some comments for future devs
Zsailer Feb 28, 2020
5a19dcd
allow None in non-ExtensionApp extensions
Zsailer Feb 28, 2020
9b1a5c5
adjust tests to capture changes
Zsailer Feb 28, 2020
45222f4
minor bug fixes
Zsailer Mar 3, 2020
4fcc50f
renamed config pytest fixture
Zsailer Mar 3, 2020
e6f8d51
standardize extension loading mechanism
Zsailer Mar 4, 2020
e3c3c6b
pass serverapp and extesnionapp to extensionapp handlers
Zsailer Mar 6, 2020
93b2894
use static url prefix for static paths
Zsailer Mar 10, 2020
5b8132e
iniitalize all enabled extension, then load later
Zsailer Mar 11, 2020
f3730de
split extension initialization and loading
Zsailer Mar 16, 2020
9cc906d
Upgrade examples to align on discovery branch
echarles Mar 20, 2020
b447855
Polish examples
echarles Mar 21, 2020
5e404d1
Launch example via python module
echarles Mar 21, 2020
8f3d517
Avoid to run initialisation methods twice
echarles Mar 21, 2020
d1803e7
Add main for simple_ext2 and simple_ext11
echarles Mar 22, 2020
3634d08
minor changes to extension toggler
Zsailer Mar 24, 2020
fd882ed
adding some comments throughout the code
Zsailer Mar 26, 2020
f854914
move all CLI handling to the ServerApp
Zsailer Mar 27, 2020
ec755ae
remove old traits from extensionapp
Zsailer Mar 30, 2020
67ca746
update tests
Zsailer Apr 2, 2020
258fbf5
update tests with changes to extensionapp
Zsailer Apr 7, 2020
693b6f5
fix examples entrypoint
Zsailer Apr 7, 2020
e77d958
add test dependency: pytest-lazy-fixture
Zsailer Apr 7, 2020
64be87a
unpin pytest
Zsailer Apr 7, 2020
2692a71
import lazyfixture directly due to changes in pytest
Zsailer Apr 7, 2020
e56bae9
drop pytest-lazy-fixture
Zsailer Apr 7, 2020
32b7210
cleaner error handling in init_server_extension
Zsailer Apr 7, 2020
3de6411
minor clean up
Zsailer Apr 7, 2020
24deb30
minor fixes after review
Zsailer Apr 9, 2020
65d659f
add underscore as prefix to extension function
Zsailer Apr 9, 2020
c66af6c
remove load_jupyter_server_extension from examples
Zsailer Apr 10, 2020
9ca9cb2
minor typo in example comment
Zsailer Apr 20, 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
35 changes: 25 additions & 10 deletions examples/simple/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ open http://localhost:8888/simple_ext1/redirect
open http://localhost:8888/static/simple_ext1/favicon.ico
```

You can also start the server extension with python modules.

```bash
python -m simple_ext1
```

## Extension 1 and Extension 2

The following command starts both the `simple_ext1` and `simple_ext2` extensions.
Expand All @@ -90,9 +96,12 @@ open http://localhost:8888/simple_ext2/params/test?var1=foo
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 && \
pip uninstall -y jupyter_server_example && \
python setup.py install && \
cp -r ./etc $(dirname $(which jupyter))/..
```

```bash
# 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
Expand All @@ -102,18 +111,20 @@ jupyter simple-ext1

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`...)
The provided settings via CLI will override the configuration that reside in the files (`jupyter_server_example1_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`.
Check the log, it should return on startup print the Config object.

The content of the Config is based on the trait you have defined via the `CLI` and in the `jupyter_server_example1_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] WARNING | Config option `configD` not recognized by `SimpleApp2`. Did you mean one of: `configA, configB, configC`?
[SimpleApp2] Config {'SimpleApp2': {'configD': 'ConfigD from file'}}
[SimpleApp1] Config {'SimpleApp1': {'configA': 'ConfigA from command line', 'configB': 'ConfigB from file', 'configC': 'ConfigC from file'}}
```
Expand All @@ -133,27 +144,31 @@ Try with the above links to check that only Extension 2 is responding (Extension

`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 "`
```bash
# TODO `--generate-config` returns an exception `"The ExtensionApp has not ServerApp "`
jupyter simple-ext11 --generate-config && vi ~/.jupyter/jupyter_config.py`.
```

The generated configuration should contains the following.

```bash
TBD
# TODO
```

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.
- The `--hello` flag will log on startup `Hello Simple11 - You have provided the --hello flag or defined a c.SimpleApp1.hello == True`
- The `ignore_js` flag
- 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
# You can also launch with a module
python -m simple_ext11 --hello
# 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
```
Expand Down
1 change: 1 addition & 0 deletions examples/simple/jupyter_simple_ext1_config.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
c.SimpleApp1.configA = 'ConfigA from file'
c.SimpleApp1.configB = 'ConfigB from file'
c.SimpleApp1.configC = 'ConfigC from file'
c.SimpleApp1.configD = 'ConfigD from file'
2 changes: 1 addition & 1 deletion examples/simple/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "jupyter-simple-ext",
"name": "jupyter-server-example",
"version": "0.0.1",
"private": true,
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions examples/simple/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ def add_data_files(path):
return data_files

setuptools.setup(
name = 'jupyter_simple_ext',
name = 'jupyter_server_example',
version = VERSION,
description = 'Jupyter Simple Extension',
description = 'Jupyter Server Example',
long_description = open('README.md').read(),
packages = find_packages(),
python_requires = '>=3.5',
Expand Down
10 changes: 5 additions & 5 deletions examples/simple/simple_ext1/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from .application import SimpleApp1

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

load_jupyter_server_extension = SimpleApp1.load_jupyter_server_extension
def _jupyter_server_extension_paths():
return [{
'module': 'simple_ext1.application',
'app': SimpleApp1
}]
4 changes: 4 additions & 0 deletions examples/simple/simple_ext1/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .application import main

if __name__ == "__main__":
main()
8 changes: 4 additions & 4 deletions examples/simple/simple_ext1/application.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import os, jinja2
from traitlets import Unicode
from jupyter_server.extension.application import ExtensionApp, ExtensionAppJinjaMixin
from .handlers import (DefaultHandler, RedirectHandler,
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'
# The url that your extension will serve its homepage.
extension_url = '/simple_ext1/default'

# Should your extension expose other server extensions when launched directly?
load_other_extensions = True
Expand Down
12 changes: 7 additions & 5 deletions examples/simple/simple_ext11/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from .application import SimpleApp1
from .application import SimpleApp11


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

load_jupyter_server_extension = SimpleApp1.load_jupyter_server_extension
{
'module': 'simple_ext11.application',
'app': SimpleApp11
}
]
4 changes: 4 additions & 0 deletions examples/simple/simple_ext11/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .application import main

if __name__ == "__main__":
main()
12 changes: 6 additions & 6 deletions examples/simple/simple_ext11/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ class SimpleApp11(SimpleApp1):
aliases.update({
'simple11-dir': 'SimpleApp11.simple11_dir',
})

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

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

# Local path to static files directory.
static_paths = [
Expand All @@ -37,12 +37,12 @@ class SimpleApp11(SimpleApp1):

hello = Bool(False,
config=True,
help='Say hello',
help='Say hello',
)

ignore_js = Bool(False,
config=True,
help='Ignore Javascript',
help='Ignore Javascript',
)

@observe('ignore_js')
Expand All @@ -56,8 +56,8 @@ def simple11_dir_formatted(self):

def initialize_settings(self):
self.log.info('hello: {}'.format(self.hello))
if self.config['hello'] == True:
self.log.info("Hello Simple11 - You have provided the --hello flag or defined 'c.SimpleApp1.hello == True' in jupyter_server_config.py")
if self.hello == True:
self.log.info("Hello Simple11: You have launched with --hello flag or defined 'c.SimpleApp1.hello == True' in your config file")
self.log.info('ignore_js: {}'.format(self.ignore_js))
super().initialize_settings()

Expand Down
10 changes: 6 additions & 4 deletions examples/simple/simple_ext2/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from .application import SimpleApp2


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

load_jupyter_server_extension = SimpleApp2.load_jupyter_server_extension
{
'module': 'simple_ext2.application',
'app': SimpleApp2
},
]
4 changes: 4 additions & 0 deletions examples/simple/simple_ext2/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .application import main

if __name__ == "__main__":
main()
6 changes: 3 additions & 3 deletions examples/simple/simple_ext2/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
DEFAULT_TEMPLATE_FILES_PATH = os.path.join(os.path.dirname(__file__), "templates")

class SimpleApp2(ExtensionAppJinjaMixin, ExtensionApp):

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

# Te url that your extension will serve its homepage.
default_url = '/simple_ext2'
extension_url = '/simple_ext2'

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

# Local path to static files directory.
static_paths = [
Expand Down
24 changes: 12 additions & 12 deletions jupyter_server/base/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def cookie_name(self):
self.request.host
))
return self.settings.get('cookie_name', default_cookie_name)

@property
def logged_in(self):
"""Is a user currently logged in?"""
Expand Down Expand Up @@ -203,23 +203,23 @@ def log(self):
def jinja_template_vars(self):
"""User-supplied values to supply to jinja templates."""
return self.settings.get('jinja_template_vars', {})

#---------------------------------------------------------------
# URLs
#---------------------------------------------------------------

@property
def version_hash(self):
"""The version hash to use for cache hints for static files"""
return self.settings.get('version_hash', '')

@property
def mathjax_url(self):
url = self.settings.get('mathjax_url', '')
if not url or url_is_absolute(url):
return url
return url_path_join(self.base_url, url)

@property
def mathjax_config(self):
return self.settings.get('mathjax_config', 'TeX-AMS-MML_HTMLorMML-full,Safe')
Expand All @@ -241,27 +241,27 @@ def contents_js_source(self):
self.log.debug("Using contents: %s", self.settings.get('contents_js_source',
'services/contents'))
return self.settings.get('contents_js_source', 'services/contents')

#---------------------------------------------------------------
# Manager objects
#---------------------------------------------------------------

@property
def kernel_manager(self):
return self.settings['kernel_manager']

@property
def contents_manager(self):
return self.settings['contents_manager']

@property
def session_manager(self):
return self.settings['session_manager']

@property
def terminal_manager(self):
return self.settings['terminal_manager']

@property
def kernel_spec_manager(self):
return self.settings['kernel_spec_manager']
Expand All @@ -273,7 +273,7 @@ def config_manager(self):
#---------------------------------------------------------------
# CORS
#---------------------------------------------------------------

@property
def allow_origin(self):
"""Normal Access-Control-Allow-Origin"""
Expand Down Expand Up @@ -310,7 +310,7 @@ def set_default_headers(self):

if self.allow_credentials:
self.set_header("Access-Control-Allow-Credentials", 'true')

def set_attachment_header(self, filename):
"""Set Content-Disposition: attachment header

Expand Down
Loading