##// END OF EJS Templates
address PR feedback
address PR feedback

File last commit:

r15623:87f1c23e
r15994:d1ebd1b6
Show More
test_notebooks_api.py
347 lines | 13.3 KiB | text/x-python | PythonLexer
MinRK
unicode normalization in test_notebooks_api
r13091 # coding: utf-8
Zachary Sailer
add tests for session api
r13044 """Test the notebooks webservice API."""
Zachary Sailer
Added notebooks API tests.
r13041
Thomas Kluyver
Improve tests for notebook REST API
r13083 import io
MinRK
copy_from in json, not in url param
r13137 import json
Zachary Sailer
Added notebooks API tests.
r13041 import os
Thomas Kluyver
Improve tests for notebook REST API
r13083 import shutil
MinRK
unicode normalization in test_notebooks_api
r13091 from unicodedata import normalize
Thomas Kluyver
Improve tests for notebook REST API
r13083 pjoin = os.path.join
Zachary Sailer
Added notebooks API tests.
r13041 import requests
MinRK
escape URLs in Location headers
r13132 from IPython.html.utils import url_path_join, url_escape
Thomas Kluyver
Add failing test for listing nonexistant directory
r13099 from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error
MinRK
test upload of v2 notebooks
r13141 from IPython.nbformat import current
Thomas Kluyver
Add test for saving notebook via REST API
r13085 from IPython.nbformat.current import (new_notebook, write, read, new_worksheet,
new_heading_cell, to_notebook_json)
MinRK
test upload of v2 notebooks
r13141 from IPython.nbformat import v2
MinRK
update notebook api tests...
r13130 from IPython.utils import py3compat
Thomas Kluyver
Improve tests for notebook REST API
r13083 from IPython.utils.data import uniq_stable
MinRK
update notebook api tests...
r13130
Brian E. Granger
Get the existing tests working.
r15079 # TODO: Remove this after we create the contents web service and directories are
# no longer listed by the notebook web service.
def notebooks_only(nb_list):
Brian E. Granger
Addressing review comments....
r15093 return [nb for nb in nb_list if nb['type']=='notebook']
Brian E. Granger
Get the existing tests working.
r15079
Thomas Kluyver
Hide directories beginning with _ from the dashboard....
r15522 def dirs_only(nb_list):
return [x for x in nb_list if x['type']=='directory']
Brian E. Granger
Get the existing tests working.
r15079
Thomas Kluyver
Improve tests for notebook REST API
r13083 class NBAPI(object):
"""Wrapper for notebook API calls."""
def __init__(self, base_url):
self.base_url = base_url
MinRK
copy_from in json, not in url param
r13137 def _req(self, verb, path, body=None):
Thomas Kluyver
Improve tests for notebook REST API
r13083 response = requests.request(verb,
MinRK
update notebook api tests...
r13130 url_path_join(self.base_url, 'api/notebooks', path),
data=body,
)
Thomas Kluyver
Improve tests for notebook REST API
r13083 response.raise_for_status()
return response
def list(self, path='/'):
return self._req('GET', path)
def read(self, name, path='/'):
return self._req('GET', url_path_join(path, name))
def create_untitled(self, path='/'):
return self._req('POST', path)
MinRK
update notebook api tests...
r13130 def upload_untitled(self, body, path='/'):
return self._req('POST', path, body)
def copy_untitled(self, copy_from, path='/'):
MinRK
copy_from in json, not in url param
r13137 body = json.dumps({'copy_from':copy_from})
return self._req('POST', path, body)
MinRK
update notebook api tests...
r13130
def create(self, name, path='/'):
return self._req('PUT', url_path_join(path, name))
Thomas Kluyver
Add test for REST API uploading notebook
r13084 def upload(self, name, body, path='/'):
MinRK
update notebook api tests...
r13130 return self._req('PUT', url_path_join(path, name), body)
Thomas Kluyver
Add test for REST API uploading notebook
r13084
MinRK
update notebook api tests...
r13130 def copy(self, copy_from, copy_to, path='/'):
MinRK
copy_from in json, not in url param
r13137 body = json.dumps({'copy_from':copy_from})
return self._req('PUT', url_path_join(path, copy_to), body)
Thomas Kluyver
Add test for copying notebook through REST API
r13086
Thomas Kluyver
Add test for saving notebook via REST API
r13085 def save(self, name, body, path='/'):
return self._req('PUT', url_path_join(path, name), body)
Thomas Kluyver
Improve tests for notebook REST API
r13083 def delete(self, name, path='/'):
return self._req('DELETE', url_path_join(path, name))
def rename(self, name, path, new_name):
MinRK
don't use jsonapi in test_notebook_api
r13138 body = json.dumps({'name': new_name})
Thomas Kluyver
Improve tests for notebook REST API
r13083 return self._req('PATCH', url_path_join(path, name), body)
Zachary Sailer
Added notebooks API tests.
r13041
Thomas Kluyver
Test notebook checkpoint APIs
r13109 def get_checkpoints(self, name, path):
return self._req('GET', url_path_join(path, name, 'checkpoints'))
def new_checkpoint(self, name, path):
return self._req('POST', url_path_join(path, name, 'checkpoints'))
def restore_checkpoint(self, name, path, checkpoint_id):
return self._req('POST', url_path_join(path, name, 'checkpoints', checkpoint_id))
def delete_checkpoint(self, name, path, checkpoint_id):
return self._req('DELETE', url_path_join(path, name, 'checkpoints', checkpoint_id))
Zachary Sailer
Added notebooks API tests.
r13041 class APITest(NotebookTestBase):
"""Test the kernels web service API"""
Thomas Kluyver
Improve tests for notebook REST API
r13083 dirs_nbs = [('', 'inroot'),
('Directory with spaces in', 'inspace'),
(u'unicodé', 'innonascii'),
('foo', 'a'),
('foo', 'b'),
('foo', 'name with spaces'),
('foo', u'unicodé'),
('foo/bar', 'baz'),
Thomas Kluyver
Case insensitive sorting in the dashboard....
r15523 ('ordering', 'A'),
('ordering', 'b'),
('ordering', 'C'),
(u'å b', u'ç d'),
Thomas Kluyver
Improve tests for notebook REST API
r13083 ]
Thomas Kluyver
Hide directories beginning with _ from the dashboard....
r15522 hidden_dirs = ['.hidden', '__pycache__']
Thomas Kluyver
Improve tests for notebook REST API
r13083
MinRK
normalize unicode in notebook API tests...
r15623 dirs = uniq_stable([py3compat.cast_unicode(d) for (d,n) in dirs_nbs])
Thomas Kluyver
Improve tests for notebook REST API
r13083 del dirs[0] # remove ''
MinRK
normalize unicode in notebook API tests...
r15623 top_level_dirs = {normalize('NFC', d.split('/')[0]) for d in dirs}
Thomas Kluyver
Improve tests for notebook REST API
r13083
def setUp(self):
nbdir = self.notebook_dir.name
Thomas Kluyver
Add test for REST API uploading notebook
r13084
Thomas Kluyver
Hide directories beginning with _ from the dashboard....
r15522 for d in (self.dirs + self.hidden_dirs):
MinRK
s/os.path.sep/os.sep/
r13182 d.replace('/', os.sep)
MinRK
update notebook api tests...
r13130 if not os.path.isdir(pjoin(nbdir, d)):
os.mkdir(pjoin(nbdir, d))
Thomas Kluyver
Improve tests for notebook REST API
r13083
for d, name in self.dirs_nbs:
MinRK
s/os.path.sep/os.sep/
r13182 d = d.replace('/', os.sep)
Thomas Kluyver
Specify encoding in remainining instances of io.open
r13657 with io.open(pjoin(nbdir, d, '%s.ipynb' % name), 'w',
encoding='utf-8') as f:
Thomas Kluyver
Improve tests for notebook REST API
r13083 nb = new_notebook(name=name)
write(nb, f, format='ipynb')
self.nb_api = NBAPI(self.base_url())
def tearDown(self):
nbdir = self.notebook_dir.name
Thomas Kluyver
Hide directories beginning with _ from the dashboard....
r15522 for dname in (list(self.top_level_dirs) + self.hidden_dirs):
Thomas Kluyver
Improve tests for notebook REST API
r13083 shutil.rmtree(pjoin(nbdir, dname), ignore_errors=True)
if os.path.isfile(pjoin(nbdir, 'inroot.ipynb')):
os.unlink(pjoin(nbdir, 'inroot.ipynb'))
def test_list_notebooks(self):
Brian E. Granger
Get the existing tests working.
r15079 nbs = notebooks_only(self.nb_api.list().json())
Thomas Kluyver
Improve tests for notebook REST API
r13083 self.assertEqual(len(nbs), 1)
self.assertEqual(nbs[0]['name'], 'inroot.ipynb')
Brian E. Granger
Get the existing tests working.
r15079 nbs = notebooks_only(self.nb_api.list('/Directory with spaces in/').json())
Thomas Kluyver
Improve tests for notebook REST API
r13083 self.assertEqual(len(nbs), 1)
self.assertEqual(nbs[0]['name'], 'inspace.ipynb')
Brian E. Granger
Get the existing tests working.
r15079 nbs = notebooks_only(self.nb_api.list(u'/unicodé/').json())
Thomas Kluyver
Improve tests for notebook REST API
r13083 self.assertEqual(len(nbs), 1)
self.assertEqual(nbs[0]['name'], 'innonascii.ipynb')
MinRK
update notebook api tests...
r13130 self.assertEqual(nbs[0]['path'], u'unicodé')
Thomas Kluyver
Improve tests for notebook REST API
r13083
Brian E. Granger
Get the existing tests working.
r15079 nbs = notebooks_only(self.nb_api.list('/foo/bar/').json())
Thomas Kluyver
Improve tests for notebook REST API
r13083 self.assertEqual(len(nbs), 1)
self.assertEqual(nbs[0]['name'], 'baz.ipynb')
MinRK
update notebook api tests...
r13130 self.assertEqual(nbs[0]['path'], 'foo/bar')
Thomas Kluyver
Improve tests for notebook REST API
r13083
Brian E. Granger
Get the existing tests working.
r15079 nbs = notebooks_only(self.nb_api.list('foo').json())
Thomas Kluyver
Improve tests for notebook REST API
r13083 self.assertEqual(len(nbs), 4)
MinRK
unicode normalization in test_notebooks_api
r13091 nbnames = { normalize('NFC', n['name']) for n in nbs }
expected = [ u'a.ipynb', u'b.ipynb', u'name with spaces.ipynb', u'unicodé.ipynb']
expected = { normalize('NFC', name) for name in expected }
self.assertEqual(nbnames, expected)
Thomas Kluyver
Case insensitive sorting in the dashboard....
r15523
nbs = notebooks_only(self.nb_api.list('ordering').json())
nbnames = [n['name'] for n in nbs]
expected = ['A.ipynb', 'b.ipynb', 'C.ipynb']
self.assertEqual(nbnames, expected)
Thomas Kluyver
Improve tests for notebook REST API
r13083
Thomas Kluyver
Hide directories beginning with _ from the dashboard....
r15522 def test_list_dirs(self):
dirs = dirs_only(self.nb_api.list().json())
MinRK
normalize unicode in notebook API tests...
r15623 dir_names = {normalize('NFC', d['name']) for d in dirs}
Thomas Kluyver
Hide directories beginning with _ from the dashboard....
r15522 self.assertEqual(dir_names, self.top_level_dirs) # Excluding hidden dirs
Thomas Kluyver
Add failing test for listing nonexistant directory
r13099 def test_list_nonexistant_dir(self):
with assert_http_error(404):
self.nb_api.list('nonexistant')
Thomas Kluyver
Add test for and fix REST save with rename
r13087
Thomas Kluyver
Improve tests for notebook REST API
r13083 def test_get_contents(self):
for d, name in self.dirs_nbs:
nb = self.nb_api.read('%s.ipynb' % name, d+'/').json()
MinRK
update notebook api tests...
r13130 self.assertEqual(nb['name'], u'%s.ipynb' % name)
Thomas Kluyver
Improve tests for notebook REST API
r13083 self.assertIn('content', nb)
self.assertIn('metadata', nb['content'])
self.assertIsInstance(nb['content']['metadata'], dict)
# Name that doesn't exist - should be a 404
Thomas Kluyver
Add failing test for listing nonexistant directory
r13099 with assert_http_error(404):
self.nb_api.read('q.ipynb', 'foo')
Thomas Kluyver
Improve tests for notebook REST API
r13083
def _check_nb_created(self, resp, name, path):
Thomas Kluyver
Add test for REST API uploading notebook
r13084 self.assertEqual(resp.status_code, 201)
MinRK
update notebook api tests...
r13130 location_header = py3compat.str_to_unicode(resp.headers['Location'])
MinRK
escape URLs in Location headers
r13132 self.assertEqual(location_header, url_escape(url_path_join(u'/api/notebooks', path, name)))
Thomas Kluyver
Improve tests for notebook REST API
r13083 self.assertEqual(resp.json()['name'], name)
MinRK
Windows testing fixes
r13178 assert os.path.isfile(pjoin(
self.notebook_dir.name,
MinRK
s/os.path.sep/os.sep/
r13182 path.replace('/', os.sep),
MinRK
Windows testing fixes
r13178 name,
))
Thomas Kluyver
Improve tests for notebook REST API
r13083
def test_create_untitled(self):
MinRK
update notebook api tests...
r13130 resp = self.nb_api.create_untitled(path=u'Ã¥ b')
self._check_nb_created(resp, 'Untitled0.ipynb', u'Ã¥ b')
Thomas Kluyver
Improve tests for notebook REST API
r13083
# Second time
MinRK
update notebook api tests...
r13130 resp = self.nb_api.create_untitled(path=u'Ã¥ b')
self._check_nb_created(resp, 'Untitled1.ipynb', u'Ã¥ b')
Thomas Kluyver
Improve tests for notebook REST API
r13083
# And two directories down
resp = self.nb_api.create_untitled(path='foo/bar')
MinRK
Windows testing fixes
r13178 self._check_nb_created(resp, 'Untitled0.ipynb', 'foo/bar')
Thomas Kluyver
Improve tests for notebook REST API
r13083
MinRK
update notebook api tests...
r13130 def test_upload_untitled(self):
Thomas Kluyver
Add test for REST API uploading notebook
r13084 nb = new_notebook(name='Upload test')
Thomas Kluyver
Add test for saving notebook via REST API
r13085 nbmodel = {'content': nb}
MinRK
update notebook api tests...
r13130 resp = self.nb_api.upload_untitled(path=u'Ã¥ b',
MinRK
don't use jsonapi in test_notebook_api
r13138 body=json.dumps(nbmodel))
MinRK
escape URLs in Location headers
r13132 self._check_nb_created(resp, 'Untitled0.ipynb', u'Ã¥ b')
MinRK
update notebook api tests...
r13130
def test_upload(self):
nb = new_notebook(name=u'ignored')
nbmodel = {'content': nb}
resp = self.nb_api.upload(u'Upload tést.ipynb', path=u'å b',
MinRK
don't use jsonapi in test_notebook_api
r13138 body=json.dumps(nbmodel))
MinRK
update notebook api tests...
r13130 self._check_nb_created(resp, u'Upload tést.ipynb', u'å b')
MinRK
test upload of v2 notebooks
r13141 def test_upload_v2(self):
nb = v2.new_notebook()
ws = v2.new_worksheet()
nb.worksheets.append(ws)
ws.cells.append(v2.new_code_cell(input='print("hi")'))
nbmodel = {'content': nb}
resp = self.nb_api.upload(u'Upload tést.ipynb', path=u'å b',
body=json.dumps(nbmodel))
self._check_nb_created(resp, u'Upload tést.ipynb', u'å b')
resp = self.nb_api.read(u'Upload tést.ipynb', u'å b')
data = resp.json()
self.assertEqual(data['content']['nbformat'], current.nbformat)
self.assertEqual(data['content']['orig_nbformat'], 2)
MinRK
update notebook api tests...
r13130 def test_copy_untitled(self):
resp = self.nb_api.copy_untitled(u'ç d.ipynb', path=u'å b')
self._check_nb_created(resp, u'ç d-Copy0.ipynb', u'å b')
Thomas Kluyver
Add test for REST API uploading notebook
r13084
Thomas Kluyver
Add test for copying notebook through REST API
r13086 def test_copy(self):
MinRK
update notebook api tests...
r13130 resp = self.nb_api.copy(u'ç d.ipynb', u'cøpy.ipynb', path=u'å b')
self._check_nb_created(resp, u'cøpy.ipynb', u'å b')
Thomas Kluyver
Add test for copying notebook through REST API
r13086
Thomas Kluyver
Improve tests for notebook REST API
r13083 def test_delete(self):
for d, name in self.dirs_nbs:
resp = self.nb_api.delete('%s.ipynb' % name, d)
self.assertEqual(resp.status_code, 204)
for d in self.dirs + ['/']:
Brian E. Granger
Get the existing tests working.
r15079 nbs = notebooks_only(self.nb_api.list(d).json())
Thomas Kluyver
Improve tests for notebook REST API
r13083 self.assertEqual(len(nbs), 0)
def test_rename(self):
resp = self.nb_api.rename('a.ipynb', 'foo', 'z.ipynb')
Thomas Kluyver
Check Location header from renaming notebook
r13089 self.assertEqual(resp.headers['Location'].split('/')[-1], 'z.ipynb')
Thomas Kluyver
Improve tests for notebook REST API
r13083 self.assertEqual(resp.json()['name'], 'z.ipynb')
assert os.path.isfile(pjoin(self.notebook_dir.name, 'foo', 'z.ipynb'))
Brian E. Granger
Get the existing tests working.
r15079 nbs = notebooks_only(self.nb_api.list('foo').json())
Thomas Kluyver
Improve tests for notebook REST API
r13083 nbnames = set(n['name'] for n in nbs)
self.assertIn('z.ipynb', nbnames)
self.assertNotIn('a.ipynb', nbnames)
Thomas Kluyver
Add test for saving notebook via REST API
r13085
MinRK
test that rename fails with 409 if it would clobber...
r13710 def test_rename_existing(self):
with assert_http_error(409):
self.nb_api.rename('a.ipynb', 'foo', 'b.ipynb')
Thomas Kluyver
Add test for saving notebook via REST API
r13085 def test_save(self):
resp = self.nb_api.read('a.ipynb', 'foo')
MinRK
don't use jsonapi in test_notebook_api
r13138 nbcontent = json.loads(resp.text)['content']
Thomas Kluyver
Add test for saving notebook via REST API
r13085 nb = to_notebook_json(nbcontent)
ws = new_worksheet()
nb.worksheets = [ws]
Thomas Kluyver
Add some unicode testing for saving notebooks
r13111 ws.cells.append(new_heading_cell(u'Created by test ³'))
Thomas Kluyver
Add test for saving notebook via REST API
r13085
nbmodel= {'name': 'a.ipynb', 'path':'foo', 'content': nb}
MinRK
don't use jsonapi in test_notebook_api
r13138 resp = self.nb_api.save('a.ipynb', path='foo', body=json.dumps(nbmodel))
Thomas Kluyver
Add test for saving notebook via REST API
r13085
nbfile = pjoin(self.notebook_dir.name, 'foo', 'a.ipynb')
Thomas Kluyver
Add some unicode testing for saving notebooks
r13111 with io.open(nbfile, 'r', encoding='utf-8') as f:
Thomas Kluyver
Add test for saving notebook via REST API
r13085 newnb = read(f, format='ipynb')
self.assertEqual(newnb.worksheets[0].cells[0].source,
Thomas Kluyver
Add some unicode testing for saving notebooks
r13111 u'Created by test ³')
nbcontent = self.nb_api.read('a.ipynb', 'foo').json()['content']
newnb = to_notebook_json(nbcontent)
self.assertEqual(newnb.worksheets[0].cells[0].source,
u'Created by test ³')
Thomas Kluyver
Add test for and fix REST save with rename
r13087
# Save and rename
nbmodel= {'name': 'a2.ipynb', 'path':'foo/bar', 'content': nb}
MinRK
don't use jsonapi in test_notebook_api
r13138 resp = self.nb_api.save('a.ipynb', path='foo', body=json.dumps(nbmodel))
Thomas Kluyver
Add test for and fix REST save with rename
r13087 saved = resp.json()
self.assertEqual(saved['name'], 'a2.ipynb')
self.assertEqual(saved['path'], 'foo/bar')
assert os.path.isfile(pjoin(self.notebook_dir.name,'foo','bar','a2.ipynb'))
assert not os.path.isfile(pjoin(self.notebook_dir.name, 'foo', 'a.ipynb'))
Thomas Kluyver
Add failing test for listing nonexistant directory
r13099 with assert_http_error(404):
Thomas Kluyver
Test notebook checkpoint APIs
r13109 self.nb_api.read('a.ipynb', 'foo')
def test_checkpoints(self):
resp = self.nb_api.read('a.ipynb', 'foo')
r = self.nb_api.new_checkpoint('a.ipynb', 'foo')
self.assertEqual(r.status_code, 201)
cp1 = r.json()
MinRK
use 'id' for checkpoint ID key...
r13122 self.assertEqual(set(cp1), {'id', 'last_modified'})
self.assertEqual(r.headers['Location'].split('/')[-1], cp1['id'])
Thomas Kluyver
Test notebook checkpoint APIs
r13109
# Modify it
MinRK
don't use jsonapi in test_notebook_api
r13138 nbcontent = json.loads(resp.text)['content']
Thomas Kluyver
Test notebook checkpoint APIs
r13109 nb = to_notebook_json(nbcontent)
ws = new_worksheet()
nb.worksheets = [ws]
hcell = new_heading_cell('Created by test')
ws.cells.append(hcell)
# Save
nbmodel= {'name': 'a.ipynb', 'path':'foo', 'content': nb}
MinRK
don't use jsonapi in test_notebook_api
r13138 resp = self.nb_api.save('a.ipynb', path='foo', body=json.dumps(nbmodel))
Thomas Kluyver
Test notebook checkpoint APIs
r13109
# List checkpoints
cps = self.nb_api.get_checkpoints('a.ipynb', 'foo').json()
self.assertEqual(cps, [cp1])
nbcontent = self.nb_api.read('a.ipynb', 'foo').json()['content']
nb = to_notebook_json(nbcontent)
self.assertEqual(nb.worksheets[0].cells[0].source, 'Created by test')
# Restore cp1
MinRK
use 'id' for checkpoint ID key...
r13122 r = self.nb_api.restore_checkpoint('a.ipynb', 'foo', cp1['id'])
Thomas Kluyver
Test notebook checkpoint APIs
r13109 self.assertEqual(r.status_code, 204)
nbcontent = self.nb_api.read('a.ipynb', 'foo').json()['content']
nb = to_notebook_json(nbcontent)
self.assertEqual(nb.worksheets, [])
# Delete cp1
MinRK
use 'id' for checkpoint ID key...
r13122 r = self.nb_api.delete_checkpoint('a.ipynb', 'foo', cp1['id'])
Thomas Kluyver
Test notebook checkpoint APIs
r13109 self.assertEqual(r.status_code, 204)
cps = self.nb_api.get_checkpoints('a.ipynb', 'foo').json()
self.assertEqual(cps, [])
MinRK
test /files/ gives 403 on hidden files
r13175