def get(self, path): """get renders the notebook template if a name is given, or redirects to the '/files/' handler if the name is not given.""" path = path.strip('/') self.log.info('Appmode get: %s', path) # Abort if the app path is not below configured trusted_path. if not path.startswith(self.trusted_path): self.log.warn( 'Appmode refused to launch %s outside trusted path %s.', path, self.trusted_path) raise web.HTTPError( 401, 'Notebook is not within trusted Appmode path.') cm = self.contents_manager # will raise 404 on not found try: model = cm.get(path, content=False) except web.HTTPError as e: if e.status_code == 404 and 'files' in path.split('/'): # 404, but '/files/' in URL, let FilesRedirect take care of it return FilesRedirectHandler.redirect_to_files(self, path) else: raise if model['type'] != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) # fix back button navigation self.add_header( "Cache-Control", "cache-control: private, max-age=0, no-cache, no-store") # gather template parameters tmp_path = self.mk_tmp_copy(path) tmp_name = tmp_path.rsplit('/', 1)[-1] render_kwargs = { 'notebook_path': tmp_path, 'notebook_name': tmp_name, 'kill_kernel': False, 'mathjax_url': self.mathjax_url, 'mathjax_config': self.mathjax_config, 'show_edit_button': self.show_edit_button, 'show_other_buttons': self.show_other_buttons, } # template parameters changed over time for parameter in ("get_custom_frontend_exporters", "get_frontend_exporters"): if hasattr(orig_handler, parameter): render_kwargs[parameter] = getattr(orig_handler, parameter) # Ok let's roll .... self.write(self.render_template('appmode.html', **render_kwargs))
def get(self, path): """get renders the notebook template if a name is given, or redirects to the '/files/' handler if the name is not given.""" # split two-part urls: <sessionpath>/index.ipynb=<notebookpath> cm = self.contents_manager session_path, notebook_path = get_session_notebook_paths(path, cm) if session_path == notebook_path and not session_path.endswith( '/index.ipynb'): # fall back to old behavior return self.old_get(path) notebook_path = notebook_path.strip('/') session_path = session_path.strip('/') download_path = notebook_path # will raise 404 on not found try: model = cm.get(notebook_path, content=False) except web.HTTPError as e: if e.status_code == 404: # 404 file not found by cm - let's try to download download_path = try_download_url(self, session_path, notebook_path, cm) if download_path != notebook_path: # OK, downloaded something - let's try to open it as notebook model = cm.get(download_path, content=False) else: return FilesRedirectHandler.redirect_to_files(self, path) else: raise if model['type'] != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) # brute force hack to add this dir to template path if MYPATH not in self.settings['jinja2_env'].loader.searchpath: self.settings['jinja2_env'].loader.searchpath.append(MYPATH) print(self.settings['jinja2_env'].loader.searchpath) address_path = (session_path + '=' + notebook_path).strip('/') print(session_path, notebook_path, download_path, address_path) name = notebook_path.rsplit('/', 1)[-1] self.write( self.render_template('sharesession.html', notebook_path=download_path, session_path=session_path, address_path=address_path, notebook_name=name, kill_kernel=False, mathjax_url=self.mathjax_url, mathjax_config=self.mathjax_config))
def get(self, path): """get renders the notebook template if a name is given, or redirects to the '/files/' handler if the name is not given.""" path_split = path.split('/') user_name = path_split.pop(1) # global environment variables are lazy but easiest way to pass username os.environ['APPMODE_USER'] = user_name path = '/'.join(path_split) path = path.strip('/') self.log.info('Appmode get: %s', path) cm = self.contents_manager # will raise 404 on not found try: model = cm.get(path, content=False) except web.HTTPError as e: if e.status_code == 404 and 'files' in path.split('/'): # 404, but '/files/' in URL, let FilesRedirect take care of it return FilesRedirectHandler.redirect_to_files(self, path) else: raise if model['type'] != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) # fix back button navigation self.add_header( "Cache-Control", "cache-control: private, max-age=0, no-cache, no-store") # gather template parameters tmp_path = self.mk_tmp_copy(path) tmp_name = tmp_path.rsplit('/', 1)[-1] render_kwargs = { 'notebook_path': tmp_path, 'notebook_name': tmp_name, 'kill_kernel': False, 'mathjax_url': self.mathjax_url, 'mathjax_config': self.mathjax_config, } # template parameters changed over time if hasattr(orig_handler, "get_custom_frontend_exporters"): get_cfw = orig_handler.get_custom_frontend_exporters render_kwargs['get_custom_frontend_exporters'] = get_cfw # Ok let's roll .... self.write(self.render_template('appmode.html', **render_kwargs))
def get(self, path): """ Inject the user's KBase cookie before trying to look up a file. One of our big use cases bypasses the typical Jupyter login mechanism. """ cookie_regex = re.compile('([^ =|]+)=([^\|]*)') client_ip = self.request.remote_ip http_headers = self.request.headers ua = http_headers.get('User-Agent', 'unknown') found_cookies = [self.cookies[c] for c in all_cookies if c in self.cookies] if found_cookies: cookie_val = urllib.unquote(found_cookies[0].value) cookie_obj = { k: v.replace('EQUALSSIGN', '=').replace('PIPESIGN', '|') for k, v in cookie_regex.findall(cookie_val) } # if app_log.isEnabledFor(logging.DEBUG): # app_log.debug("kbase cookie = {}".format(cookie_val)) # app_log.debug("KBaseLoginHandler.get: user_id={uid} token={tok}" # .format(uid=sess.get('token', 'none'), # tok=sess.get('token', 'none'))) biokbase.auth.set_environ_token(cookie_obj.get('token', None)) kbase_env.session = cookie_obj.get('kbase_sessionid', '') kbase_env.client_ip = client_ip kbase_env.user = cookie_obj.get('user_id', '') log_event(g_log, 'session_start', {'user': kbase_env.user, 'user_agent': ua}) """get renders the notebook template if a name is given, or redirects to the '/files/' handler if the name is not given.""" path = path.strip('/') cm = self.contents_manager # will raise 404 on not found try: model = cm.get(path, content=False) except web.HTTPError as e: raise # if e.status_code == 404 and 'files' in path.split('/'): # # 404, but '/files/' in URL, let FilesRedirect take care of it # return FilesRedirectHandler.redirect_to_files(self, path) # else: # raise if model['type'] != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) name = url_escape(path.rsplit('/', 1)[-1]) path = url_escape(path) self.write(self.render_template('notebook.html', notebook_path=path, notebook_name=path, kill_kernel=False, mathjax_url=self.mathjax_url, ) )
def get(self, path): """ Inject the user's KBase cookie before trying to look up a file. One of our big use cases bypasses the typical Jupyter login mechanism. """ cookie_regex = re.compile('([^ =|]+)=([^\|]*)') client_ip = self.request.remote_ip http_headers = self.request.headers ua = http_headers.get('User-Agent', 'unknown') auth_cookie = self.cookies.get(auth_cookie_name, None) if auth_cookie: cookie_val = urllib.unquote(auth_cookie.value) cookie_obj = { k: v.replace('EQUALSSIGN', '=').replace('PIPESIGN', '|') for k, v in cookie_regex.findall(cookie_val) } else: raise web.HTTPError(status_code=401, log_message='No auth cookie, denying access', reason='Authorization required for Narrative access') biokbase.auth.set_environ_token(cookie_obj.get('token', None)) kbase_env.session = cookie_obj.get('kbase_sessionid', '') kbase_env.client_ip = client_ip kbase_env.user = cookie_obj.get('user_id', '') log_event(g_log, 'session_start', {'user': kbase_env.user, 'user_agent': ua}) """get renders the notebook template if a name is given, or redirects to the '/files/' handler if the name is not given.""" path = path.strip('/') cm = self.contents_manager # will raise 404 on not found try: model = cm.get(path, content=False) except web.HTTPError as e: raise # if e.status_code == 404 and 'files' in path.split('/'): # # 404, but '/files/' in URL, let FilesRedirect take care of it # return FilesRedirectHandler.redirect_to_files(self, path) # else: # raise if model['type'] != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) name = url_escape(path.rsplit('/', 1)[-1]) path = url_escape(path) self.write(self.render_template('notebook.html', notebook_path=path, notebook_name=path, kill_kernel=False, mathjax_url=self.mathjax_url, ) )
def get(self, path): """ Inject the user's KBase cookie before trying to look up a file. One of our big use cases bypasses the typical Jupyter login mechanism. """ client_ip = self.request.remote_ip http_headers = self.request.headers ua = http_headers.get('User-Agent', 'unknown') auth_cookie = self.cookies.get(auth_cookie_name, None) if auth_cookie: token = urllib.unquote(auth_cookie.value) else: raise web.HTTPError( status_code=401, log_message='No auth cookie, denying access', reason='Authorization required for Narrative access') if token != kbase_env.auth_token: init_session_env(get_user_info(token), client_ip) log_event(g_log, 'session_start', { 'user': kbase_env.user, 'user_agent': ua }) """ get renders the notebook template if a name is given, or redirects to the '/files/' handler if the name is not given. """ path = path.strip('/') cm = self.contents_manager # will raise 404 on not found try: model = cm.get(path, content=False) except web.HTTPError as e: raise # if e.status_code == 404 and 'files' in path.split('/'): # # 404, but '/files/' in URL, let FilesRedirect take care of it # return FilesRedirectHandler.redirect_to_files(self, path) # else: # raise if model['type'] != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) name = url_escape(path.rsplit('/', 1)[-1]) path = url_escape(path) self.write( self.render_template('notebook.html', notebook_path=path, notebook_name=path, kill_kernel=False, mathjax_url=self.mathjax_url))
def get(self, path): """get renders the notebook template if a name is given, or redirects to the '/files/' handler if the name is not given.""" path = path.strip('/') self.log.info('Appmode get: %s', path) cm = self.contents_manager # will raise 404 on not found try: model = cm.get(path, content=False) except web.HTTPError as e: if e.status_code == 404 and 'files' in path.split('/'): # 404, but '/files/' in URL, let FilesRedirect take care of it return FilesRedirectHandler.redirect_to_files(self, path) else: raise if model['type'] != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) # fix back button navigation self.add_header( "Cache-Control", "cache-control: private, max-age=0, no-cache, no-store") # Ok let's roll .... tmp_path = self.mk_tmp_copy(path) tmp_name = tmp_path.rsplit('/', 1)[-1] self.write( self.render_template( 'appmode.html', notebook_path=tmp_path, notebook_name=tmp_name, kill_kernel=False, mathjax_url=self.mathjax_url, mathjax_config=self.mathjax_config, ))
def get(self, path): path = path.strip('/') cm = content_manager(self) if content_manager else self.contents_manager log.info("Viewing notebook %s" % path) try: model = cm.get(path, content=True) except web.HTTPError as e: raise if model['type'] != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) html_exporter = HTMLExporter() html_exporter.template_name = 'classic' (body, resources) = html_exporter.from_notebook_node(model['content']) name = path.rsplit('/', 1)[-1] original_path = path if 'clone_url' in model: path = model['clone_url'] if model['clone_url'] and self.get_argument("clone_folder", False): path = path.split('/') path.pop(-1) path = "/".join(path) self.write(self.render_template('notebook_view.html', notebook_name=name, path=original_path, notebook=body, resources=resources, clonable=show_clone, voila=has_voila, clone_url=path, base_url=self.base_url ) ) self.finish()
def get(self, path): _init_session(self.request, self.cookies) """ get renders the notebook template if a name is given, or redirects to the '/files/' handler if the name is not given. """ path = path.strip("/") cm = self.contents_manager # will raise 404 on not found try: model = cm.get(path, content=False) except web.HTTPError as e: log_event(g_log, "loading_error", {"error": str(e)}) if e.status_code == 403: self.write(self.render_template("403.html", status_code=403)) return else: self.write( self.render_template( "generic_error.html", message=e.log_message, status_code=e.status_code, )) return if model.get("type") != "notebook": # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) path = url_escape(path) self.write( self.render_template( "notebook.html", notebook_path=path, notebook_name=path, kill_kernel=False, mathjax_url=self.mathjax_url, google_analytics_id=URLS.google_analytics_id, userName=kbase_env.user, google_ad_id=URLS.google_ad_id, google_ad_conversion=URLS.google_ad_conversion, ))
def get(self, path): _init_session(self.request, self.cookies) """ get renders the notebook template if a name is given, or redirects to the '/files/' handler if the name is not given. """ path = path.strip('/') cm = self.contents_manager # will raise 404 on not found try: model = cm.get(path, content=False) except web.HTTPError as e: log_event(g_log, 'loading_error', {'error': str(e)}) if e.status_code == 403: self.write(self.render_template('403.html', status_code=403)) return else: self.write(self.render_template( 'generic_error.html', message=e.log_message, status_code=e.status_code )) return if model.get('type') != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) path = url_escape(path) self.write( self.render_template( 'notebook.html', notebook_path=path, notebook_name=path, kill_kernel=False, mathjax_url=self.mathjax_url, google_analytics_id=URLS.google_analytics_id, userName=kbase_env.user, google_ad_id=URLS.google_ad_id, google_ad_conversion=URLS.google_ad_conversion, ) )
def get(self, path): _init_session(self.request, self.cookies) """ get renders the notebook template if a name is given, or redirects to the '/files/' handler if the name is not given. """ path = path.strip('/') cm = self.contents_manager # will raise 404 on not found try: model = cm.get(path, content=False) except web.HTTPError as e: log_event(g_log, 'loading_error', {'error': str(e)}) if e.status_code == 403: self.write(self.render_template('403.html', status_code=403)) return else: self.write( self.render_template('generic_error.html', message=e.log_message, status_code=e.status_code)) return if model.get('type') != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) path = url_escape(path) self.write( self.render_template( 'notebook.html', notebook_path=path, notebook_name=path, kill_kernel=False, mathjax_url=self.mathjax_url, google_analytics_id=URLS.google_analytics_id, ))
def process_request(self, path, query): # copied from jupyter_server/jupyter_server/services/sessions/handlers.py # main handle global saved_nbapp # check if we changed the ipynb file rerun = False # if should rerun whole ipynb path = path or '' path = path.strip('/') if '/' in path: path_without_slash = path.rsplit('/', 1)[1] else: path_without_slash = path content_last_modified_time = ExcelModeHandler.cached_dict_content_last_modified_time.get( path_without_slash, None) (cached_bc, server_type) = ExcelModeHandler.cached_dict_bc.get( path, (None, None)) # finding session, kernel and client if cached_bc == None: try: one_session = yield self.get_session(path_without_slash) self.log.info(one_session) krnl_model = one_session['kernel'] server_type = self.get_server_type(krnl_model) krnl_id = krnl_model['id'] self.log.info('find %s kernel id %s ' % (str(server_type), krnl_id)) krnl = saved_nbapp.kernel_manager.get_kernel(krnl_id) self.log.info(vars(krnl)) cached_bc = krnl.blocking_client() ExcelModeHandler.cached_dict_bc[path] = (cached_bc, server_type) self.log.info("get blocking_client: %s" % str(cached_bc)) self.log.info(vars(cached_bc)) rerun = True except Exception as ex: self.log.error(ex) else: self.log.info("find in cache blocking_client: %s" % str(cached_bc)) if not rerun: model = self.contents_manager.get(path, content=False) # self.log.info( vars(self.contents_manager) ) if model['last_modified'] != content_last_modified_time: rerun = True # rerun whole jpynb file when start up if rerun: try: model = self.contents_manager.get(path, content=True) self.log.debug(model) except web.HTTPError as e: if e.status_code == 404 and 'files' in path.split('/'): # 404, but '/files/' in URL, let FilesRedirect take care of it return FilesRedirectHandler.redirect_to_files(self, path) else: raise if model['type'] != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) try: if model['last_modified'] != content_last_modified_time: self.log.info('execute all cells:' + str(model['last_modified'])) cells = model['content']['cells'] # print("cells", cells) # print("first_cells", cells[0]) for cell in cells: if cell.cell_type == 'code' and cell.source.strip(): self.run_code(cached_bc, cell.source, waitForResult=True) if server_type == ServerType.PYTHON: self.run_code_python_related(cached_bc) ExcelModeHandler.cached_dict_content_last_modified_time[ path] = model['last_modified'] except Exception as ex: self.log.error(ex) # run real function call try: self.log.debug('start to get result: ', query) msg = self.run_code_query(cached_bc, query, server_type) r = self.analysis_result(msg, server_type) except Exception as ex: # raise r = str(ex) s = str(r) self.log.info('result len %ld:%s' % (len(s), s[:100])) self.write(s)
def get(self, path): global cached_bc, content_last_modified_time rerun = False try: self.add_header('Content-Type', 'application/json') self.log.info('Excel Mode: %s', self.request) # uri='/Excel/TestingJupyter.ipynb?&functionName=addtwo&1=2&2=101' # query = parse.urlsplit(self.request.uri).query #parse in python 3.xx, avoid to use uris = self.request.uri.split('?') if len(uris) >= 2: query = uris[1] else: self.write('input is empty') if cached_bc == None: rerun = True cm = self.contents_manager # self.log.info(cm) km = saved_nbapp.kernel_manager # self.log.info("type of km: ") # self.log.info(km) kernals = km.list_kernel_ids() if len(kernals) <= 0: kn = km.start_kernel() self.log.info("type of kn: ", str(kn)) # km.load_connection_file() # km.start_channels() # connect_shell kernals = km.list_kernel_ids() self.log.info("kenerals:" + str(kernals)) if len(kernals) > 0: krnl_id = kernals[0] krnl = km.get_kernel(krnl_id) cached_bc = krnl.blocking_client() self.log.info("type of kernal: ", krnl) except: raise # check if we change the file try: if not rerun: model = cm.get(path, content=True) if model['last_modified'] != content_last_modified_time: rerun = True except: pass if rerun: try: model = cm.get(path, content=True) except web.HTTPError as e: if e.status_code == 404 and 'files' in path.split('/'): # 404, but '/files/' in URL, let FilesRedirect take care of it return FilesRedirectHandler.redirect_to_files(self, path) else: raise if model['type'] != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) try: if model['last_modified'] != content_last_modified_time: self.log.info('execute all cells:' + str(model['last_modified'])) cells = model['content']['cells'] print("cells", cells) print("first_cells", cells[0]) for cell in cells: if cell.cell_type == 'code' and cell.source.strip(): self.run_code(cached_bc, cell.source) invoke_command = ''' from urllib import parse import inspect def run_function(query): d = dict(parse.parse_qsl(query) ) d = { k.lower() if isinstance(k, str ) and k != None else k :v for k,v in d.items() } if not 'functionname' in d: return functionName= d['functionname'] f=globals()[functionName] args = inspect.signature(f) i =1 new_d ={} for v in args.parameters : if str(i) in d: new_d[v] = d[str(i)] i +=1 return f(**new_d) ''' self.run_code(cached_bc, invoke_command) content_last_modified_time = model['last_modified'] except: raise try: print('start to get result: ', query) msg = self.run_code(cached_bc, 'a=run_function("' + query + '")', user_expressions={'output': 'a'}) print(msg) if msg['content']['status'] == 'ok': r = msg['content']['user_expressions']['output']['data'] else: r = msg['content'] #return all content might be easier # print ('result: ' , r) except Exception as ex: # raise r = str(ex) # fix back button navigation self.write(r)
def get(self, format: str, path: str): """Handle the GET method call.""" if format != 'pdf': self.log.exception('format must be pdf') raise web.HTTPError(500, 'format must be pdf') self.config.PDFExporter.preprocessors = [thermohw.ExtractAttachmentsPreprocessor] self.config.PDFExporter.template_file = os.path.join(thermohw_dir, 'homework.tpl') self.config.PDFExporter.filters = {'convert_div': thermohw.convert_div, 'convert_raw_html': thermohw.convert_raw_html} self.config.PDFExporter.latex_count = 1 exporter = PDFExporter(config=self.config, log=self.log) exporter.writer.build_directory = '.' pdfs = [] path = path.strip('/').strip() paths = path.split('.ipynb') for path in paths: if not path: continue path += '.ipynb' # If the notebook relates to a real file (default contents manager), # give its path to nbconvert. ext_resources_dir: Union[str, None] basename: str os_path: str if hasattr(self.contents_manager, '_get_os_path'): os_path = self.contents_manager._get_os_path(path) ext_resources_dir, basename = os.path.split(os_path) else: ext_resources_dir = None model: Dict[str, str] = self.contents_manager.get(path=path) name: str = model['name'] if model['type'] != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) nb = model['content'] self.set_header('Last-Modified', model['last_modified']) # create resources dictionary mod_date: str = model['last_modified'].strftime(text.date_format) nb_title: str = os.path.splitext(name)[0] config_dir: str = self.application.settings['config_dir'] resource_dict: Dict[str, str] = { "metadata": { "name": nb_title, "modified_date": mod_date }, "config_dir": config_dir, } if ext_resources_dir: resource_dict['metadata']['path'] = ext_resources_dir output: bytes try: output, _ = exporter.from_notebook_node( nb, resources=resource_dict ) except Exception as e: self.log.exception("nbconvert failed: %s", e) raise web.HTTPError(500, "nbconvert failed: %s" % e) pdfs.append(io.BytesIO(output)) writer = PdfWriter() for pdf in pdfs: writer.addpages(PdfReader(pdf).pages) bio = io.BytesIO() writer.write(bio) bio.seek(0) output = bio.read() bio.close() # Force download if requested if self.get_argument('download', 'false').lower() == 'true': filename = 'final_output.pdf' self.set_header('Content-Disposition', 'attachment; filename="{}"'.format(filename)) # MIME type if exporter.output_mimetype: self.set_header('Content-Type', '{}; charset=utf-8'.format(exporter.output_mimetype)) self.set_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') self.finish(output)
def get(self, path): """ Inject the user's KBase cookie before trying to look up a file. One of our big use cases bypasses the typical Jupyter login mechanism. """ cookie_regex = re.compile('([^ =|]+)=([^\|]*)') client_ip = self.request.remote_ip http_headers = self.request.headers ua = http_headers.get('User-Agent', 'unknown') found_cookies = [ self.cookies[c] for c in all_cookies if c in self.cookies ] if found_cookies: cookie_val = urllib.unquote(found_cookies[0].value) cookie_obj = { k: v.replace('EQUALSSIGN', '=').replace('PIPESIGN', '|') for k, v in cookie_regex.findall(cookie_val) } # if app_log.isEnabledFor(logging.DEBUG): # app_log.debug("kbase cookie = {}".format(cookie_val)) # app_log.debug("KBaseLoginHandler.get: user_id={uid} token={tok}" # .format(uid=sess.get('token', 'none'), # tok=sess.get('token', 'none'))) biokbase.auth.set_environ_token(cookie_obj.get('token', None)) kbase_env.session = cookie_obj.get('kbase_sessionid', '') kbase_env.client_ip = client_ip kbase_env.user = cookie_obj.get('user_id', '') log_event(g_log, 'session_start', { 'user': kbase_env.user, 'user_agent': ua }) """get renders the notebook template if a name is given, or redirects to the '/files/' handler if the name is not given.""" path = path.strip('/') cm = self.contents_manager # will raise 404 on not found try: model = cm.get(path, content=False) except web.HTTPError as e: raise # if e.status_code == 404 and 'files' in path.split('/'): # # 404, but '/files/' in URL, let FilesRedirect take care of it # return FilesRedirectHandler.redirect_to_files(self, path) # else: # raise if model['type'] != 'notebook': # not a notebook, redirect to files return FilesRedirectHandler.redirect_to_files(self, path) name = url_escape(path.rsplit('/', 1)[-1]) path = url_escape(path) self.write( self.render_template( 'notebook.html', notebook_path=path, notebook_name=path, kill_kernel=False, mathjax_url=self.mathjax_url, ))