##// END OF EJS Templates
test that rename fails with 409 if it would clobber...
MinRK -
Show More
@@ -1,319 +1,323 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Test the notebooks webservice API."""
2 """Test the notebooks webservice API."""
3
3
4 import io
4 import io
5 import json
5 import json
6 import os
6 import os
7 import shutil
7 import shutil
8 from unicodedata import normalize
8 from unicodedata import normalize
9
9
10 pjoin = os.path.join
10 pjoin = os.path.join
11
11
12 import requests
12 import requests
13
13
14 from IPython.html.utils import url_path_join, url_escape
14 from IPython.html.utils import url_path_join, url_escape
15 from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error
15 from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error
16 from IPython.nbformat import current
16 from IPython.nbformat import current
17 from IPython.nbformat.current import (new_notebook, write, read, new_worksheet,
17 from IPython.nbformat.current import (new_notebook, write, read, new_worksheet,
18 new_heading_cell, to_notebook_json)
18 new_heading_cell, to_notebook_json)
19 from IPython.nbformat import v2
19 from IPython.nbformat import v2
20 from IPython.utils import py3compat
20 from IPython.utils import py3compat
21 from IPython.utils.data import uniq_stable
21 from IPython.utils.data import uniq_stable
22
22
23
23
24 class NBAPI(object):
24 class NBAPI(object):
25 """Wrapper for notebook API calls."""
25 """Wrapper for notebook API calls."""
26 def __init__(self, base_url):
26 def __init__(self, base_url):
27 self.base_url = base_url
27 self.base_url = base_url
28
28
29 def _req(self, verb, path, body=None):
29 def _req(self, verb, path, body=None):
30 response = requests.request(verb,
30 response = requests.request(verb,
31 url_path_join(self.base_url, 'api/notebooks', path),
31 url_path_join(self.base_url, 'api/notebooks', path),
32 data=body,
32 data=body,
33 )
33 )
34 response.raise_for_status()
34 response.raise_for_status()
35 return response
35 return response
36
36
37 def list(self, path='/'):
37 def list(self, path='/'):
38 return self._req('GET', path)
38 return self._req('GET', path)
39
39
40 def read(self, name, path='/'):
40 def read(self, name, path='/'):
41 return self._req('GET', url_path_join(path, name))
41 return self._req('GET', url_path_join(path, name))
42
42
43 def create_untitled(self, path='/'):
43 def create_untitled(self, path='/'):
44 return self._req('POST', path)
44 return self._req('POST', path)
45
45
46 def upload_untitled(self, body, path='/'):
46 def upload_untitled(self, body, path='/'):
47 return self._req('POST', path, body)
47 return self._req('POST', path, body)
48
48
49 def copy_untitled(self, copy_from, path='/'):
49 def copy_untitled(self, copy_from, path='/'):
50 body = json.dumps({'copy_from':copy_from})
50 body = json.dumps({'copy_from':copy_from})
51 return self._req('POST', path, body)
51 return self._req('POST', path, body)
52
52
53 def create(self, name, path='/'):
53 def create(self, name, path='/'):
54 return self._req('PUT', url_path_join(path, name))
54 return self._req('PUT', url_path_join(path, name))
55
55
56 def upload(self, name, body, path='/'):
56 def upload(self, name, body, path='/'):
57 return self._req('PUT', url_path_join(path, name), body)
57 return self._req('PUT', url_path_join(path, name), body)
58
58
59 def copy(self, copy_from, copy_to, path='/'):
59 def copy(self, copy_from, copy_to, path='/'):
60 body = json.dumps({'copy_from':copy_from})
60 body = json.dumps({'copy_from':copy_from})
61 return self._req('PUT', url_path_join(path, copy_to), body)
61 return self._req('PUT', url_path_join(path, copy_to), body)
62
62
63 def save(self, name, body, path='/'):
63 def save(self, name, body, path='/'):
64 return self._req('PUT', url_path_join(path, name), body)
64 return self._req('PUT', url_path_join(path, name), body)
65
65
66 def delete(self, name, path='/'):
66 def delete(self, name, path='/'):
67 return self._req('DELETE', url_path_join(path, name))
67 return self._req('DELETE', url_path_join(path, name))
68
68
69 def rename(self, name, path, new_name):
69 def rename(self, name, path, new_name):
70 body = json.dumps({'name': new_name})
70 body = json.dumps({'name': new_name})
71 return self._req('PATCH', url_path_join(path, name), body)
71 return self._req('PATCH', url_path_join(path, name), body)
72
72
73 def get_checkpoints(self, name, path):
73 def get_checkpoints(self, name, path):
74 return self._req('GET', url_path_join(path, name, 'checkpoints'))
74 return self._req('GET', url_path_join(path, name, 'checkpoints'))
75
75
76 def new_checkpoint(self, name, path):
76 def new_checkpoint(self, name, path):
77 return self._req('POST', url_path_join(path, name, 'checkpoints'))
77 return self._req('POST', url_path_join(path, name, 'checkpoints'))
78
78
79 def restore_checkpoint(self, name, path, checkpoint_id):
79 def restore_checkpoint(self, name, path, checkpoint_id):
80 return self._req('POST', url_path_join(path, name, 'checkpoints', checkpoint_id))
80 return self._req('POST', url_path_join(path, name, 'checkpoints', checkpoint_id))
81
81
82 def delete_checkpoint(self, name, path, checkpoint_id):
82 def delete_checkpoint(self, name, path, checkpoint_id):
83 return self._req('DELETE', url_path_join(path, name, 'checkpoints', checkpoint_id))
83 return self._req('DELETE', url_path_join(path, name, 'checkpoints', checkpoint_id))
84
84
85 class APITest(NotebookTestBase):
85 class APITest(NotebookTestBase):
86 """Test the kernels web service API"""
86 """Test the kernels web service API"""
87 dirs_nbs = [('', 'inroot'),
87 dirs_nbs = [('', 'inroot'),
88 ('Directory with spaces in', 'inspace'),
88 ('Directory with spaces in', 'inspace'),
89 (u'unicodΓ©', 'innonascii'),
89 (u'unicodΓ©', 'innonascii'),
90 ('foo', 'a'),
90 ('foo', 'a'),
91 ('foo', 'b'),
91 ('foo', 'b'),
92 ('foo', 'name with spaces'),
92 ('foo', 'name with spaces'),
93 ('foo', u'unicodΓ©'),
93 ('foo', u'unicodΓ©'),
94 ('foo/bar', 'baz'),
94 ('foo/bar', 'baz'),
95 (u'Γ₯ b', u'Γ§ d')
95 (u'Γ₯ b', u'Γ§ d')
96 ]
96 ]
97
97
98 dirs = uniq_stable([d for (d,n) in dirs_nbs])
98 dirs = uniq_stable([d for (d,n) in dirs_nbs])
99 del dirs[0] # remove ''
99 del dirs[0] # remove ''
100
100
101 def setUp(self):
101 def setUp(self):
102 nbdir = self.notebook_dir.name
102 nbdir = self.notebook_dir.name
103
103
104 for d in self.dirs:
104 for d in self.dirs:
105 d.replace('/', os.sep)
105 d.replace('/', os.sep)
106 if not os.path.isdir(pjoin(nbdir, d)):
106 if not os.path.isdir(pjoin(nbdir, d)):
107 os.mkdir(pjoin(nbdir, d))
107 os.mkdir(pjoin(nbdir, d))
108
108
109 for d, name in self.dirs_nbs:
109 for d, name in self.dirs_nbs:
110 d = d.replace('/', os.sep)
110 d = d.replace('/', os.sep)
111 with io.open(pjoin(nbdir, d, '%s.ipynb' % name), 'w',
111 with io.open(pjoin(nbdir, d, '%s.ipynb' % name), 'w',
112 encoding='utf-8') as f:
112 encoding='utf-8') as f:
113 nb = new_notebook(name=name)
113 nb = new_notebook(name=name)
114 write(nb, f, format='ipynb')
114 write(nb, f, format='ipynb')
115
115
116 self.nb_api = NBAPI(self.base_url())
116 self.nb_api = NBAPI(self.base_url())
117
117
118 def tearDown(self):
118 def tearDown(self):
119 nbdir = self.notebook_dir.name
119 nbdir = self.notebook_dir.name
120
120
121 for dname in ['foo', 'Directory with spaces in', u'unicodΓ©', u'Γ₯ b']:
121 for dname in ['foo', 'Directory with spaces in', u'unicodΓ©', u'Γ₯ b']:
122 shutil.rmtree(pjoin(nbdir, dname), ignore_errors=True)
122 shutil.rmtree(pjoin(nbdir, dname), ignore_errors=True)
123
123
124 if os.path.isfile(pjoin(nbdir, 'inroot.ipynb')):
124 if os.path.isfile(pjoin(nbdir, 'inroot.ipynb')):
125 os.unlink(pjoin(nbdir, 'inroot.ipynb'))
125 os.unlink(pjoin(nbdir, 'inroot.ipynb'))
126
126
127 def test_list_notebooks(self):
127 def test_list_notebooks(self):
128 nbs = self.nb_api.list().json()
128 nbs = self.nb_api.list().json()
129 self.assertEqual(len(nbs), 1)
129 self.assertEqual(len(nbs), 1)
130 self.assertEqual(nbs[0]['name'], 'inroot.ipynb')
130 self.assertEqual(nbs[0]['name'], 'inroot.ipynb')
131
131
132 nbs = self.nb_api.list('/Directory with spaces in/').json()
132 nbs = self.nb_api.list('/Directory with spaces in/').json()
133 self.assertEqual(len(nbs), 1)
133 self.assertEqual(len(nbs), 1)
134 self.assertEqual(nbs[0]['name'], 'inspace.ipynb')
134 self.assertEqual(nbs[0]['name'], 'inspace.ipynb')
135
135
136 nbs = self.nb_api.list(u'/unicodΓ©/').json()
136 nbs = self.nb_api.list(u'/unicodΓ©/').json()
137 self.assertEqual(len(nbs), 1)
137 self.assertEqual(len(nbs), 1)
138 self.assertEqual(nbs[0]['name'], 'innonascii.ipynb')
138 self.assertEqual(nbs[0]['name'], 'innonascii.ipynb')
139 self.assertEqual(nbs[0]['path'], u'unicodΓ©')
139 self.assertEqual(nbs[0]['path'], u'unicodΓ©')
140
140
141 nbs = self.nb_api.list('/foo/bar/').json()
141 nbs = self.nb_api.list('/foo/bar/').json()
142 self.assertEqual(len(nbs), 1)
142 self.assertEqual(len(nbs), 1)
143 self.assertEqual(nbs[0]['name'], 'baz.ipynb')
143 self.assertEqual(nbs[0]['name'], 'baz.ipynb')
144 self.assertEqual(nbs[0]['path'], 'foo/bar')
144 self.assertEqual(nbs[0]['path'], 'foo/bar')
145
145
146 nbs = self.nb_api.list('foo').json()
146 nbs = self.nb_api.list('foo').json()
147 self.assertEqual(len(nbs), 4)
147 self.assertEqual(len(nbs), 4)
148 nbnames = { normalize('NFC', n['name']) for n in nbs }
148 nbnames = { normalize('NFC', n['name']) for n in nbs }
149 expected = [ u'a.ipynb', u'b.ipynb', u'name with spaces.ipynb', u'unicodΓ©.ipynb']
149 expected = [ u'a.ipynb', u'b.ipynb', u'name with spaces.ipynb', u'unicodΓ©.ipynb']
150 expected = { normalize('NFC', name) for name in expected }
150 expected = { normalize('NFC', name) for name in expected }
151 self.assertEqual(nbnames, expected)
151 self.assertEqual(nbnames, expected)
152
152
153 def test_list_nonexistant_dir(self):
153 def test_list_nonexistant_dir(self):
154 with assert_http_error(404):
154 with assert_http_error(404):
155 self.nb_api.list('nonexistant')
155 self.nb_api.list('nonexistant')
156
156
157 def test_get_contents(self):
157 def test_get_contents(self):
158 for d, name in self.dirs_nbs:
158 for d, name in self.dirs_nbs:
159 nb = self.nb_api.read('%s.ipynb' % name, d+'/').json()
159 nb = self.nb_api.read('%s.ipynb' % name, d+'/').json()
160 self.assertEqual(nb['name'], u'%s.ipynb' % name)
160 self.assertEqual(nb['name'], u'%s.ipynb' % name)
161 self.assertIn('content', nb)
161 self.assertIn('content', nb)
162 self.assertIn('metadata', nb['content'])
162 self.assertIn('metadata', nb['content'])
163 self.assertIsInstance(nb['content']['metadata'], dict)
163 self.assertIsInstance(nb['content']['metadata'], dict)
164
164
165 # Name that doesn't exist - should be a 404
165 # Name that doesn't exist - should be a 404
166 with assert_http_error(404):
166 with assert_http_error(404):
167 self.nb_api.read('q.ipynb', 'foo')
167 self.nb_api.read('q.ipynb', 'foo')
168
168
169 def _check_nb_created(self, resp, name, path):
169 def _check_nb_created(self, resp, name, path):
170 self.assertEqual(resp.status_code, 201)
170 self.assertEqual(resp.status_code, 201)
171 location_header = py3compat.str_to_unicode(resp.headers['Location'])
171 location_header = py3compat.str_to_unicode(resp.headers['Location'])
172 self.assertEqual(location_header, url_escape(url_path_join(u'/api/notebooks', path, name)))
172 self.assertEqual(location_header, url_escape(url_path_join(u'/api/notebooks', path, name)))
173 self.assertEqual(resp.json()['name'], name)
173 self.assertEqual(resp.json()['name'], name)
174 assert os.path.isfile(pjoin(
174 assert os.path.isfile(pjoin(
175 self.notebook_dir.name,
175 self.notebook_dir.name,
176 path.replace('/', os.sep),
176 path.replace('/', os.sep),
177 name,
177 name,
178 ))
178 ))
179
179
180 def test_create_untitled(self):
180 def test_create_untitled(self):
181 resp = self.nb_api.create_untitled(path=u'Γ₯ b')
181 resp = self.nb_api.create_untitled(path=u'Γ₯ b')
182 self._check_nb_created(resp, 'Untitled0.ipynb', u'Γ₯ b')
182 self._check_nb_created(resp, 'Untitled0.ipynb', u'Γ₯ b')
183
183
184 # Second time
184 # Second time
185 resp = self.nb_api.create_untitled(path=u'Γ₯ b')
185 resp = self.nb_api.create_untitled(path=u'Γ₯ b')
186 self._check_nb_created(resp, 'Untitled1.ipynb', u'Γ₯ b')
186 self._check_nb_created(resp, 'Untitled1.ipynb', u'Γ₯ b')
187
187
188 # And two directories down
188 # And two directories down
189 resp = self.nb_api.create_untitled(path='foo/bar')
189 resp = self.nb_api.create_untitled(path='foo/bar')
190 self._check_nb_created(resp, 'Untitled0.ipynb', 'foo/bar')
190 self._check_nb_created(resp, 'Untitled0.ipynb', 'foo/bar')
191
191
192 def test_upload_untitled(self):
192 def test_upload_untitled(self):
193 nb = new_notebook(name='Upload test')
193 nb = new_notebook(name='Upload test')
194 nbmodel = {'content': nb}
194 nbmodel = {'content': nb}
195 resp = self.nb_api.upload_untitled(path=u'Γ₯ b',
195 resp = self.nb_api.upload_untitled(path=u'Γ₯ b',
196 body=json.dumps(nbmodel))
196 body=json.dumps(nbmodel))
197 self._check_nb_created(resp, 'Untitled0.ipynb', u'Γ₯ b')
197 self._check_nb_created(resp, 'Untitled0.ipynb', u'Γ₯ b')
198
198
199 def test_upload(self):
199 def test_upload(self):
200 nb = new_notebook(name=u'ignored')
200 nb = new_notebook(name=u'ignored')
201 nbmodel = {'content': nb}
201 nbmodel = {'content': nb}
202 resp = self.nb_api.upload(u'Upload tΓ©st.ipynb', path=u'Γ₯ b',
202 resp = self.nb_api.upload(u'Upload tΓ©st.ipynb', path=u'Γ₯ b',
203 body=json.dumps(nbmodel))
203 body=json.dumps(nbmodel))
204 self._check_nb_created(resp, u'Upload tΓ©st.ipynb', u'Γ₯ b')
204 self._check_nb_created(resp, u'Upload tΓ©st.ipynb', u'Γ₯ b')
205
205
206 def test_upload_v2(self):
206 def test_upload_v2(self):
207 nb = v2.new_notebook()
207 nb = v2.new_notebook()
208 ws = v2.new_worksheet()
208 ws = v2.new_worksheet()
209 nb.worksheets.append(ws)
209 nb.worksheets.append(ws)
210 ws.cells.append(v2.new_code_cell(input='print("hi")'))
210 ws.cells.append(v2.new_code_cell(input='print("hi")'))
211 nbmodel = {'content': nb}
211 nbmodel = {'content': nb}
212 resp = self.nb_api.upload(u'Upload tΓ©st.ipynb', path=u'Γ₯ b',
212 resp = self.nb_api.upload(u'Upload tΓ©st.ipynb', path=u'Γ₯ b',
213 body=json.dumps(nbmodel))
213 body=json.dumps(nbmodel))
214 self._check_nb_created(resp, u'Upload tΓ©st.ipynb', u'Γ₯ b')
214 self._check_nb_created(resp, u'Upload tΓ©st.ipynb', u'Γ₯ b')
215 resp = self.nb_api.read(u'Upload tΓ©st.ipynb', u'Γ₯ b')
215 resp = self.nb_api.read(u'Upload tΓ©st.ipynb', u'Γ₯ b')
216 data = resp.json()
216 data = resp.json()
217 self.assertEqual(data['content']['nbformat'], current.nbformat)
217 self.assertEqual(data['content']['nbformat'], current.nbformat)
218 self.assertEqual(data['content']['orig_nbformat'], 2)
218 self.assertEqual(data['content']['orig_nbformat'], 2)
219
219
220 def test_copy_untitled(self):
220 def test_copy_untitled(self):
221 resp = self.nb_api.copy_untitled(u'Γ§ d.ipynb', path=u'Γ₯ b')
221 resp = self.nb_api.copy_untitled(u'Γ§ d.ipynb', path=u'Γ₯ b')
222 self._check_nb_created(resp, u'Γ§ d-Copy0.ipynb', u'Γ₯ b')
222 self._check_nb_created(resp, u'Γ§ d-Copy0.ipynb', u'Γ₯ b')
223
223
224 def test_copy(self):
224 def test_copy(self):
225 resp = self.nb_api.copy(u'Γ§ d.ipynb', u'cΓΈpy.ipynb', path=u'Γ₯ b')
225 resp = self.nb_api.copy(u'Γ§ d.ipynb', u'cΓΈpy.ipynb', path=u'Γ₯ b')
226 self._check_nb_created(resp, u'cΓΈpy.ipynb', u'Γ₯ b')
226 self._check_nb_created(resp, u'cΓΈpy.ipynb', u'Γ₯ b')
227
227
228 def test_delete(self):
228 def test_delete(self):
229 for d, name in self.dirs_nbs:
229 for d, name in self.dirs_nbs:
230 resp = self.nb_api.delete('%s.ipynb' % name, d)
230 resp = self.nb_api.delete('%s.ipynb' % name, d)
231 self.assertEqual(resp.status_code, 204)
231 self.assertEqual(resp.status_code, 204)
232
232
233 for d in self.dirs + ['/']:
233 for d in self.dirs + ['/']:
234 nbs = self.nb_api.list(d).json()
234 nbs = self.nb_api.list(d).json()
235 self.assertEqual(len(nbs), 0)
235 self.assertEqual(len(nbs), 0)
236
236
237 def test_rename(self):
237 def test_rename(self):
238 resp = self.nb_api.rename('a.ipynb', 'foo', 'z.ipynb')
238 resp = self.nb_api.rename('a.ipynb', 'foo', 'z.ipynb')
239 self.assertEqual(resp.headers['Location'].split('/')[-1], 'z.ipynb')
239 self.assertEqual(resp.headers['Location'].split('/')[-1], 'z.ipynb')
240 self.assertEqual(resp.json()['name'], 'z.ipynb')
240 self.assertEqual(resp.json()['name'], 'z.ipynb')
241 assert os.path.isfile(pjoin(self.notebook_dir.name, 'foo', 'z.ipynb'))
241 assert os.path.isfile(pjoin(self.notebook_dir.name, 'foo', 'z.ipynb'))
242
242
243 nbs = self.nb_api.list('foo').json()
243 nbs = self.nb_api.list('foo').json()
244 nbnames = set(n['name'] for n in nbs)
244 nbnames = set(n['name'] for n in nbs)
245 self.assertIn('z.ipynb', nbnames)
245 self.assertIn('z.ipynb', nbnames)
246 self.assertNotIn('a.ipynb', nbnames)
246 self.assertNotIn('a.ipynb', nbnames)
247
247
248 def test_rename_existing(self):
249 with assert_http_error(409):
250 self.nb_api.rename('a.ipynb', 'foo', 'b.ipynb')
251
248 def test_save(self):
252 def test_save(self):
249 resp = self.nb_api.read('a.ipynb', 'foo')
253 resp = self.nb_api.read('a.ipynb', 'foo')
250 nbcontent = json.loads(resp.text)['content']
254 nbcontent = json.loads(resp.text)['content']
251 nb = to_notebook_json(nbcontent)
255 nb = to_notebook_json(nbcontent)
252 ws = new_worksheet()
256 ws = new_worksheet()
253 nb.worksheets = [ws]
257 nb.worksheets = [ws]
254 ws.cells.append(new_heading_cell(u'Created by test Β³'))
258 ws.cells.append(new_heading_cell(u'Created by test Β³'))
255
259
256 nbmodel= {'name': 'a.ipynb', 'path':'foo', 'content': nb}
260 nbmodel= {'name': 'a.ipynb', 'path':'foo', 'content': nb}
257 resp = self.nb_api.save('a.ipynb', path='foo', body=json.dumps(nbmodel))
261 resp = self.nb_api.save('a.ipynb', path='foo', body=json.dumps(nbmodel))
258
262
259 nbfile = pjoin(self.notebook_dir.name, 'foo', 'a.ipynb')
263 nbfile = pjoin(self.notebook_dir.name, 'foo', 'a.ipynb')
260 with io.open(nbfile, 'r', encoding='utf-8') as f:
264 with io.open(nbfile, 'r', encoding='utf-8') as f:
261 newnb = read(f, format='ipynb')
265 newnb = read(f, format='ipynb')
262 self.assertEqual(newnb.worksheets[0].cells[0].source,
266 self.assertEqual(newnb.worksheets[0].cells[0].source,
263 u'Created by test Β³')
267 u'Created by test Β³')
264 nbcontent = self.nb_api.read('a.ipynb', 'foo').json()['content']
268 nbcontent = self.nb_api.read('a.ipynb', 'foo').json()['content']
265 newnb = to_notebook_json(nbcontent)
269 newnb = to_notebook_json(nbcontent)
266 self.assertEqual(newnb.worksheets[0].cells[0].source,
270 self.assertEqual(newnb.worksheets[0].cells[0].source,
267 u'Created by test Β³')
271 u'Created by test Β³')
268
272
269 # Save and rename
273 # Save and rename
270 nbmodel= {'name': 'a2.ipynb', 'path':'foo/bar', 'content': nb}
274 nbmodel= {'name': 'a2.ipynb', 'path':'foo/bar', 'content': nb}
271 resp = self.nb_api.save('a.ipynb', path='foo', body=json.dumps(nbmodel))
275 resp = self.nb_api.save('a.ipynb', path='foo', body=json.dumps(nbmodel))
272 saved = resp.json()
276 saved = resp.json()
273 self.assertEqual(saved['name'], 'a2.ipynb')
277 self.assertEqual(saved['name'], 'a2.ipynb')
274 self.assertEqual(saved['path'], 'foo/bar')
278 self.assertEqual(saved['path'], 'foo/bar')
275 assert os.path.isfile(pjoin(self.notebook_dir.name,'foo','bar','a2.ipynb'))
279 assert os.path.isfile(pjoin(self.notebook_dir.name,'foo','bar','a2.ipynb'))
276 assert not os.path.isfile(pjoin(self.notebook_dir.name, 'foo', 'a.ipynb'))
280 assert not os.path.isfile(pjoin(self.notebook_dir.name, 'foo', 'a.ipynb'))
277 with assert_http_error(404):
281 with assert_http_error(404):
278 self.nb_api.read('a.ipynb', 'foo')
282 self.nb_api.read('a.ipynb', 'foo')
279
283
280 def test_checkpoints(self):
284 def test_checkpoints(self):
281 resp = self.nb_api.read('a.ipynb', 'foo')
285 resp = self.nb_api.read('a.ipynb', 'foo')
282 r = self.nb_api.new_checkpoint('a.ipynb', 'foo')
286 r = self.nb_api.new_checkpoint('a.ipynb', 'foo')
283 self.assertEqual(r.status_code, 201)
287 self.assertEqual(r.status_code, 201)
284 cp1 = r.json()
288 cp1 = r.json()
285 self.assertEqual(set(cp1), {'id', 'last_modified'})
289 self.assertEqual(set(cp1), {'id', 'last_modified'})
286 self.assertEqual(r.headers['Location'].split('/')[-1], cp1['id'])
290 self.assertEqual(r.headers['Location'].split('/')[-1], cp1['id'])
287
291
288 # Modify it
292 # Modify it
289 nbcontent = json.loads(resp.text)['content']
293 nbcontent = json.loads(resp.text)['content']
290 nb = to_notebook_json(nbcontent)
294 nb = to_notebook_json(nbcontent)
291 ws = new_worksheet()
295 ws = new_worksheet()
292 nb.worksheets = [ws]
296 nb.worksheets = [ws]
293 hcell = new_heading_cell('Created by test')
297 hcell = new_heading_cell('Created by test')
294 ws.cells.append(hcell)
298 ws.cells.append(hcell)
295 # Save
299 # Save
296 nbmodel= {'name': 'a.ipynb', 'path':'foo', 'content': nb}
300 nbmodel= {'name': 'a.ipynb', 'path':'foo', 'content': nb}
297 resp = self.nb_api.save('a.ipynb', path='foo', body=json.dumps(nbmodel))
301 resp = self.nb_api.save('a.ipynb', path='foo', body=json.dumps(nbmodel))
298
302
299 # List checkpoints
303 # List checkpoints
300 cps = self.nb_api.get_checkpoints('a.ipynb', 'foo').json()
304 cps = self.nb_api.get_checkpoints('a.ipynb', 'foo').json()
301 self.assertEqual(cps, [cp1])
305 self.assertEqual(cps, [cp1])
302
306
303 nbcontent = self.nb_api.read('a.ipynb', 'foo').json()['content']
307 nbcontent = self.nb_api.read('a.ipynb', 'foo').json()['content']
304 nb = to_notebook_json(nbcontent)
308 nb = to_notebook_json(nbcontent)
305 self.assertEqual(nb.worksheets[0].cells[0].source, 'Created by test')
309 self.assertEqual(nb.worksheets[0].cells[0].source, 'Created by test')
306
310
307 # Restore cp1
311 # Restore cp1
308 r = self.nb_api.restore_checkpoint('a.ipynb', 'foo', cp1['id'])
312 r = self.nb_api.restore_checkpoint('a.ipynb', 'foo', cp1['id'])
309 self.assertEqual(r.status_code, 204)
313 self.assertEqual(r.status_code, 204)
310 nbcontent = self.nb_api.read('a.ipynb', 'foo').json()['content']
314 nbcontent = self.nb_api.read('a.ipynb', 'foo').json()['content']
311 nb = to_notebook_json(nbcontent)
315 nb = to_notebook_json(nbcontent)
312 self.assertEqual(nb.worksheets, [])
316 self.assertEqual(nb.worksheets, [])
313
317
314 # Delete cp1
318 # Delete cp1
315 r = self.nb_api.delete_checkpoint('a.ipynb', 'foo', cp1['id'])
319 r = self.nb_api.delete_checkpoint('a.ipynb', 'foo', cp1['id'])
316 self.assertEqual(r.status_code, 204)
320 self.assertEqual(r.status_code, 204)
317 cps = self.nb_api.get_checkpoints('a.ipynb', 'foo').json()
321 cps = self.nb_api.get_checkpoints('a.ipynb', 'foo').json()
318 self.assertEqual(cps, [])
322 self.assertEqual(cps, [])
319
323
General Comments 0
You need to be logged in to leave comments. Login now