mirror of
https://github.com/jupyter/notebook.git
synced 2024-12-27 04:20:22 +08:00
Added notebooks API tests.
This commit is contained in:
parent
5f1b7727d8
commit
95b505d602
@ -94,17 +94,16 @@ class FileNotebookManager(NotebookManager):
|
||||
def change_notebook(self, data, notebook_name, notebook_path='/'):
|
||||
"""Changes notebook"""
|
||||
changes = data.keys()
|
||||
response = 200
|
||||
for change in changes:
|
||||
full_path = self.get_os_path(notebook_name, notebook_path)
|
||||
if change == "name":
|
||||
new_path = self.get_os_path(data['name'], notebook_path)
|
||||
if not os.path.isfile(new_path):
|
||||
try:
|
||||
os.rename(full_path,
|
||||
self.get_os_path(data['name'], notebook_path))
|
||||
notebook_name = data['name']
|
||||
else:
|
||||
response = 409
|
||||
except OSError as e:
|
||||
raise web.HTTPError(409, u'Notebook name already exists.')
|
||||
if change == "path":
|
||||
new_path = self.get_os_path(data['name'], data['path'])
|
||||
stutil.move(full_path, new_path)
|
||||
@ -112,7 +111,7 @@ class FileNotebookManager(NotebookManager):
|
||||
if change == "content":
|
||||
self.save_notebook(data, notebook_name, notebook_path)
|
||||
model = self.notebook_model(notebook_name, notebook_path)
|
||||
return model, response
|
||||
return model
|
||||
|
||||
def notebook_exists(self, name, path):
|
||||
"""Returns a True if the notebook exists. Else, returns False.
|
||||
@ -131,31 +130,6 @@ class FileNotebookManager(NotebookManager):
|
||||
path = self.get_os_path(name, path)
|
||||
return os.path.isfile(path)
|
||||
|
||||
def get_os_path(self, fname, path='/'):
|
||||
"""Given a notebook name and a server URL path, return its file system
|
||||
path.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : string
|
||||
The name of a notebook file with the .ipynb extension
|
||||
path : string
|
||||
The relative URL path (with '/' as separator) to the named
|
||||
notebook.
|
||||
|
||||
Returns
|
||||
-------
|
||||
path : string
|
||||
A file system path that combines notebook_dir (location where
|
||||
server started), the relative path, and the filename with the
|
||||
current operating system's url.
|
||||
"""
|
||||
parts = path.split('/')
|
||||
parts = [p for p in parts if p != ''] # remove duplicate splits
|
||||
parts += [fname]
|
||||
path = os.path.join(self.notebook_dir, *parts)
|
||||
return path
|
||||
|
||||
def read_notebook_object_from_path(self, path):
|
||||
"""read a notebook object from a path"""
|
||||
info = os.stat(path)
|
||||
|
@ -36,7 +36,7 @@ class NotebookRootHandler(IPythonHandler):
|
||||
"""get returns a list of notebooks from the location
|
||||
where the server was started."""
|
||||
nbm = self.notebook_manager
|
||||
notebooks = nbm.list_notebooks("")
|
||||
notebooks = nbm.list_notebooks("/")
|
||||
self.finish(jsonapi.dumps(notebooks))
|
||||
|
||||
@web.authenticated
|
||||
@ -53,18 +53,9 @@ class NotebookRootHandler(IPythonHandler):
|
||||
fname = nbm.new_notebook(notebook_path='/')
|
||||
self.set_header('Location', nbm.notebook_dir + fname)
|
||||
model = nbm.notebook_model(fname)
|
||||
self.set_header('Location', '{0}api/notebooks/{1}'.format(self.base_project_url, notebook_name))
|
||||
self.set_header('Location', '{0}api/notebooks/{1}'.format(self.base_project_url, fname))
|
||||
self.finish(jsonapi.dumps(model))
|
||||
|
||||
|
||||
class NotebookRootRedirect(IPythonHandler):
|
||||
|
||||
@web.authenticated
|
||||
def get(self):
|
||||
"""get redirects to not include trailing backslash"""
|
||||
self.redirect("/api/notebooks")
|
||||
|
||||
|
||||
class NotebookHandler(IPythonHandler):
|
||||
|
||||
SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH', 'POST','DELETE')
|
||||
@ -86,7 +77,7 @@ class NotebookHandler(IPythonHandler):
|
||||
# get and return notebook representation
|
||||
format = self.get_argument('format', default='json')
|
||||
download = self.get_argument('download', default='False')
|
||||
model = nbm.notebook_model(name,path)
|
||||
model = nbm.notebook_model(name, path)
|
||||
last_mod, representation, name = nbm.get_notebook(name, path, format)
|
||||
self.set_header('Last-Modified', last_mod)
|
||||
|
||||
@ -109,8 +100,7 @@ class NotebookHandler(IPythonHandler):
|
||||
nbm = self.notebook_manager
|
||||
name, path = nbm.named_notebook_path(notebook_path)
|
||||
data = jsonapi.loads(self.request.body)
|
||||
model, response = nbm.change_notebook(data, name, path)
|
||||
self.set_status(response)
|
||||
model = nbm.change_notebook(data, name, path)
|
||||
self.finish(jsonapi.dumps(model))
|
||||
|
||||
@web.authenticated
|
||||
@ -217,7 +207,7 @@ default_handlers = [
|
||||
ModifyNotebookCheckpointsHandler),
|
||||
(r"api/notebooks/%s/" % _notebook_path_regex, NotebookHandler),
|
||||
(r"api/notebooks/%s" % _notebook_path_regex, NotebookHandler),
|
||||
(r"api/notebooks/", NotebookRootRedirect),
|
||||
(r"api/notebooks/", NotebookRootHandler),
|
||||
(r"api/notebooks", NotebookRootHandler),
|
||||
]
|
||||
|
||||
|
@ -71,6 +71,32 @@ class NotebookManager(LoggingConfigurable):
|
||||
name = None
|
||||
path = "/".join(names) + '/'
|
||||
return name, path
|
||||
|
||||
def get_os_path(self, fname=None, path='/'):
|
||||
"""Given a notebook name and a server URL path, return its file system
|
||||
path.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : string
|
||||
The name of a notebook file with the .ipynb extension
|
||||
path : string
|
||||
The relative URL path (with '/' as separator) to the named
|
||||
notebook.
|
||||
|
||||
Returns
|
||||
-------
|
||||
path : string
|
||||
A file system path that combines notebook_dir (location where
|
||||
server started), the relative path, and the filename with the
|
||||
current operating system's url.
|
||||
"""
|
||||
parts = path.split('/')
|
||||
parts = [p for p in parts if p != ''] # remove duplicate splits
|
||||
if fname is not None:
|
||||
parts += [fname]
|
||||
path = os.path.join(self.notebook_dir, *parts)
|
||||
return path
|
||||
|
||||
def url_encode(self, path):
|
||||
"""Returns the path with all special characters URL encoded"""
|
||||
@ -135,7 +161,7 @@ class NotebookManager(LoggingConfigurable):
|
||||
model = {"name": notebook_name,
|
||||
"path": notebook_path,
|
||||
"last_modified (UTC)": last_modified.ctime()}
|
||||
if content == True:
|
||||
if content is True:
|
||||
model['content'] = contents
|
||||
return model
|
||||
|
||||
@ -196,7 +222,7 @@ class NotebookManager(LoggingConfigurable):
|
||||
nb.metadata.name = name
|
||||
self.write_notebook_object(nb, name, notebook_path, new_name)
|
||||
|
||||
def write_notebook_object(self, nb, notebook_name=None, notebook_path='/', new_name=None):
|
||||
def write_notebook_object(self, nb, notebook_name='/', notebook_path='/', new_name=None):
|
||||
"""Write a notebook object and return its notebook_name.
|
||||
|
||||
If notebook_name is None, this method should create a new notebook_name.
|
||||
|
124
IPython/html/services/tests/test_services_api.py
Normal file
124
IPython/html/services/tests/test_services_api.py
Normal file
@ -0,0 +1,124 @@
|
||||
"""Test the all of the services API."""
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import urllib
|
||||
from zmq.utils import jsonapi
|
||||
|
||||
import requests
|
||||
|
||||
from IPython.html.tests.launchnotebook import NotebookTestBase
|
||||
|
||||
class APITest(NotebookTestBase):
|
||||
"""Test the kernels web service API"""
|
||||
|
||||
def base_url(self):
|
||||
return super(APITest,self).base_url()
|
||||
|
||||
def notebooks_url(self):
|
||||
return self.base_url() + 'api/notebooks'
|
||||
|
||||
def kernels_url(self):
|
||||
return self.base_url() + 'api/kernels'
|
||||
|
||||
def sessions_url(self):
|
||||
return self.base_url() + 'api/sessions'
|
||||
|
||||
def contents_url(self):
|
||||
return self.contents_url() + 'api/contents'
|
||||
|
||||
def mknb(self, name='', path='/'):
|
||||
url = self.notebooks_url() + path
|
||||
return url, requests.post(url)
|
||||
|
||||
def delnb(self, name, path='/'):
|
||||
url = self.notebooks_url() + path + name
|
||||
r = requests.delete(url)
|
||||
return r.status_code
|
||||
|
||||
def test_no_notebooks(self):
|
||||
url = self.notebooks_url()
|
||||
r = requests.get(url)
|
||||
self.assertEqual(r.json(), [])
|
||||
|
||||
def test_root_notebook_handler(self):
|
||||
# POST a notebook and test the dict thats returned.
|
||||
url, nb = self.mknb()
|
||||
data = nb.json()
|
||||
assert isinstance(data, dict)
|
||||
assert data.has_key("name")
|
||||
assert data.has_key("path")
|
||||
self.assertEqual(data['name'], u'Untitled0.ipynb')
|
||||
self.assertEqual(data['path'], u'/')
|
||||
|
||||
# GET list of notebooks in directory.
|
||||
r = requests.get(url)
|
||||
assert isinstance(r.json(), list)
|
||||
assert isinstance(r.json()[0], dict)
|
||||
|
||||
# GET with a notebook name.
|
||||
url = self.notebooks_url() + '/Untitled0.ipynb'
|
||||
r = requests.get(url)
|
||||
assert isinstance(data, dict)
|
||||
self.assertEqual(r.json(), data)
|
||||
|
||||
# PATCH (rename) request.
|
||||
new_name = {'name':'test.ipynb'}
|
||||
r = requests.patch(url, data=jsonapi.dumps(new_name))
|
||||
data = r.json()
|
||||
assert isinstance(data, dict)
|
||||
|
||||
# make sure the patch worked.
|
||||
new_url = self.notebooks_url() + '/test.ipynb'
|
||||
r = requests.get(new_url)
|
||||
assert isinstance(r.json(), dict)
|
||||
self.assertEqual(r.json(), data)
|
||||
|
||||
# GET bad (old) notebook name.
|
||||
r = requests.get(url)
|
||||
self.assertEqual(r.status_code, 404)
|
||||
|
||||
# POST notebooks to folders one and two levels down.
|
||||
os.makedirs(os.path.join(self.notebook_dir.name, 'foo'))
|
||||
os.makedirs(os.path.join(self.notebook_dir.name, 'foo','bar'))
|
||||
url, nb = self.mknb(path='/foo/')
|
||||
url2, nb2 = self.mknb(path='/foo/bar/')
|
||||
data = nb.json()
|
||||
data2 = nb2.json()
|
||||
assert isinstance(data, dict)
|
||||
assert isinstance(data2, dict)
|
||||
assert data.has_key("name")
|
||||
assert data.has_key("path")
|
||||
self.assertEqual(data['name'], u'Untitled0.ipynb')
|
||||
self.assertEqual(data['path'], u'/foo/')
|
||||
assert data2.has_key("name")
|
||||
assert data2.has_key("path")
|
||||
self.assertEqual(data2['name'], u'Untitled0.ipynb')
|
||||
self.assertEqual(data2['path'], u'/foo/bar/')
|
||||
|
||||
# GET request on notebooks one and two levels down.
|
||||
r = requests.get(url+'Untitled0.ipynb')
|
||||
r2 = requests.get(url2+'Untitled0.ipynb')
|
||||
assert isinstance(r.json(), dict)
|
||||
self.assertEqual(r.json(), data)
|
||||
assert isinstance(r2.json(), dict)
|
||||
self.assertEqual(r2.json(), data2)
|
||||
|
||||
# PATCH notebooks that are one and two levels down.
|
||||
new_name = {'name': 'testfoo.ipynb'}
|
||||
r = requests.patch(url+'Untitled0.ipynb', data=jsonapi.dumps(new_name))
|
||||
r = requests.get(url+'testfoo.ipynb')
|
||||
data = r.json()
|
||||
assert isinstance(data, dict)
|
||||
assert data.has_key('name')
|
||||
self.assertEqual(data['name'], 'testfoo.ipynb')
|
||||
r = requests.get(url+'Untitled0.ipynb')
|
||||
self.assertEqual(r.status_code, 404)
|
||||
|
||||
# DELETE notebooks
|
||||
r = self.delnb('testfoo.ipynb', '/foo/')
|
||||
r2 = self.delnb('Untitled0.ipynb', '/foo/bar/')
|
||||
self.assertEqual(r, 204)
|
||||
self.assertEqual(r2, 204)
|
@ -28,6 +28,7 @@ class NotebookTestBase(TestCase):
|
||||
'--ipython-dir=%s' % self.ipython_dir.name,
|
||||
'--notebook-dir=%s' % self.notebook_dir.name
|
||||
]
|
||||
#self.notebook = Popen(notebook_args)
|
||||
self.notebook = Popen(notebook_args, stdout=PIPE, stderr=PIPE)
|
||||
time.sleep(3.0)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user