def test_hidden_files(self): not_hidden = [ u'å b', u'å b/ç. d', ] hidden = [ u'.å b', u'å b/.ç d', ] dirs = not_hidden + hidden nbdir = self.notebook_dir.name for d in dirs: path = pjoin(nbdir, d.replace('/', os.sep)) if not os.path.exists(path): os.mkdir(path) with open(pjoin(path, 'foo'), 'w') as f: f.write('foo') with open(pjoin(path, '.foo'), 'w') as f: f.write('.foo') url = self.base_url() for d in not_hidden: path = pjoin(nbdir, d.replace('/', os.sep)) r = requests.get(url_path_join(url, 'files', d, 'foo')) r.raise_for_status() self.assertEqual(r.text, 'foo') r = requests.get(url_path_join(url, 'files', d, '.foo')) self.assertEqual(r.status_code, 404) for d in hidden: path = pjoin(nbdir, d.replace('/', os.sep)) for foo in ('foo', '.foo'): r = requests.get(url_path_join(url, 'files', d, foo)) self.assertEqual(r.status_code, 404)
def test_old_files_redirect(self): """pre-2.0 'files/' prefixed links are properly redirected""" nbdir = self.notebook_dir.name base = self.base_url() os.mkdir(pjoin(nbdir, 'files')) os.makedirs(pjoin(nbdir, 'sub', 'files')) for prefix in ('', 'sub'): with open(pjoin(nbdir, prefix, 'files', 'f1.txt'), 'w') as f: f.write(prefix + '/files/f1') with open(pjoin(nbdir, prefix, 'files', 'f2.txt'), 'w') as f: f.write(prefix + '/files/f2') with open(pjoin(nbdir, prefix, 'f2.txt'), 'w') as f: f.write(prefix + '/f2') with open(pjoin(nbdir, prefix, 'f3.txt'), 'w') as f: f.write(prefix + '/f3') url = url_path_join(base, 'notebooks', prefix, 'files', 'f1.txt') r = requests.get(url) self.assertEqual(r.status_code, 200) self.assertEqual(r.text, prefix + '/files/f1') url = url_path_join(base, 'notebooks', prefix, 'files', 'f2.txt') r = requests.get(url) self.assertEqual(r.status_code, 200) self.assertEqual(r.text, prefix + '/files/f2') url = url_path_join(base, 'notebooks', prefix, 'files', 'f3.txt') r = requests.get(url) self.assertEqual(r.status_code, 200) self.assertEqual(r.text, prefix + '/f3')
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 cm.dir_exists(path): # it's a *directory*, redirect to /tree url = url_path_join(self.base_url, 'tree', path) else: orig_path = path # otherwise, redirect to /files parts = path.split('/') if not 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.warn("Deprecated files/ URL: %s", orig_path) parts.remove('files') path = '/'.join(parts) if not cm.file_exists(path=path): raise web.HTTPError(404) url = url_path_join(self.base_url, 'files', path) url = url_escape(url) self.log.debug("Redirecting %s to %s", self.request.path, url) self.redirect(url)
def test_redirect(self): r = requests.get(url_path_join(self.base_url(), 'tree/foo/bar.ipynb')) self.assertEqual(r.url, self.base_url() + 'notebooks/foo/bar.ipynb') r = requests.get(url_path_join(self.base_url(), 'tree/foo/baz.txt')) self.assertEqual(r.url, url_path_join(self.base_url(), 'files/foo/baz.txt'))
def test_from_post_zip(self): nbmodel_url = url_path_join(self.base_url(), 'api/contents/foo/testnb.ipynb') nbmodel = requests.get(nbmodel_url).json() r = self.nbconvert_api.from_post(format='latex', nbmodel=nbmodel) self.assertIn(u'application/zip', r.headers['Content-Type']) self.assertIn(u'.zip', r.headers['Content-Disposition'])
def _req(self, verb, path, body=None, params=None): response = requests.request(verb, url_path_join(self.base_url, 'nbconvert', path), data=body, params=params, ) response.raise_for_status() return response
def get(self, path): self.log.warn("/api/notebooks is deprecated, use /api/contents") self.redirect(url_path_join( self.base_url, 'api/contents', path ))
def _req(self, verb, section, body=None): response = requests.request(verb, url_path_join(self.base_url, 'api/config', section), data=body, ) response.raise_for_status() return response
def _req(self, verb, path, body=None, params=None): response = requests.request(verb, url_path_join(self.base_url, 'api/nbconvert', path), data=body, params=params, ) response.raise_for_status() return response
def _req(self, verb, path, body=None): response = requests.request(verb, url_path_join(self.base_url, path), data=body, ) response.raise_for_status() return response
def test_download(self): nbdir = self.notebook_dir.name base = self.base_url() text = 'hello' with open(pjoin(nbdir, 'test.txt'), 'w') as f: f.write(text) r = requests.get(url_path_join(base, 'files', 'test.txt')) disposition = r.headers.get('Content-Disposition', '') self.assertNotIn('attachment', disposition) r = requests.get(url_path_join(base, 'files', 'test.txt') + '?download=1') disposition = r.headers.get('Content-Disposition', '') self.assertIn('attachment', disposition) self.assertIn('filename="test.txt"', disposition)
def test_download(self): nbdir = self.notebook_dir.name base = self.base_url() text = 'hello' with open(pjoin(nbdir, 'test.txt'), 'w') as f: f.write(text) r = requests.get(url_path_join(base, 'files', 'test.txt')) disposition = r.headers.get('Content-Disposition', '') self.assertNotIn('attachment', disposition) r = requests.get( url_path_join(base, 'files', 'test.txt') + '?download=1') disposition = r.headers.get('Content-Disposition', '') self.assertIn('attachment', disposition) self.assertIn('filename="test.txt"', disposition)
def _req(self, verb, section, body=None): response = requests.request( verb, url_path_join(self.base_url, 'api/config', section), data=body, ) response.raise_for_status() return response
def test_get_nb_no_content(self): for d, name in self.dirs_nbs: path = url_path_join(d, name + '.ipynb') nb = self.api.read(path, content=False).json() self.assertEqual(nb['name'], u'%s.ipynb' % name) self.assertEqual(nb['path'], path) self.assertEqual(nb['type'], 'notebook') self.assertIn('content', nb) self.assertEqual(nb['content'], None)
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_escape(url_path_join(self.base_url, 'api', 'contents', path))
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', path, 'checkpoints', checkpoint['id']) self.set_header('Location', url_escape(location)) self.set_status(201) self.finish(data)
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_escape(url_path_join(u'/api/contents', 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 test_contents_manager(self): "make sure ContentsManager returns right files (ipynb, bin, txt)." nbdir = self.notebook_dir.name base = self.base_url() nb = new_notebook( cells=[ new_markdown_cell(u'Created by test ³'), new_code_cell("print(2*6)", outputs=[ new_output("stream", text="12"), ]) ] ) with io.open(pjoin(nbdir, 'testnb.ipynb'), 'w', encoding='utf-8') as f: write(nb, f, version=4) with io.open(pjoin(nbdir, 'test.bin'), 'wb') as f: f.write(b'\xff' + os.urandom(5)) f.close() with io.open(pjoin(nbdir, 'test.txt'), 'w') as f: f.write(u'foobar') f.close() r = requests.get(url_path_join(base, 'files', 'testnb.ipynb')) self.assertEqual(r.status_code, 200) self.assertIn('print(2*6)', r.text) json.loads(r.text) r = requests.get(url_path_join(base, 'files', 'test.bin')) self.assertEqual(r.status_code, 200) self.assertEqual(r.headers['content-type'], 'application/octet-stream') self.assertEqual(r.content[:1], b'\xff') self.assertEqual(len(r.content), 6) r = requests.get(url_path_join(base, 'files', 'test.txt')) self.assertEqual(r.status_code, 200) self.assertEqual(r.headers['content-type'], 'text/plain') self.assertEqual(r.text, 'foobar')
def test_get_nb_contents(self): for d, name in self.dirs_nbs: path = url_path_join(d, name + '.ipynb') nb = self.api.read(path).json() self.assertEqual(nb['name'], u'%s.ipynb' % name) self.assertEqual(nb['path'], path) self.assertEqual(nb['type'], 'notebook') self.assertIn('content', nb) self.assertEqual(nb['format'], 'json') self.assertIn('metadata', nb['content']) self.assertIsInstance(nb['content']['metadata'], dict)
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_escape(url_path_join( self.base_url, 'api', 'contents', path ))
def test_delete(self): for d, name in self.dirs_nbs: print('%r, %r' % (d, name)) resp = self.api.delete(url_path_join(d, name + '.ipynb')) self.assertEqual(resp.status_code, 204) for d in self.dirs + ['/']: nbs = notebooks_only(self.api.list(d).json()) print('------') print(d) print(nbs) self.assertEqual(nbs, [])
def _req(self, verb, path, body=None): response = requests.request(verb, url_path_join(self.base_url, 'api/kernels', path), data=body) if 400 <= response.status_code < 600: try: response.reason = response.json()['message'] except: pass response.raise_for_status() return response
def _req(self, verb, path, body=None): response = requests.request(verb, url_path_join(self.base_url, 'api/sessions', path), data=body) if 400 <= response.status_code < 600: try: response.reason = response.json()['message'] except: pass response.raise_for_status() return response
def test_contents_manager(self): "make sure ContentsManager returns right files (ipynb, bin, txt)." nbdir = self.notebook_dir.name base = self.base_url() nb = new_notebook(cells=[ new_markdown_cell(u'Created by test ³'), new_code_cell("print(2*6)", outputs=[ new_output("stream", text="12"), ]) ]) with io.open(pjoin(nbdir, 'testnb.ipynb'), 'w', encoding='utf-8') as f: write(nb, f, version=4) with io.open(pjoin(nbdir, 'test.bin'), 'wb') as f: f.write(b'\xff' + os.urandom(5)) f.close() with io.open(pjoin(nbdir, 'test.txt'), 'w') as f: f.write(u'foobar') f.close() r = requests.get(url_path_join(base, 'files', 'testnb.ipynb')) self.assertEqual(r.status_code, 200) self.assertIn('print(2*6)', r.text) json.loads(r.text) r = requests.get(url_path_join(base, 'files', 'test.bin')) self.assertEqual(r.status_code, 200) self.assertEqual(r.headers['content-type'], 'application/octet-stream') self.assertEqual(r.content[:1], b'\xff') self.assertEqual(len(r.content), 6) r = requests.get(url_path_join(base, 'files', 'test.txt')) self.assertEqual(r.status_code, 200) self.assertEqual(r.headers['content-type'], 'text/plain') self.assertEqual(r.text, 'foobar')
def test_from_post(self): nbmodel_url = url_path_join(self.base_url(), 'api/contents/foo/testnb.ipynb') nbmodel = requests.get(nbmodel_url).json() r = self.nbconvert_api.from_post(format='html', nbmodel=nbmodel) self.assertEqual(r.status_code, 200) self.assertIn(u'text/html', r.headers['Content-Type']) self.assertIn(u'Created by test', r.text) self.assertIn(u'print', r.text) r = self.nbconvert_api.from_post(format='python', nbmodel=nbmodel) self.assertIn(u'text/x-python', r.headers['Content-Type']) self.assertIn(u'print(2*6)', r.text)
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 = km.start_kernel(kernel_name=model['name']) model = km.kernel_model(kernel_id) location = url_path_join(self.base_url, 'api', 'kernels', kernel_id) self.set_header('Location', url_escape(location)) self.set_status(201) self.finish(json.dumps(model))
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 = km.start_kernel(kernel_name=model['name']) model = km.kernel_model(kernel_id) location = url_path_join(self.base_url, 'api', 'kernels', kernel_id) self.set_header('Location', url_escape(location)) self.set_status(201) self.finish(json.dumps(model))
def test_get_binary_file_contents(self): for d, name in self.dirs_nbs: path = url_path_join(d, name + '.blob') model = self.api.read(path).json() self.assertEqual(model['name'], u'%s.blob' % name) self.assertEqual(model['path'], path) self.assertIn('content', model) self.assertEqual(model['format'], 'base64') self.assertEqual(model['type'], 'file') self.assertEqual( base64.decodestring(model['content'].encode('ascii')), self._blob_for_name(name), ) # Name that doesn't exist - should be a 404 with assert_http_error(404): self.api.read('foo/q.txt')
def test_get_text_file_contents(self): for d, name in self.dirs_nbs: path = url_path_join(d, name + '.txt') model = self.api.read(path).json() self.assertEqual(model['name'], u'%s.txt' % name) self.assertEqual(model['path'], path) self.assertIn('content', model) self.assertEqual(model['format'], 'text') self.assertEqual(model['type'], 'file') self.assertEqual(model['content'], self._txt_for_name(name)) # Name that doesn't exist - should be a 404 with assert_http_error(404): self.api.read('foo/q.txt') # Specifying format=text should fail on a non-UTF-8 file with assert_http_error(400): self.api.read('foo/bar/baz.blob', type='file', format='text')
def nbopen(filename, profile='default'): filename = os.path.abspath(filename) home_dir = os.path.expanduser('~') server_inf = find_best_server(filename, profile) if server_inf is not None: print("Using existing server at", server_inf['notebook_dir']) path = os.path.relpath(filename, start=server_inf['notebook_dir']) url = url_path_join(server_inf['url'], 'notebooks', path) webbrowser.open(url, new=2) elif filename.startswith(home_dir): print("Starting new server") notebookapp.launch_new_instance(file_to_run=os.path.abspath(filename), notebook_dir=home_dir, open_browser=True, argv=[], # Avoid it seeing our own argv ) else: raise OutsideHomeDir
def set_default_headers(self): headers = self.settings.get('headers', {}) if "Content-Security-Policy" not in headers: headers["Content-Security-Policy"] = ( "frame-ancestors 'self'; " # Make sure the report-uri is relative to the base_url "report-uri " + url_path_join(self.base_url, csp_report_uri) + ";" ) # Allow for overriding headers for header_name,value in headers.items() : try: self.set_header(header_name, value) except Exception as e: # tornado raise Exception (not a subclass) # if method is unsupported (websocket and Access-Control-Allow-Origin # for example, so just ignore) self.log.debug(e)
def set_default_headers(self): headers = self.settings.get('headers', {}) if "Content-Security-Policy" not in headers: headers["Content-Security-Policy"] = ( "frame-ancestors 'self'; " # Make sure the report-uri is relative to the base_url "report-uri " + url_path_join(self.base_url, csp_report_uri) + ";") # Allow for overriding headers for header_name, value in headers.items(): try: self.set_header(header_name, value) except Exception as e: # tornado raise Exception (not a subclass) # if method is unsupported (websocket and Access-Control-Allow-Origin # for example, so just ignore) self.log.debug(e)
def nbopen(filename, profile='default'): filename = os.path.abspath(filename) home_dir = os.path.expanduser('~') server_inf = find_best_server(filename, profile) if server_inf is not None: print("Using existing server at", server_inf['notebook_dir']) path = os.path.relpath(filename, start=server_inf['notebook_dir']) url = url_path_join(server_inf['url'], 'notebooks', path) webbrowser.open(url, new=2) elif filename.startswith(home_dir): print("Starting new server") notebookapp.launch_new_instance( file_to_run=os.path.abspath(filename), notebook_dir=home_dir, open_browser=True, argv=[], # Avoid it seeing our own argv ) else: raise OutsideHomeDir
def post(self): # Creates a new session #(unless a session already exists for the named nb) sm = self.session_manager cm = self.contents_manager km = self.kernel_manager model = self.get_json_body() if model is None: raise web.HTTPError(400, "No JSON data provided") try: path = model['notebook']['path'] except KeyError: raise web.HTTPError(400, "Missing field in JSON data: notebook.path") try: kernel_name = model['kernel']['name'] except KeyError: self.log.debug("No kernel name specified, using default kernel") kernel_name = None # Check to see if session exists if sm.session_exists(path=path): model = sm.get_session(path=path) else: try: model = sm.create_session(path=path, kernel_name=kernel_name) except NoSuchKernel: msg = ("The '%s' kernel is not available. Please pick another " "suitable kernel instead, or install that kernel." % kernel_name) status_msg = '%s not found' % kernel_name self.log.warn('Kernel not found: %s' % kernel_name) self.set_status(501) self.finish( json.dumps(dict(message=msg, short_message=status_msg))) return location = url_path_join(self.base_url, 'api', 'sessions', model['id']) self.set_header('Location', url_escape(location)) self.set_status(201) self.finish(json.dumps(model, default=date_default))
def post(self): # Creates a new session #(unless a session already exists for the named nb) sm = self.session_manager cm = self.contents_manager km = self.kernel_manager model = self.get_json_body() if model is None: raise web.HTTPError(400, "No JSON data provided") try: path = model['notebook']['path'] except KeyError: raise web.HTTPError(400, "Missing field in JSON data: notebook.path") try: kernel_name = model['kernel']['name'] except KeyError: self.log.debug("No kernel name specified, using default kernel") kernel_name = None # Check to see if session exists if sm.session_exists(path=path): model = sm.get_session(path=path) else: try: model = sm.create_session(path=path, kernel_name=kernel_name) except NoSuchKernel: msg = ("The '%s' kernel is not available. Please pick another " "suitable kernel instead, or install that kernel." % kernel_name) status_msg = '%s not found' % kernel_name self.log.warn('Kernel not found: %s' % kernel_name) self.set_status(501) self.finish(json.dumps(dict(message=msg, short_message=status_msg))) return location = url_path_join(self.base_url, 'api', 'sessions', model['id']) self.set_header('Location', url_escape(location)) self.set_status(201) self.finish(json.dumps(model, default=date_default))
def delete_checkpoint(self, path, checkpoint_id): return self._req('DELETE', url_path_join(path, 'checkpoints', checkpoint_id))
def interrupt(self, id): return self._req('POST', url_path_join(id, 'interrupt'))
def restart(self, id): return self._req('POST', url_path_join(id, 'restart'))
def restore_checkpoint(self, path, checkpoint_id): return self._req('POST', url_path_join(path, 'checkpoints', checkpoint_id))
def new_checkpoint(self, path): return self._req('POST', url_path_join(path, 'checkpoints'))
def get_checkpoints(self, path): return self._req('GET', url_path_join(path, 'checkpoints'))
def kernel_resource(self, name, path): return self._req('GET', url_path_join('kernelspecs', name, path))
def kernel_spec_info(self, name): return self._req('GET', url_path_join('api/kernelspecs', name))