Skip to content

Commit

Permalink
Merge pull request #34 from afshin/sessions
Browse files Browse the repository at this point in the history
Workspaces
  • Loading branch information
blink1073 authored Jan 5, 2018
2 parents c126539 + 89fab75 commit 93f25e9
Show file tree
Hide file tree
Showing 14 changed files with 217 additions and 118 deletions.
2 changes: 1 addition & 1 deletion jupyterlab_launcher/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
class LabLauncherApp(NotebookApp):

default_url = Unicode('/lab',
help="The default URL to redirect to from `/`")
help='The default URL to redirect to from `/`')

lab_config = LabConfig()

Expand Down
114 changes: 71 additions & 43 deletions jupyterlab_launcher/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from notebook.utils import url_path_join as ujoin
from traitlets import HasTraits, Bool, Unicode

from .workspaces_handler import WorkspacesHandler
from .settings_handler import SettingsHandler
from .themes_handler import ThemesHandler

Expand All @@ -21,6 +22,8 @@

# The default urls for the application.
default_public_url = '/lab/static/'
default_workspaces_url = '/lab/workspaces/'
default_workspaces_api_url = '/lab/api/workspaces/'
default_settings_url = '/lab/api/settings/'
default_themes_url = '/lab/api/themes/'
default_tree_url = '/lab/tree/'
Expand Down Expand Up @@ -106,55 +109,61 @@ def render_template(self, name, **ns):
class LabConfig(HasTraits):
"""The lab application configuration object.
"""
app_name = Unicode('',
help='The name of the application')
app_name = Unicode('', help='The name of the application.')

app_version = Unicode('',
help='The version of the application')
app_version = Unicode('', help='The version of the application.')

app_namespace = Unicode('',
help='The namespace of the application')
app_namespace = Unicode('', help='The namespace of the application.')

page_url = Unicode('/lab',
help='The url path for the application')
page_url = Unicode('/lab', help='The url path for the application.')

app_settings_dir = Unicode('',
help='The application settings directory')
app_settings_dir = Unicode('', help='The application settings directory.')

templates_dir = Unicode('',
help='The templates directory for the application')
templates_dir = Unicode('', help='The application templates directory.')

static_dir = Unicode('',
help=('The optional location of the local static files. '
'If given, a handler will be added to server the files.'))
help=('The optional location of local static files. '
'If given, a static file handler will be '
'added.'))

public_url = Unicode(default_public_url,
help=('The url public path for the application static files. '
'This can be a CDN if desired'))
help=('The url public path for static application '
'files. This can be a CDN if desired.'))

settings_url = Unicode(default_settings_url,
help='The url path of the settings handler')
help='The url path of the settings handler.')

user_settings_dir = Unicode('',
help='The optional location of the user settings directory')
help=('The optional location of the user '
'settings directory.'))

schemas_dir = Unicode('',
help='The optional location of the settings schemas directory. '
'If given, a handler will be added for settings')
help=('The optional location of the settings '
'schemas directory. If given, a handler will '
'be added for settings.'))

themes_url = Unicode(default_themes_url,
help='The theme url')
workspaces_dir = Unicode('',
help=('The optional location of the saved '
'workspaces directory. If given, a handler '
'will be added for workspaces.'))

workspaces_url = Unicode(default_workspaces_url,
help='The url path of the workspaces handler.')

themes_url = Unicode(default_themes_url, help='The theme url.')

themes_dir = Unicode('',
help=('The optional location of the themes directory. '
'If given, a handler will be added for themes'))
help=('The optional location of the themes '
'directory. If given, a handler will be added '
'for themes.'))

tree_url = Unicode(default_tree_url,
help='The url path of the tree handler')
help='The url path of the tree handler.')

cache_files = Bool(True,
help=('Whether to cache files on the server. This should be '
'`True` unless in development mode'))
help=('Whether to cache files on the server. '
'This should be `True` except in dev mode.'))


class NotFoundHandler(LabHandler):
def render_template(self, name, **ns):
Expand All @@ -176,13 +185,11 @@ def add_handlers(web_app, config):

