Skip to content

Commit

Permalink
Merge pull request #285 from Zsailer/base_url-static
Browse files Browse the repository at this point in the history
Prefix all extension URLs with base_url (including static)
  • Loading branch information
echarles committed Aug 25, 2020
2 parents 321588d + fa6c0d1 commit 7a7789c
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 8 deletions.
11 changes: 6 additions & 5 deletions jupyter_server/extension/application.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import sys
import re
import logging
from urllib.parse import urljoin

from jinja2 import Environment, FileSystemLoader

from traitlets import (
Unicode,
List,
Dict,
Bool,
default,
validate
default
)
from traitlets.config import Config
from tornado.log import LogFormatter
Expand Down Expand Up @@ -191,8 +190,10 @@ def _default_log_format(self):

@property
def static_url_prefix(self):
return "/static/{name}/".format(
name=self.name)
static_url = "static/{name}".format(
name=self.name
)
return urljoin(self.serverapp.base_url, static_url)

static_paths = List(Unicode(),
help="""paths to search for serving static files.
Expand Down
12 changes: 10 additions & 2 deletions jupyter_server/extension/handler.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from urllib.parse import urljoin
from jupyter_server.base.handlers import FileFindHandler


Expand All @@ -15,7 +16,7 @@ class ExtensionHandlerMixin:
"""Base class for Jupyter server extension handlers.
Subclasses can serve static files behind a namespaced
endpoint: "/static/<name>/"
endpoint: "<base_url>/static/<name>/"
This allows multiple extensions to serve static files under
their own namespace and avoid intercepting requests for
Expand Down Expand Up @@ -49,9 +50,16 @@ def config(self):
def server_config(self):
return self.settings["config"]

@property
def base_url(self):
return self.settings.get('base_url', '/')

@property
def static_url_prefix(self):
return "/static/{name}/".format(name=self.name)
static_url = "static/{name}".format(
name=self.name
)
return urljoin(self.serverapp.base_url, static_url)

@property
def static_path(self):
Expand Down
3 changes: 2 additions & 1 deletion jupyter_server/extension/serverextension.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def _get_config_dir(user=False, sys_prefix=False):
return extdir


def _get_extmanager_for_context(user=False, sys_prefix=False):
def _get_extmanager_for_context(write_dir="jupyter_server_config.d", user=False, sys_prefix=False):
"""Get an extension manager pointing at the current context
Returns the path to the current context and an ExtensionManager object.
Expand Down Expand Up @@ -295,6 +295,7 @@ def list_server_extensions(self):
{"user": False, "sys_prefix": True},
{"user": False, "sys_prefix": False}
)

for option in configurations:
config_dir, ext_manager = _get_extmanager_for_context(**option)
self.log.info("Config dir: {}".format(config_dir))
Expand Down
4 changes: 4 additions & 0 deletions tests/extension/mockextensions/app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from traitlets import Unicode, List

from jupyter_server.base.handlers import JupyterHandler
Expand All @@ -10,6 +11,8 @@
ExtensionHandlerJinjaMixin
)

STATIC_PATH = os.path.join(os.path.dirname(__file__), "static")


class MockExtensionHandler(ExtensionHandlerMixin, JupyterHandler):

Expand All @@ -31,6 +34,7 @@ class MockExtensionApp(ExtensionAppJinjaMixin, ExtensionApp):

name = 'mockextension'
template_paths = List().tag(config=True)
static_paths = [STATIC_PATH]
mock_trait = Unicode('mock trait', config=True)
loaded = False

Expand Down
1 change: 1 addition & 0 deletions tests/extension/mockextensions/static/mock.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mock static content
39 changes: 39 additions & 0 deletions tests/extension/test_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,42 @@ async def test_handler_argv(fetch):
)
assert r.code == 200
assert r.body.decode() == 'test mock trait'


@pytest.mark.parametrize(
'server_config',
[
{
"ServerApp": {
"jpserver_extensions": {
"tests.extension.mockextensions": True
},
# Move extension handlers behind a url prefix
"base_url": "test_prefix"
},
"MockExtensionApp": {
# Change a trait in the MockExtensionApp using
# the following config value.
"mock_trait": "test mock trait"
}
}
]
)
async def test_base_url(fetch):
# Test that the extension's handlers were properly prefixed
r = await fetch(
'test_prefix', 'mock',
method='GET'
)
assert r.code == 200
assert r.body.decode() == 'test mock trait'

# Test that the static namespace was prefixed by base_url
r = await fetch(
'test_prefix',
'static', 'mockextension', 'mock.txt',
method='GET'
)
assert r.code == 200
body = r.body.decode()
assert "mock static content" in body

0 comments on commit 7a7789c

Please sign in to comment.