##// END OF EJS Templates
move utils.io.atomic_writing to contents.fileio
move utils.io.atomic_writing to contents.fileio

File last commit:

r20785:ffe9ef65
r21113:348b2930
Show More
test_contents_api.py
687 lines | 24.2 KiB | text/x-python | PythonLexer
MinRK
unicode normalization in test_notebooks_api
r13091 # coding: utf-8
MinRK
rename notebooks service to contents service...
r17524 """Test the contents webservice API."""
Zachary Sailer
Added notebooks API tests.
r13041
MinRK
teach contents service about non-notebook files
r17525 import base64
Scott Sanderson
TEST: Test separate roots for Contents and Checkpoints.
r19748 from contextlib import contextmanager
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
Scott Sanderson
STY: s/CheckpointManager/Checkpoints...
r19839 from ..filecheckpoints import GenericFileCheckpoints
Scott Sanderson
DEV: Separate FileCheckpointManager and GenericFileCheckpointManager....
r19838
from IPython.config import Config
Min RK
abstract some methods in contents service tests...
r19604 from IPython.html.utils import url_path_join, url_escape, to_os_path
Thomas Kluyver
Add failing test for listing nonexistant directory
r13099 from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error
MinRK
don't use nbformat.current in IPython.html...
r18607 from IPython.nbformat import read, write, from_dict
from IPython.nbformat.v4 import (
new_notebook, new_markdown_cell,
)
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
Scott Sanderson
TEST: Test separate roots for Contents and Checkpoints.
r19748 from IPython.utils.tempdir import TemporaryDirectory
Thomas Kluyver
Improve tests for notebook REST API
r13083
MinRK
update notebook api tests...
r13130
MinRK
teach contents service about non-notebook files
r17525 def notebooks_only(dir_model):
return [nb for nb in dir_model['content'] if nb['type']=='notebook']
Brian E. Granger
Get the existing tests working.
r15079
MinRK
teach contents service about non-notebook files
r17525 def dirs_only(dir_model):
return [x for x in dir_model['content'] if x['type']=='directory']
Thomas Kluyver
Hide directories beginning with _ from the dashboard....
r15522
Brian E. Granger
Get the existing tests working.
r15079
MinRK
rename notebooks service to contents service...
r17524 class API(object):
"""Wrapper for contents API calls."""
Thomas Kluyver
Improve tests for notebook REST API
r13083 def __init__(self, base_url):
self.base_url = base_url
Thomas Kluyver
Fix various review comments
r18790 def _req(self, verb, path, body=None, params=None):
Thomas Kluyver
Improve tests for notebook REST API
r13083 response = requests.request(verb,
MinRK
rename notebooks service to contents service...
r17524 url_path_join(self.base_url, 'api/contents', path),
Thomas Kluyver
Actually pass URL params with API request
r18795 data=body, params=params,
MinRK
update notebook api tests...
r13130 )
Thomas Kluyver
Improve tests for notebook REST API
r13083 response.raise_for_status()
return response
def list(self, path='/'):
return self._req('GET', path)
Min RK
allow requesting contents without body...
r20134 def read(self, path, type=None, format=None, content=None):
Thomas Kluyver
Fix various review comments
r18790 params = {}
Min RK
ContentsManager type kwarg to match model key...
r19391 if type is not None:
params['type'] = type
Thomas Kluyver
Allow specifying format when getting files from contents API
r18788 if format is not None:
Thomas Kluyver
Fix various review comments
r18790 params['format'] = format
Min RK
allow requesting contents without body...
r20134 if content == False:
params['content'] = '0'
Thomas Kluyver
Fix various review comments
r18790 return self._req('GET', path, params=params)
Thomas Kluyver
Improve tests for notebook REST API
r13083
Min RK
split ContentsManager.new, add ContentsManager.new_untitled
r18759 def create_untitled(self, path='/', ext='.ipynb'):
MinRK
add support and tests for uploading and saving regular files
r17527 body = None
if ext:
body = json.dumps({'ext': ext})
return self._req('POST', path, body)
Thomas Kluyver
Improve tests for notebook REST API
r13083
Min RK
address review in contents service...
r18758 def mkdir_untitled(self, path='/'):
return self._req('POST', path, json.dumps({'type': 'directory'}))
Min RK
remove copy via PUT...
r18750 def copy(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
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 def create(self, path='/'):
return self._req('PUT', path)
MinRK
update notebook api tests...
r13130
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 def upload(self, path, body):
return self._req('PUT', path, body)
Thomas Kluyver
Add test for REST API uploading notebook
r13084
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 def mkdir(self, path='/'):
return self._req('PUT', path, json.dumps({'type': 'directory'}))
MinRK
support deleting empty directories...
r17530
Min RK
remove copy via PUT...
r18750 def copy_put(self, copy_from, path='/'):
MinRK
copy_from in json, not in url param
r13137 body = json.dumps({'copy_from':copy_from})
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 return self._req('PUT', path, body)
Thomas Kluyver
Add test for copying notebook through REST API
r13086
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 def save(self, path, body):
return self._req('PUT', path, body)
Thomas Kluyver
Add test for saving notebook via REST API
r13085
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 def delete(self, path='/'):
return self._req('DELETE', path)
Thomas Kluyver
Improve tests for notebook REST API
r13083
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 def rename(self, path, new_path):
body = json.dumps({'path': new_path})
return self._req('PATCH', path, body)
Zachary Sailer
Added notebooks API tests.
r13041
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 def get_checkpoints(self, path):
return self._req('GET', url_path_join(path, 'checkpoints'))
Thomas Kluyver
Test notebook checkpoint APIs
r13109
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 def new_checkpoint(self, path):
return self._req('POST', url_path_join(path, 'checkpoints'))
Thomas Kluyver
Test notebook checkpoint APIs
r13109
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 def restore_checkpoint(self, path, checkpoint_id):
return self._req('POST', url_path_join(path, 'checkpoints', checkpoint_id))
Thomas Kluyver
Test notebook checkpoint APIs
r13109
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 def delete_checkpoint(self, path, checkpoint_id):
return self._req('DELETE', url_path_join(path, 'checkpoints', checkpoint_id))
Thomas Kluyver
Test notebook checkpoint APIs
r13109
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
Scott Sanderson
STY: Define dirs as a single expression.
r19617 # Don't include root dir.
dirs = uniq_stable([py3compat.cast_unicode(d) for (d,n) in dirs_nbs[1:]])
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
MinRK
teach contents service about non-notebook files
r17525 @staticmethod
def _blob_for_name(name):
return name.encode('utf-8') + b'\xFF'
@staticmethod
def _txt_for_name(name):
return u'%s text file' % name
Min RK
abstract some methods in contents service tests...
r19604
def to_os_path(self, api_path):
return to_os_path(api_path, root=self.notebook_dir.name)
def make_dir(self, api_path):
"""Create a directory at api_path"""
os_path = self.to_os_path(api_path)
try:
os.makedirs(os_path)
except OSError:
print("Directory already exists: %r" % os_path)
Scott Sanderson
TEST: Abstract out directory/file deletion methods.
r19613
Min RK
abstract some methods in contents service tests...
r19604 def make_txt(self, api_path, txt):
"""Make a text file at a given api_path"""
os_path = self.to_os_path(api_path)
with io.open(os_path, 'w', encoding='utf-8') as f:
f.write(txt)
def make_blob(self, api_path, blob):
"""Make a binary file at a given api_path"""
os_path = self.to_os_path(api_path)
with io.open(os_path, 'wb') as f:
f.write(blob)
def make_nb(self, api_path, nb):
"""Make a notebook file at a given api_path"""
os_path = self.to_os_path(api_path)
with io.open(os_path, 'w', encoding='utf-8') as f:
write(nb, f, version=4)
Scott Sanderson
TEST: Abstract out directory/file deletion methods.
r19613
def delete_dir(self, api_path):
"""Delete a directory at api_path, removing any contents."""
os_path = self.to_os_path(api_path)
shutil.rmtree(os_path, ignore_errors=True)
def delete_file(self, api_path):
"""Delete a file at the given path if it exists."""
if self.isfile(api_path):
os.unlink(self.to_os_path(api_path))
Min RK
abstract some methods in contents service tests...
r19604
def isfile(self, api_path):
return os.path.isfile(self.to_os_path(api_path))
def isdir(self, api_path):
return os.path.isdir(self.to_os_path(api_path))
Thomas Kluyver
Improve tests for notebook REST API
r13083 def setUp(self):
MinRK
teach contents service about non-notebook files
r17525
Thomas Kluyver
Hide directories beginning with _ from the dashboard....
r15522 for d in (self.dirs + self.hidden_dirs):
Min RK
abstract some methods in contents service tests...
r19604 self.make_dir(d)
Thomas Kluyver
Improve tests for notebook REST API
r13083
for d, name in self.dirs_nbs:
MinRK
teach contents service about non-notebook files
r17525 # create a notebook
Min RK
abstract some methods in contents service tests...
r19604 nb = new_notebook()
self.make_nb(u'{}/{}.ipynb'.format(d, name), nb)
MinRK
teach contents service about non-notebook files
r17525 # create a text file
Min RK
abstract some methods in contents service tests...
r19604 txt = self._txt_for_name(name)
self.make_txt(u'{}/{}.txt'.format(d, name), txt)
MinRK
teach contents service about non-notebook files
r17525 # create a binary file
Min RK
abstract some methods in contents service tests...
r19604 blob = self._blob_for_name(name)
self.make_blob(u'{}/{}.blob'.format(d, name), blob)
MinRK
teach contents service about non-notebook files
r17525
MinRK
rename notebooks service to contents service...
r17524 self.api = API(self.base_url())
Thomas Kluyver
Improve tests for notebook REST API
r13083
def tearDown(self):
Thomas Kluyver
Hide directories beginning with _ from the dashboard....
r15522 for dname in (list(self.top_level_dirs) + self.hidden_dirs):
Scott Sanderson
TEST: Abstract out directory/file deletion methods.
r19613 self.delete_dir(dname)
self.delete_file('inroot.ipynb')
Thomas Kluyver
Improve tests for notebook REST API
r13083
def test_list_notebooks(self):
MinRK
rename notebooks service to contents service...
r17524 nbs = notebooks_only(self.api.list().json())
Thomas Kluyver
Improve tests for notebook REST API
r13083 self.assertEqual(len(nbs), 1)
self.assertEqual(nbs[0]['name'], 'inroot.ipynb')
MinRK
rename notebooks service to contents service...
r17524 nbs = notebooks_only(self.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')
MinRK
rename notebooks service to contents service...
r17524 nbs = notebooks_only(self.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
Remove separate 'path', 'name' in Contents API...
r18749 self.assertEqual(nbs[0]['path'], u'unicodé/innonascii.ipynb')
Thomas Kluyver
Improve tests for notebook REST API
r13083
MinRK
rename notebooks service to contents service...
r17524 nbs = notebooks_only(self.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
Remove separate 'path', 'name' in Contents API...
r18749 self.assertEqual(nbs[0]['path'], 'foo/bar/baz.ipynb')
Thomas Kluyver
Improve tests for notebook REST API
r13083
MinRK
rename notebooks service to contents service...
r17524 nbs = notebooks_only(self.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)
MinRK
mv services/notebooks services/contents
r17523
MinRK
rename notebooks service to contents service...
r17524 nbs = notebooks_only(self.api.list('ordering').json())
Thomas Kluyver
Case insensitive sorting in the dashboard....
r15523 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):
MinRK
rename notebooks service to contents service...
r17524 dirs = dirs_only(self.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
Min RK
allow requesting contents without body...
r20134 def test_get_dir_no_content(self):
for d in self.dirs:
model = self.api.read(d, content=False).json()
self.assertEqual(model['path'], d)
self.assertEqual(model['type'], 'directory')
self.assertIn('content', model)
self.assertEqual(model['content'], None)
Thomas Kluyver
Add failing test for listing nonexistant directory
r13099 def test_list_nonexistant_dir(self):
with assert_http_error(404):
MinRK
rename notebooks service to contents service...
r17524 self.api.list('nonexistant')
Thomas Kluyver
Add test for and fix REST save with rename
r13087
MinRK
teach contents service about non-notebook files
r17525 def test_get_nb_contents(self):
Thomas Kluyver
Improve tests for notebook REST API
r13083 for d, name in self.dirs_nbs:
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 path = url_path_join(d, name + '.ipynb')
nb = self.api.read(path).json()
MinRK
update notebook api tests...
r13130 self.assertEqual(nb['name'], u'%s.ipynb' % name)
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 self.assertEqual(nb['path'], path)
MinRK
teach contents service about non-notebook files
r17525 self.assertEqual(nb['type'], 'notebook')
self.assertIn('content', nb)
self.assertEqual(nb['format'], 'json')
Thomas Kluyver
Improve tests for notebook REST API
r13083 self.assertIn('metadata', nb['content'])
self.assertIsInstance(nb['content']['metadata'], dict)
Min RK
allow requesting contents without body...
r20134 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)
MinRK
teach contents service about non-notebook files
r17525 def test_get_contents_no_such_file(self):
Thomas Kluyver
Improve tests for notebook REST API
r13083 # Name that doesn't exist - should be a 404
Thomas Kluyver
Add failing test for listing nonexistant directory
r13099 with assert_http_error(404):
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 self.api.read('foo/q.ipynb')
Thomas Kluyver
Improve tests for notebook REST API
r13083
MinRK
teach contents service about non-notebook files
r17525 def test_get_text_file_contents(self):
for d, name in self.dirs_nbs:
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 path = url_path_join(d, name + '.txt')
model = self.api.read(path).json()
MinRK
teach contents service about non-notebook files
r17525 self.assertEqual(model['name'], u'%s.txt' % name)
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 self.assertEqual(model['path'], path)
MinRK
teach contents service about non-notebook files
r17525 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):
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 self.api.read('foo/q.txt')
MinRK
teach contents service about non-notebook files
r17525
Thomas Kluyver
Allow specifying format when getting files from contents API
r18788 # Specifying format=text should fail on a non-UTF-8 file
with assert_http_error(400):
Min RK
ContentsManager type kwarg to match model key...
r19391 self.api.read('foo/bar/baz.blob', type='file', format='text')
Thomas Kluyver
Allow specifying format when getting files from contents API
r18788
MinRK
teach contents service about non-notebook files
r17525 def test_get_binary_file_contents(self):
for d, name in self.dirs_nbs:
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 path = url_path_join(d, name + '.blob')
model = self.api.read(path).json()
MinRK
teach contents service about non-notebook files
r17525 self.assertEqual(model['name'], u'%s.blob' % name)
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 self.assertEqual(model['path'], path)
MinRK
teach contents service about non-notebook files
r17525 self.assertIn('content', model)
self.assertEqual(model['format'], 'base64')
self.assertEqual(model['type'], 'file')
Scott Sanderson
TEST: Verify base64 return values after decoding.
r19615 self.assertEqual(
Scott Sanderson
BUG: Convert to bytes before comparing binary blobs.
r19616 base64.decodestring(model['content'].encode('ascii')),
Scott Sanderson
TEST: Verify base64 return values after decoding.
r19615 self._blob_for_name(name),
)
MinRK
teach contents service about non-notebook files
r17525
# Name that doesn't exist - should be a 404
with assert_http_error(404):
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 self.api.read('foo/q.txt')
MinRK
teach contents service about non-notebook files
r17525
Thomas Kluyver
Add type parameter for contents GET requests
r18781 def test_get_bad_type(self):
with assert_http_error(400):
Min RK
ContentsManager type kwarg to match model key...
r19391 self.api.read(u'unicodé', type='file') # this is a directory
Thomas Kluyver
Add type parameter for contents GET requests
r18781
with assert_http_error(400):
Min RK
ContentsManager type kwarg to match model key...
r19391 self.api.read(u'unicodé/innonascii.ipynb', type='directory')
Thomas Kluyver
Add type parameter for contents GET requests
r18781
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 def _check_created(self, resp, path, type='notebook'):
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
Remove separate 'path', 'name' in Contents API...
r18749 self.assertEqual(location_header, url_escape(url_path_join(u'/api/contents', path)))
MinRK
test creating a directory with PUT
r17528 rjson = resp.json()
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 self.assertEqual(rjson['name'], path.rsplit('/', 1)[-1])
MinRK
test creating a directory with PUT
r17528 self.assertEqual(rjson['path'], path)
self.assertEqual(rjson['type'], type)
Min RK
abstract some methods in contents service tests...
r19604 isright = self.isdir if type == 'directory' else self.isfile
assert isright(path)
Thomas Kluyver
Improve tests for notebook REST API
r13083
def test_create_untitled(self):
MinRK
rename notebooks service to contents service...
r17524 resp = self.api.create_untitled(path=u'Ã¥ b')
Min RK
adjustments to filename increment...
r18813 self._check_created(resp, u'Ã¥ b/Untitled.ipynb')
Thomas Kluyver
Improve tests for notebook REST API
r13083
# Second time
MinRK
rename notebooks service to contents service...
r17524 resp = self.api.create_untitled(path=u'Ã¥ b')
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 self._check_created(resp, u'Ã¥ b/Untitled1.ipynb')
Thomas Kluyver
Improve tests for notebook REST API
r13083
# And two directories down
MinRK
rename notebooks service to contents service...
r17524 resp = self.api.create_untitled(path='foo/bar')
Min RK
adjustments to filename increment...
r18813 self._check_created(resp, 'foo/bar/Untitled.ipynb')
Thomas Kluyver
Improve tests for notebook REST API
r13083
MinRK
add support and tests for uploading and saving regular files
r17527 def test_create_untitled_txt(self):
resp = self.api.create_untitled(path='foo/bar', ext='.txt')
Min RK
adjustments to filename increment...
r18813 self._check_created(resp, 'foo/bar/untitled.txt', type='file')
MinRK
add support and tests for uploading and saving regular files
r17527
Min RK
adjustments to filename increment...
r18813 resp = self.api.read(path='foo/bar/untitled.txt')
MinRK
add support and tests for uploading and saving regular files
r17527 model = resp.json()
self.assertEqual(model['type'], 'file')
self.assertEqual(model['format'], 'text')
self.assertEqual(model['content'], '')
MinRK
update notebook api tests...
r13130 def test_upload(self):
MinRK
update html/js to nbformat 4
r18584 nb = new_notebook()
MinRK
add support and tests for uploading and saving regular files
r17527 nbmodel = {'content': nb, 'type': 'notebook'}
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 path = u'å b/Upload tést.ipynb'
resp = self.api.upload(path, body=json.dumps(nbmodel))
self._check_created(resp, path)
MinRK
test creating a directory with PUT
r17528
Min RK
address review in contents service...
r18758 def test_mkdir_untitled(self):
resp = self.api.mkdir_untitled(path=u'Ã¥ b')
Min RK
adjustments to filename increment...
r18813 self._check_created(resp, u'Ã¥ b/Untitled Folder', type='directory')
Min RK
address review in contents service...
r18758
# Second time
resp = self.api.mkdir_untitled(path=u'Ã¥ b')
Min RK
adjustments to filename increment...
r18813 self._check_created(resp, u'Ã¥ b/Untitled Folder 1', type='directory')
Min RK
address review in contents service...
r18758
# And two directories down
resp = self.api.mkdir_untitled(path='foo/bar')
Min RK
adjustments to filename increment...
r18813 self._check_created(resp, 'foo/bar/Untitled Folder', type='directory')
Min RK
address review in contents service...
r18758
MinRK
test creating a directory with PUT
r17528 def test_mkdir(self):
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 path = u'å b/New ∂ir'
resp = self.api.mkdir(path)
self._check_created(resp, path, type='directory')
MinRK
update notebook api tests...
r13130
MinRK
update contents per further review...
r17537 def test_mkdir_hidden_400(self):
with assert_http_error(400):
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 resp = self.api.mkdir(u'Ã¥ b/.hidden')
MinRK
update contents per further review...
r17537
MinRK
add support and tests for uploading and saving regular files
r17527 def test_upload_txt(self):
body = u'ünicode téxt'
model = {
'content' : body,
'format' : 'text',
'type' : 'file',
}
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 path = u'å b/Upload tést.txt'
resp = self.api.upload(path, body=json.dumps(model))
MinRK
add support and tests for uploading and saving regular files
r17527
# check roundtrip
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 resp = self.api.read(path)
MinRK
add support and tests for uploading and saving regular files
r17527 model = resp.json()
self.assertEqual(model['type'], 'file')
self.assertEqual(model['format'], 'text')
self.assertEqual(model['content'], body)
def test_upload_b64(self):
body = b'\xFFblob'
b64body = base64.encodestring(body).decode('ascii')
model = {
'content' : b64body,
'format' : 'base64',
'type' : 'file',
}
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 path = u'å b/Upload tést.blob'
resp = self.api.upload(path, body=json.dumps(model))
MinRK
add support and tests for uploading and saving regular files
r17527
# check roundtrip
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 resp = self.api.read(path)
MinRK
add support and tests for uploading and saving regular files
r17527 model = resp.json()
self.assertEqual(model['type'], 'file')
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 self.assertEqual(model['path'], path)
MinRK
add support and tests for uploading and saving regular files
r17527 self.assertEqual(model['format'], 'base64')
decoded = base64.decodestring(model['content'].encode('ascii'))
self.assertEqual(decoded, body)
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")'))
MinRK
add support and tests for uploading and saving regular files
r17527 nbmodel = {'content': nb, 'type': 'notebook'}
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 path = u'å b/Upload tést.ipynb'
resp = self.api.upload(path, body=json.dumps(nbmodel))
self._check_created(resp, path)
resp = self.api.read(path)
MinRK
test upload of v2 notebooks
r13141 data = resp.json()
MinRK
don't use nbformat.current in IPython.html...
r18607 self.assertEqual(data['content']['nbformat'], 4)
MinRK
test upload of v2 notebooks
r13141
Min RK
remove copy via PUT...
r18750 def test_copy(self):
Min RK
adjustments to filename increment...
r18813 resp = self.api.copy(u'å b/ç d.ipynb', u'å b')
self._check_created(resp, u'å b/ç d-Copy1.ipynb')
MinRK
Remove separate 'path', 'name' in Contents API...
r18749
Min RK
remove copy via PUT...
r18750 resp = self.api.copy(u'å b/ç d.ipynb', u'å b')
Min RK
adjustments to filename increment...
r18813 self._check_created(resp, u'å b/ç d-Copy2.ipynb')
def test_copy_copy(self):
resp = self.api.copy(u'å b/ç d.ipynb', u'å b')
self._check_created(resp, u'å b/ç d-Copy1.ipynb')
resp = self.api.copy(u'å b/ç d-Copy1.ipynb', u'å b')
self._check_created(resp, u'å b/ç d-Copy2.ipynb')
MinRK
updates per review...
r17535 def test_copy_path(self):
Min RK
remove copy via PUT...
r18750 resp = self.api.copy(u'foo/a.ipynb', u'Ã¥ b')
Min RK
adjustments to filename increment...
r18813 self._check_created(resp, u'Ã¥ b/a.ipynb')
resp = self.api.copy(u'foo/a.ipynb', u'Ã¥ b')
self._check_created(resp, u'Ã¥ b/a-Copy1.ipynb')
Min RK
remove copy via PUT...
r18750
def test_copy_put_400(self):
with assert_http_error(400):
resp = self.api.copy_put(u'å b/ç d.ipynb', u'å b/cøpy.ipynb')
MinRK
updates per review...
r17535
MinRK
support deleting empty directories...
r17530 def test_copy_dir_400(self):
# can't copy directories
with assert_http_error(400):
Min RK
remove copy via PUT...
r18750 resp = self.api.copy(u'Ã¥ b', u'foo')
MinRK
support deleting empty directories...
r17530
Thomas Kluyver
Improve tests for notebook REST API
r13083 def test_delete(self):
for d, name in self.dirs_nbs:
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 print('%r, %r' % (d, name))
resp = self.api.delete(url_path_join(d, name + '.ipynb'))
Thomas Kluyver
Improve tests for notebook REST API
r13083 self.assertEqual(resp.status_code, 204)
for d in self.dirs + ['/']:
MinRK
rename notebooks service to contents service...
r17524 nbs = notebooks_only(self.api.list(d).json())
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 print('------')
print(d)
print(nbs)
self.assertEqual(nbs, [])
Thomas Kluyver
Improve tests for notebook REST API
r13083
MinRK
support deleting empty directories...
r17530 def test_delete_dirs(self):
# depth-first delete everything, so we don't try to delete empty directories
for name in sorted(self.dirs + ['/'], key=len, reverse=True):
listing = self.api.list(name).json()['content']
for model in listing:
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 self.api.delete(model['path'])
MinRK
support deleting empty directories...
r17530 listing = self.api.list('/').json()['content']
self.assertEqual(listing, [])
def test_delete_non_empty_dir(self):
"""delete non-empty dir raises 400"""
with assert_http_error(400):
self.api.delete(u'Ã¥ b')
Thomas Kluyver
Improve tests for notebook REST API
r13083 def test_rename(self):
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 resp = self.api.rename('foo/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')
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 self.assertEqual(resp.json()['path'], 'foo/z.ipynb')
Min RK
abstract some methods in contents service tests...
r19604 assert self.isfile('foo/z.ipynb')
Thomas Kluyver
Improve tests for notebook REST API
r13083
MinRK
rename notebooks service to contents service...
r17524 nbs = notebooks_only(self.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
Scott Sanderson
TEST: Also test deletion.
r20785 def test_checkpoints_follow_file(self):
Scott Sanderson
TEST: Add test for renaming files with checkpoint....
r20784
# Read initial file state
orig = self.api.read('foo/a.ipynb')
# Create a checkpoint of initial state
r = self.api.new_checkpoint('foo/a.ipynb')
cp1 = r.json()
# Modify file and save
nbcontent = json.loads(orig.text)['content']
nb = from_dict(nbcontent)
hcell = new_markdown_cell('Created by test')
nb.cells.append(hcell)
nbmodel = {'content': nb, 'type': 'notebook'}
self.api.save('foo/a.ipynb', body=json.dumps(nbmodel))
# Rename the file.
self.api.rename('foo/a.ipynb', 'foo/z.ipynb')
# Looking for checkpoints in the old location should yield no results.
self.assertEqual(self.api.get_checkpoints('foo/a.ipynb').json(), [])
# Looking for checkpoints in the new location should work.
cps = self.api.get_checkpoints('foo/z.ipynb').json()
Scott Sanderson
TEST: Also test deletion.
r20785 self.assertEqual(cps, [cp1])
# Delete the file. The checkpoint should be deleted as well.
self.api.delete('foo/z.ipynb')
cps = self.api.get_checkpoints('foo/z.ipynb').json()
self.assertEqual(cps, [])
Scott Sanderson
TEST: Add test for renaming files with checkpoint....
r20784
MinRK
test that rename fails with 409 if it would clobber...
r13710 def test_rename_existing(self):
with assert_http_error(409):
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 self.api.rename('foo/a.ipynb', 'foo/b.ipynb')
MinRK
test that rename fails with 409 if it would clobber...
r13710
Thomas Kluyver
Add test for saving notebook via REST API
r13085 def test_save(self):
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 resp = self.api.read('foo/a.ipynb')
MinRK
don't use jsonapi in test_notebook_api
r13138 nbcontent = json.loads(resp.text)['content']
MinRK
use from_dict for dict->notebook...
r18601 nb = from_dict(nbcontent)
MinRK
remove heading cells in v4
r18596 nb.cells.append(new_markdown_cell(u'Created by test ³'))
Thomas Kluyver
Add test for saving notebook via REST API
r13085
Scott Sanderson
TEST: Add test for renaming files with checkpoint....
r20784 nbmodel = {'content': nb, 'type': 'notebook'}
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 resp = self.api.save('foo/a.ipynb', body=json.dumps(nbmodel))
Thomas Kluyver
Add test for saving notebook via REST API
r13085
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 nbcontent = self.api.read('foo/a.ipynb').json()['content']
MinRK
use from_dict for dict->notebook...
r18601 newnb = from_dict(nbcontent)
MinRK
update html/js to nbformat 4
r18584 self.assertEqual(newnb.cells[0].source,
Thomas Kluyver
Add some unicode testing for saving notebooks
r13111 u'Created by test ³')
Thomas Kluyver
Add test for and fix REST save with rename
r13087
Thomas Kluyver
Test notebook checkpoint APIs
r13109 def test_checkpoints(self):
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 resp = self.api.read('foo/a.ipynb')
r = self.api.new_checkpoint('foo/a.ipynb')
Thomas Kluyver
Test notebook checkpoint APIs
r13109 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']
MinRK
use from_dict for dict->notebook...
r18601 nb = from_dict(nbcontent)
MinRK
remove heading cells in v4
r18596 hcell = new_markdown_cell('Created by test')
MinRK
update html/js to nbformat 4
r18584 nb.cells.append(hcell)
Thomas Kluyver
Test notebook checkpoint APIs
r13109 # Save
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 nbmodel= {'content': nb, 'type': 'notebook'}
resp = self.api.save('foo/a.ipynb', body=json.dumps(nbmodel))
Thomas Kluyver
Test notebook checkpoint APIs
r13109
# List checkpoints
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 cps = self.api.get_checkpoints('foo/a.ipynb').json()
Thomas Kluyver
Test notebook checkpoint APIs
r13109 self.assertEqual(cps, [cp1])
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 nbcontent = self.api.read('foo/a.ipynb').json()['content']
MinRK
use from_dict for dict->notebook...
r18601 nb = from_dict(nbcontent)
MinRK
update html/js to nbformat 4
r18584 self.assertEqual(nb.cells[0].source, 'Created by test')
Thomas Kluyver
Test notebook checkpoint APIs
r13109
# Restore cp1
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 r = self.api.restore_checkpoint('foo/a.ipynb', cp1['id'])
Thomas Kluyver
Test notebook checkpoint APIs
r13109 self.assertEqual(r.status_code, 204)
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 nbcontent = self.api.read('foo/a.ipynb').json()['content']
MinRK
use from_dict for dict->notebook...
r18601 nb = from_dict(nbcontent)
MinRK
update html/js to nbformat 4
r18584 self.assertEqual(nb.cells, [])
Thomas Kluyver
Test notebook checkpoint APIs
r13109
# Delete cp1
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 r = self.api.delete_checkpoint('foo/a.ipynb', cp1['id'])
Thomas Kluyver
Test notebook checkpoint APIs
r13109 self.assertEqual(r.status_code, 204)
MinRK
Remove separate 'path', 'name' in Contents API...
r18749 cps = self.api.get_checkpoints('foo/a.ipynb').json()
Thomas Kluyver
Test notebook checkpoint APIs
r13109 self.assertEqual(cps, [])
Scott Sanderson
TEST: Test separate roots for Contents and Checkpoints.
r19748
Scott Sanderson
DEV: Add full support for non-notebook checkpoints.
r19786 def test_file_checkpoints(self):
"""
Test checkpointing of non-notebook files.
"""
filename = 'foo/a.txt'
resp = self.api.read(filename)
orig_content = json.loads(resp.text)['content']
# Create a checkpoint.
r = self.api.new_checkpoint(filename)
self.assertEqual(r.status_code, 201)
cp1 = r.json()
self.assertEqual(set(cp1), {'id', 'last_modified'})
self.assertEqual(r.headers['Location'].split('/')[-1], cp1['id'])
# Modify the file and save.
new_content = orig_content + '\nsecond line'
model = {
'content': new_content,
'type': 'file',
'format': 'text',
}
resp = self.api.save(filename, body=json.dumps(model))
# List checkpoints
cps = self.api.get_checkpoints(filename).json()
self.assertEqual(cps, [cp1])
content = self.api.read(filename).json()['content']
self.assertEqual(content, new_content)
# Restore cp1
r = self.api.restore_checkpoint(filename, cp1['id'])
self.assertEqual(r.status_code, 204)
restored_content = self.api.read(filename).json()['content']
self.assertEqual(restored_content, orig_content)
# Delete cp1
r = self.api.delete_checkpoint(filename, cp1['id'])
self.assertEqual(r.status_code, 204)
cps = self.api.get_checkpoints(filename).json()
self.assertEqual(cps, [])
Scott Sanderson
TEST: Test separate roots for Contents and Checkpoints.
r19748 @contextmanager
def patch_cp_root(self, dirname):
"""
Temporarily patch the root dir of our checkpoint manager.
"""
Scott Sanderson
STY: s/CheckpointManager/Checkpoints...
r19839 cpm = self.notebook.contents_manager.checkpoints
Scott Sanderson
TEST: Test separate roots for Contents and Checkpoints.
r19748 old_dirname = cpm.root_dir
cpm.root_dir = dirname
try:
yield
finally:
cpm.root_dir = old_dirname
def test_checkpoints_separate_root(self):
"""
Scott Sanderson
STY: s/CheckpointManager/Checkpoints...
r19839 Test that FileCheckpoints functions correctly even when it's
Scott Sanderson
TEST: Test separate roots for Contents and Checkpoints.
r19748 using a different root dir from FileContentsManager. This also keeps
the implementation honest for use with ContentsManagers that don't map
models to the filesystem
Scott Sanderson
DEV: Add full support for non-notebook checkpoints.
r19786 Override this method to a no-op when testing other managers.
"""
Scott Sanderson
TEST: Test separate roots for Contents and Checkpoints.
r19748 with TemporaryDirectory() as td:
with self.patch_cp_root(td):
self.test_checkpoints()
Scott Sanderson
DEV: Add full support for non-notebook checkpoints.
r19786
with TemporaryDirectory() as td:
with self.patch_cp_root(td):
self.test_file_checkpoints()
Scott Sanderson
DEV: Allow CheckpointManagers to optimize for shared backends....
r19828
Scott Sanderson
DEV: Separate FileCheckpointManager and GenericFileCheckpointManager....
r19838 class GenericFileCheckpointsAPITest(APITest):
"""
Scott Sanderson
STY: s/CheckpointManager/Checkpoints...
r19839 Run the tests from APITest with GenericFileCheckpoints.
Scott Sanderson
DEV: Separate FileCheckpointManager and GenericFileCheckpointManager....
r19838 """
config = Config()
Scott Sanderson
STY: s/CheckpointManager/Checkpoints...
r19839 config.FileContentsManager.checkpoints_class = GenericFileCheckpoints
def test_config_did_something(self):
self.assertIsInstance(
self.notebook.contents_manager.checkpoints,
GenericFileCheckpoints,
)