# Set up the main page handler.
base_url = web_app.settings['base_url']
lab_url = ujoin(base_url, config.page_url, r'/?')
tree_url = ujoin(base_url, config.tree_url, r'/.+')
handlers = [
(ujoin(base_url, config.page_url, r'/?'), LabHandler, {
'lab_config': config
}),
(ujoin(base_url, config.tree_url, r'/?.*'), LabHandler, {
'lab_config': config
})
(lab_url, LabHandler, {'lab_config': config}),
(tree_url, LabHandler, {'lab_config': config})
]

# Cache all or none of the files depending on the `cache_files` setting.
Expand All @@ -191,7 +198,7 @@ def add_handlers(web_app, config):
# Handle local static assets.
if config.static_dir:
config.public_url = ujoin(base_url, default_public_url)
handlers.append((config.public_url + "(.*)", FileFindHandler, {
handlers.append((config.public_url + '(.*)', FileFindHandler, {
'path': config.static_dir,
'no_cache_paths': no_cache_paths
}))
Expand All @@ -206,21 +213,42 @@ def add_handlers(web_app, config):
'settings_dir': config.user_settings_dir
}))

# Handle saved workspaces.
if config.workspaces_dir:
# Handle JupyterLab client URLs that include workspaces.
config.workspaces_url = ujoin(base_url, default_workspaces_url)
workspaces_path = ujoin(base_url, config.workspaces_url, r'/.+')
handlers.append((workspaces_path, LabHandler, {'lab_config': config}))

# Handle API requests for workspaces.
config.workspaces_api_url = ujoin(base_url, default_workspaces_api_url)
workspaces_api_path = config.workspaces_api_url + '(?P<space_name>.+)'
handlers.append((workspaces_api_path, WorkspacesHandler, {
'workspaces_url': config.workspaces_url,
'path': config.workspaces_dir
}))

# Handle local themes.
if config.themes_dir:
config.themes_url = ujoin(base_url, default_themes_url)
handlers.append((ujoin(config.themes_url, "(.*)"), ThemesHandler, {
'themes_url': config.themes_url,
'path': config.themes_dir,
'no_cache_paths': no_cache_paths
}))
handlers.append((
ujoin(config.themes_url, '(.*)'),
ThemesHandler,
{
'themes_url': config.themes_url,
'path': config.themes_dir,
'no_cache_paths': no_cache_paths
}
))

# Let the lab handler act as the fallthrough option instead of a 404.
handlers.append((ujoin(base_url, config.page_url, r'/?.*'), NotFoundHandler, {
'lab_config': config
}))
handlers.append((
ujoin(base_url, config.page_url, r'/?.*'),
NotFoundHandler,
{'lab_config': config}
))

web_app.add_handlers(".*$", handlers)
web_app.add_handlers('.*$', handlers)


def _camelCase(base):
Expand Down
7 changes: 4 additions & 3 deletions jupyterlab_launcher/json_minify.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# This file comes from https://raw.githubusercontent.com/getify/JSON.minify/1e3590ddb043b62c851506d9ae8425336335d879/json_minify/__init__.py
# This file comes from
# https://raw.githubusercontent.com/getify/JSON.minify/1e3590ddb043b62c851506d9ae8425336335d879/json_minify/__init__.py
#
# It is licensed under the following license:

Expand All @@ -11,8 +12,8 @@
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Expand Down
42 changes: 21 additions & 21 deletions jupyterlab_launcher/settings_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from notebook.base.handlers import APIHandler, json_errors


_file_extension = ".jupyterlab-settings"
_file_extension = '.jupyterlab-settings'


class SettingsHandler(APIHandler):
Expand All @@ -21,7 +21,7 @@ def initialize(self, app_settings_dir, schemas_dir, settings_dir):
self.schemas_dir = schemas_dir
self.settings_dir = settings_dir
self.overrides = dict()
overrides_file = os.path.join(app_settings_dir, "overrides.json")
overrides_file = os.path.join(app_settings_dir, 'overrides.json')
if os.path.exists(overrides_file):
with open(overrides_file) as fid:
try:
Expand All @@ -32,11 +32,11 @@ def initialize(self, app_settings_dir, schemas_dir, settings_dir):
@json_errors
@web.authenticated
def get(self, section_name):
self.set_header("Content-Type", "application/json")
self.set_header('Content-Type', 'application/json')

