async def get(self, path=None): """ Display appropriate page for given path. - A directory listing is shown if path is a directory - Redirected to notebook page if path is a notebook - Render the raw file if path is any other file """ path = path.strip('/') cm = self.contents_manager if await maybe_future(cm.dir_exists(path=path)): if await maybe_future(cm.is_hidden(path)) and not cm.allow_hidden: self.log.info( "Refusing to serve hidden directory, via 404 Error") raise web.HTTPError(404) # Set treePath for routing to the directory page_config = self.get_page_config() page_config['treePath'] = path tpl = self.render_template("tree.html", page_config=page_config) return self.write(tpl) elif await maybe_future(cm.file_exists(path)): # it's not a directory, we have redirecting to do model = await maybe_future(cm.get(path, content=False)) if model['type'] == 'notebook': url = ujoin(self.base_url, 'notebooks', url_escape(path)) else: # Return raw content if file is not a notebook url = ujoin(self.base_url, 'files', url_escape(path)) self.log.debug("Redirecting %s to %s", self.request.path, url) self.redirect(url) else: raise web.HTTPError(404)
async def redirect_to_files(self, path): """make redirect logic a reusable static method so it can be called from other handlers. """ cm = self.contents_manager if await ensure_async(cm.dir_exists(path)): # it's a *directory*, redirect to /tree url = url_path_join(self.base_url, 'tree', url_escape(path)) else: orig_path = path # otherwise, redirect to /files parts = path.split('/') if not await ensure_async(cm.file_exists(path=path) ) and 'files' in parts: # redirect without files/ iff it would 404 # this preserves pre-2.0-style 'files/' links self.log.warning("Deprecated files/ URL: %s", orig_path) parts.remove('files') path = '/'.join(parts) if not await ensure_async(cm.file_exists(path=path)): raise web.HTTPError(404) url = url_path_join(self.base_url, 'files', url_escape(path)) self.log.debug("Redirecting %s to %s", self.request.path, url) self.redirect(url)
def get(self, matched_part=None, *args, **kwargs): var1 = self.get_argument("var1", default=None) components = [x for x in self.request.path.split("/") if x] self.write("<h1>Hello Simple App 2 from Handler.</h1>") self.write("<p>matched_part: {}</p>".format(url_escape(matched_part))) self.write("<p>var1: {}</p>".format(url_escape(var1))) self.write("<p>components: {}</p>".format(components))
def post(self, path=''): """post creates a new checkpoint""" cm = self.contents_manager checkpoint = yield gen.maybe_future(cm.create_checkpoint(path)) data = json.dumps(checkpoint, default=date_default) location = url_path_join(self.base_url, 'api/contents', url_escape(path), 'checkpoints', url_escape(checkpoint['id'])) self.set_header('Location', location) self.set_status(201) self.finish(data)
async def post(self, path=""): """post creates a new checkpoint""" cm = self.contents_manager checkpoint = await ensure_async(cm.create_checkpoint(path)) data = json.dumps(checkpoint, default=json_default) location = url_path_join( self.base_url, "api/contents", url_escape(path), "checkpoints", url_escape(checkpoint["id"]), ) self.set_header("Location", location) self.set_status(201) self.finish(data)
def test_url_escape(): # changes path or notebook name with special characters to url encoding # these tests specifically encode paths with spaces path = url_escape('/this is a test/for spaces/') nt.assert_equal(path, '/this%20is%20a%20test/for%20spaces/') path = url_escape('notebook with space.ipynb') nt.assert_equal(path, 'notebook%20with%20space.ipynb') path = url_escape('/path with a/notebook and space.ipynb') nt.assert_equal(path, '/path%20with%20a/notebook%20and%20space.ipynb') path = url_escape('/ !@$#%^&* / test %^ notebook @#$ name.ipynb') nt.assert_equal(path, '/%20%21%40%24%23%25%5E%26%2A%20/%20test%20%25%5E%20notebook%20%40%23%24%20name.ipynb')
def get(self, path=''): cm = self.contents_manager if cm.dir_exists(path=path): if cm.is_hidden(path) and not cm.allow_hidden: self.log.info( "Refusing to serve hidden directory, via 404 Error") raise web.HTTPError(404) breadcrumbs = self.generate_breadcrumbs(path) page_title = self.generate_page_title(path) contents = cm.get(path) self.write( self.render_template( 'tree.html', page_title=page_title, notebook_path=path, breadcrumbs=breadcrumbs, contents=contents, terminals_available=False, server_root=self.settings['server_root_dir'], )) elif cm.file_exists(path): # it's not a directory, we have redirecting to do model = cm.get(path, content=False) # redirect to /api/notebooks if it's a notebook, otherwise /api/files service = 'notebooks' if model['type'] == 'notebook' else 'files' url = url_path_join( self.base_url, service, url_escape(path), ) self.log.debug("Redirecting %s to %s", self.request.path, url) self.redirect(url) else: raise web.HTTPError(404)
def test_url_escaping(unescaped, escaped): # Test escaping. path = url_escape(unescaped) assert path == escaped # Test unescaping. path = url_unescape(escaped) assert path == unescaped
def set_attachment_header(self, filename): """Set Content-Disposition: attachment header As a method to ensure handling of filename encoding """ escaped_filename = url_escape(filename) self.set_header( 'Content-Disposition', 'attachment;' " filename*=utf-8''{utf8}".format(utf8=escaped_filename, ))
def generate_breadcrumbs(self, path): breadcrumbs = [(url_path_join(self.base_url, 'voila/tree'), '')] parts = path.split('/') for i in range(len(parts)): if parts[i]: link = url_path_join(self.base_url, 'voila/tree', url_escape(url_path_join(*parts[:i + 1])), ) breadcrumbs.append((link, parts[i])) return breadcrumbs
def location_url(self, path): """Return the full URL location of a file. Parameters ---------- path : unicode The API path of the file, such as "foo/bar.txt". """ return url_path_join(self.base_url, "api", "contents", url_escape(path))
def get(self, path=''): cm = self.contents_manager if cm.dir_exists(path=path): if cm.is_hidden(path) and not cm.allow_hidden: self.log.info("Refusing to serve hidden directory, via 404 Error") raise web.HTTPError(404) breadcrumbs = self.generate_breadcrumbs(path) page_title = self.generate_page_title(path) contents = cm.get(path) template_arg = ( self.get_argument("voila-template", self.voila_configuration.template) if self.voila_configuration.allow_template_override == "YES" else self.voila_configuration.template ) theme_arg = ( self.get_argument("voila-theme", self.voila_configuration.theme) if self.voila_configuration.allow_theme_override == "YES" else self.voila_configuration.theme ) def allowed_content(content): if content['type'] in ['directory', 'notebook']: return True __, ext = os.path.splitext(content.get('path')) return ext in self.allowed_extensions contents['content'] = sorted(contents['content'], key=lambda i: i['name']) contents['content'] = filter(allowed_content, contents['content']) include_assets_functions = create_include_assets_functions(template_arg, self.base_url) self.write(self.render_template('tree.html', page_title=page_title, notebook_path=path, breadcrumbs=breadcrumbs, contents=contents, terminals_available=False, server_root=get_server_root_dir(self.settings), theme=theme_arg, query=self.request.query, **include_assets_functions)) elif cm.file_exists(path): # it's not a directory, we have redirecting to do model = cm.get(path, content=False) # redirect to /api/notebooks if it's a notebook, otherwise /api/files service = 'notebooks' if model['type'] == 'notebook' else 'files' url = url_path_join( self.base_url, service, url_escape(path), ) self.log.debug("Redirecting %s to %s", self.request.path, url) self.redirect(url) else: raise web.HTTPError(404)
def _check_created(self, resp, path, type='notebook'): self.assertEqual(resp.status_code, 201) location_header = py3compat.str_to_unicode(resp.headers['Location']) self.assertEqual( location_header, url_path_join(self.url_prefix, u'api/contents', url_escape(path))) rjson = resp.json() self.assertEqual(rjson['name'], path.rsplit('/', 1)[-1]) self.assertEqual(rjson['path'], path) self.assertEqual(rjson['type'], type) isright = self.isdir if type == 'directory' else self.isfile assert isright(path)
def get(self, path): path = path.strip('/') if not self.contents_manager.file_exists(path): raise web.HTTPError(404, u'File does not exist: %s' % path) basename = path.rsplit('/', 1)[-1] self.write( self.render_template( 'edit.html', file_path=url_escape(path), basename=basename, page_title=basename + " (editing)", ))
async def create_kernel(response: Response, model: NewKernelModel = None): self = router.app km = self.kernel_manager if model is None: kernel_name = km.default_kernel_name elif model.name is None: kernel_name = km.default_kernel_name else: kernel_name = model.name kernel_id = await maybe_future(km.start_kernel(kernel_name=kernel_name)) kernel = await maybe_future(km.kernel_model(kernel_id)) location = url_path_join(self.base_url, 'api', 'kernels', url_escape(kernel_id)) response.headers['Location'] = location # Validate model! return Kernel(**kernel)
def post(self): km = self.kernel_manager model = self.get_json_body() if model is None: model = {"name": km.default_kernel_name} else: model.setdefault("name", km.default_kernel_name) kernel_id = yield maybe_future( km.start_kernel(kernel_name=model["name"])) model = yield maybe_future(km.kernel_model(kernel_id)) location = url_path_join(self.base_url, "api", "kernels", url_escape(kernel_id)) self.set_header("Location", location) self.set_status(201) self.finish(json.dumps(model, default=date_default))
async def post(self): km = self.kernel_manager model = self.get_json_body() if model is None: model = {'name': km.default_kernel_name} else: model.setdefault('name', km.default_kernel_name) kernel_id = await km.start_kernel(kernel_name=model['name'], path=model.get('path')) model = await ensure_async(km.kernel_model(kernel_id)) location = url_path_join(self.base_url, 'api', 'kernels', url_escape(kernel_id)) self.set_header('Location', location) self.set_status(201) self.finish(json.dumps(model, default=date_default))
async def post(self): km = self.kernel_manager model = self.get_json_body() if model is None: model = {"name": km.default_kernel_name} else: model.setdefault("name", km.default_kernel_name) kernel_id = await km.start_kernel(kernel_name=model["name"], path=model.get("path")) model = await ensure_async(km.kernel_model(kernel_id)) location = url_path_join(self.base_url, "api", "kernels", url_escape(kernel_id)) self.set_header("Location", location) self.set_status(201) self.finish(json.dumps(model, default=json_default))
def get(self, path): self.log.warning("/api/notebooks is deprecated, use /api/contents") self.redirect( url_path_join(self.base_url, "api/contents", url_escape(path)))
def initialize_handlers(self): handlers = [] # Set config for Jupyterlab page_config = self.serverapp.web_app.settings.setdefault( 'page_config_data', {}) page_config.setdefault('buildAvailable', not self.core_mode and not self.dev_mode) page_config.setdefault('buildCheck', not self.core_mode and not self.dev_mode) page_config['devMode'] = self.dev_mode page_config['token'] = self.serverapp.token page_config['exposeAppInBrowser'] = self.expose_app_in_browser page_config['quitButton'] = self.serverapp.quit_button # Client-side code assumes notebookVersion is a JSON-encoded string page_config['notebookVersion'] = json.dumps(jpserver_version_info) if self.serverapp.file_to_run: relpath = os.path.relpath(self.serverapp.file_to_run, self.serverapp.root_dir) uri = url_escape( ujoin('{}/tree'.format(self.app_url), *relpath.split(os.sep))) self.default_url = uri self.serverapp.file_to_run = '' self.log.info('JupyterLab extension loaded from %s' % HERE) self.log.info('JupyterLab application directory is %s' % self.app_dir) build_handler_options = AppOptions(logger=self.log, app_dir=self.app_dir) builder = Builder(self.core_mode, app_options=build_handler_options) build_handler = (build_path, BuildHandler, {'builder': builder}) handlers.append(build_handler) errored = False if self.core_mode: self.log.info(CORE_NOTE.strip()) ensure_core(self.log) elif self.dev_mode: if not self.watch: ensure_dev(self.log) self.log.info(DEV_NOTE) else: msgs = ensure_app(self.app_dir) if msgs: [self.log.error(msg) for msg in msgs] handler = (self.app_url, ErrorHandler, {'messages': msgs}) handlers.append(handler) errored = True if self.watch: self.log.info('Starting JupyterLab watch mode...') if self.dev_mode: watch_dev(self.log) else: watch(app_options=build_handler_options) page_config['buildAvailable'] = False self.cache_files = False if not self.core_mode and not errored: ext_manager = ExtensionManager(app_options=build_handler_options) ext_handler = (extensions_handler_path, ExtensionHandler, { 'manager': ext_manager }) handlers.append(ext_handler) # If running under JupyterHub, add more metadata. if hasattr(self, 'hub_prefix'): page_config['hubPrefix'] = self.hub_prefix page_config['hubHost'] = self.hub_host page_config['hubUser'] = self.user page_config['shareUrl'] = ujoin(self.hub_prefix, 'user-redirect') # Assume the server_name property indicates running JupyterHub 1.0. if hasattr(self, 'server_name'): page_config['hubServerName'] = self.server_name api_token = os.getenv('JUPYTERHUB_API_TOKEN', '') page_config['token'] = api_token # Update Jupyter Server's webapp settings with jupyterlab settings. self.serverapp.web_app.settings['page_config_data'] = page_config # Extend Server handlers with jupyterlab handlers. self.handlers.extend(handlers) super().initialize_handlers()