schema = _get_schema(self.schemas_dir, section_name, self.overrides)
path = _path(self.settings_dir, section_name, _file_extension)
raw = "{}"
raw = '{}'
settings = dict()

if os.path.exists(path):
Expand All @@ -55,7 +55,7 @@ def get(self, section_name):
validator.validate(settings)
except ValidationError as e:
self.log.warn(str(e))
raw = "{}"
raw = '{}'

# Send back the raw data to the client.
resp = dict(id=section_name, raw=raw, schema=schema)
Expand All @@ -66,9 +66,9 @@ def get(self, section_name):
@web.authenticated
def put(self, section_name):
if not self.settings_dir:
raise web.HTTPError(404, "No current settings directory")
raise web.HTTPError(404, 'No current settings directory')

raw = self.request.body.strip().decode(u"utf-8")
raw = self.request.body.strip().decode(u'utf-8')

# Validate the data against the schema.
schema = _get_schema(self.schemas_dir, section_name, self.overrides)
Expand All @@ -80,7 +80,7 @@ def put(self, section_name):

# Write the raw data (comments included) to a file.
path = _path(self.settings_dir, section_name, _file_extension, True)
with open(path, "w") as fid:
with open(path, 'w') as fid:
fid.write(raw)

self.set_status(204)
Expand All @@ -92,57 +92,57 @@ def _get_schema(schemas_dir, section_name, overrides):
path = _path(schemas_dir, section_name)

if not os.path.exists(path):
raise web.HTTPError(404, "Schema not found: %r" % path)
raise web.HTTPError(404, 'Schema not found: %r' % path)

with open(path) as fid:
# Attempt to load the schema file.
try:
schema = json.load(fid)
except Exception as e:
name = section_name
message = "Failed parsing schema ({}): {}".format(name, str(e))
message = 'Failed parsing schema ({}): {}'.format(name, str(e))
raise web.HTTPError(500, message)

# Override default values in the schema if necessary.
if section_name in overrides:
defaults = overrides[section_name]
for key in defaults:
if key in schema["properties"]:
schema["properties"][key]["default"] = defaults[key]
if key in schema['properties']:
schema['properties'][key]['default'] = defaults[key]
else:
schema["properties"][key] = dict(default=defaults[key])
schema['properties'][key] = dict(default=defaults[key])

# Validate the schema.
try:
Validator.check_schema(schema)
except Exception as e:
name = section_name
message = "Failed validating schema ({}): {}".format(name, str(e))
message = 'Failed validating schema ({}): {}'.format(name, str(e))
raise web.HTTPError(500, message)

return schema


def _path(root_dir, section_name, file_extension = ".json", make_dirs = False):
def _path(root_dir, section_name, file_extension='.json', make_dirs=False):
"""Parse the URL section name and find the local file system path."""

parent_dir = root_dir

# Attempt to parse path, e.g. @jupyterlab/apputils-extension:themes.
# Try to parse path, e.g. @jupyterlab/apputils-extension:themes.
try:
package_dir, plugin = section_name.split(":")
package_dir, plugin = section_name.split(':')
parent_dir = os.path.join(root_dir, package_dir)
path = os.path.join(parent_dir, plugin + file_extension)
# This is deprecated and exists to support the older URL scheme.
except:
path = os.path.join(root_dir, section_name + file_extension)
except Exception:
message = 'Settings not found ({})'.format(section_name)
raise web.HTTPError(404, message)

if make_dirs and not os.path.exists(parent_dir):
try:
os.makedirs(parent_dir)
except Exception as e:
name = section_name
message = "Failed writing settings ({}): {}".format(name, str(e))
message = 'Failed writing settings ({}): {}'.format(name, str(e))
raise web.HTTPError(500, message)

return path

This file was deleted.

This file was deleted.

Loading

0 comments on commit 93f25e9

Please sign in to comment.