##// END OF EJS Templates
Merge pull request #7191 from minrk/contents-test-reuse...
Thomas Kluyver -
r19677:dc60d348 merge
parent child Browse files
Show More
@@ -357,6 +357,7 class FileContentsManager(ContentsManager):
357 if model['content'] is None:
357 if model['content'] is None:
358 model['content'] = base64.encodestring(bcontent).decode('ascii')
358 model['content'] = base64.encodestring(bcontent).decode('ascii')
359 model['format'] = 'base64'
359 model['format'] = 'base64'
360 if model['format'] == 'base64':
360 default_mime = 'application/octet-stream'
361 default_mime = 'application/octet-stream'
361
362
362 model['mimetype'] = mimetypes.guess_type(os_path)[0] or default_mime
363 model['mimetype'] = mimetypes.guess_type(os_path)[0] or default_mime
@@ -347,6 +347,9 class ContentsManager(LoggingConfigurable):
347 from_path must be a full path to a file.
347 from_path must be a full path to a file.
348 """
348 """
349 path = from_path.strip('/')
349 path = from_path.strip('/')
350 if to_path is not None:
351 to_path = to_path.strip('/')
352
350 if '/' in path:
353 if '/' in path:
351 from_dir, from_name = path.rsplit('/', 1)
354 from_dir, from_name = path.rsplit('/', 1)
352 else:
355 else:
@@ -359,7 +362,7 class ContentsManager(LoggingConfigurable):
359 if model['type'] == 'directory':
362 if model['type'] == 'directory':
360 raise HTTPError(400, "Can't copy directories")
363 raise HTTPError(400, "Can't copy directories")
361
364
362 if not to_path:
365 if to_path is None:
363 to_path = from_dir
366 to_path = from_dir
364 if self.dir_exists(to_path):
367 if self.dir_exists(to_path):
365 name = copy_pat.sub(u'.', from_name)
368 name = copy_pat.sub(u'.', from_name)
@@ -12,7 +12,7 pjoin = os.path.join
12
12
13 import requests
13 import requests
14
14
15 from IPython.html.utils import url_path_join, url_escape
15 from IPython.html.utils import url_path_join, url_escape, to_os_path
16 from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error
16 from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error
17 from IPython.nbformat import read, write, from_dict
17 from IPython.nbformat import read, write, from_dict
18 from IPython.nbformat.v4 import (
18 from IPython.nbformat.v4 import (
@@ -73,9 +73,6 class API(object):
73 def upload(self, path, body):
73 def upload(self, path, body):
74 return self._req('PUT', path, body)
74 return self._req('PUT', path, body)
75
75
76 def mkdir_untitled(self, path='/'):
77 return self._req('POST', path, json.dumps({'type': 'directory'}))
78
79 def mkdir(self, path='/'):
76 def mkdir(self, path='/'):
80 return self._req('PUT', path, json.dumps({'type': 'directory'}))
77 return self._req('PUT', path, json.dumps({'type': 'directory'}))
81
78
@@ -122,8 +119,8 class APITest(NotebookTestBase):
122 ]
119 ]
123 hidden_dirs = ['.hidden', '__pycache__']
120 hidden_dirs = ['.hidden', '__pycache__']
124
121
125 dirs = uniq_stable([py3compat.cast_unicode(d) for (d,n) in dirs_nbs])
122 # Don't include root dir.
126 del dirs[0] # remove ''
123 dirs = uniq_stable([py3compat.cast_unicode(d) for (d,n) in dirs_nbs[1:]])
127 top_level_dirs = {normalize('NFC', d.split('/')[0]) for d in dirs}
124 top_level_dirs = {normalize('NFC', d.split('/')[0]) for d in dirs}
128
125
129 @staticmethod
126 @staticmethod
@@ -133,44 +130,77 class APITest(NotebookTestBase):
133 @staticmethod
130 @staticmethod
134 def _txt_for_name(name):
131 def _txt_for_name(name):
135 return u'%s text file' % name
132 return u'%s text file' % name
136
133
134 def to_os_path(self, api_path):
135 return to_os_path(api_path, root=self.notebook_dir.name)
136
137 def make_dir(self, api_path):
138 """Create a directory at api_path"""
139 os_path = self.to_os_path(api_path)
140 try:
141 os.makedirs(os_path)
142 except OSError:
143 print("Directory already exists: %r" % os_path)
144
145 def make_txt(self, api_path, txt):
146 """Make a text file at a given api_path"""
147 os_path = self.to_os_path(api_path)
148 with io.open(os_path, 'w', encoding='utf-8') as f:
149 f.write(txt)
150
151 def make_blob(self, api_path, blob):
152 """Make a binary file at a given api_path"""
153 os_path = self.to_os_path(api_path)
154 with io.open(os_path, 'wb') as f:
155 f.write(blob)
156
157 def make_nb(self, api_path, nb):
158 """Make a notebook file at a given api_path"""
159 os_path = self.to_os_path(api_path)
160
161 with io.open(os_path, 'w', encoding='utf-8') as f:
162 write(nb, f, version=4)
163
164 def delete_dir(self, api_path):
165 """Delete a directory at api_path, removing any contents."""
166 os_path = self.to_os_path(api_path)
167 shutil.rmtree(os_path, ignore_errors=True)
168
169 def delete_file(self, api_path):
170 """Delete a file at the given path if it exists."""
171 if self.isfile(api_path):
172 os.unlink(self.to_os_path(api_path))
173
174 def isfile(self, api_path):
175 return os.path.isfile(self.to_os_path(api_path))
176
177 def isdir(self, api_path):
178 return os.path.isdir(self.to_os_path(api_path))
179
137 def setUp(self):
180 def setUp(self):
138 nbdir = self.notebook_dir.name
139 self.blob = os.urandom(100)
140 self.b64_blob = base64.encodestring(self.blob).decode('ascii')
141
181
142 for d in (self.dirs + self.hidden_dirs):
182 for d in (self.dirs + self.hidden_dirs):
143 d.replace('/', os.sep)
183 self.make_dir(d)
144 if not os.path.isdir(pjoin(nbdir, d)):
145 os.mkdir(pjoin(nbdir, d))
146
184
147 for d, name in self.dirs_nbs:
185 for d, name in self.dirs_nbs:
148 d = d.replace('/', os.sep)
149 # create a notebook
186 # create a notebook
150 with io.open(pjoin(nbdir, d, '%s.ipynb' % name), 'w',
187 nb = new_notebook()
151 encoding='utf-8') as f:
188 self.make_nb(u'{}/{}.ipynb'.format(d, name), nb)
152 nb = new_notebook()
189
153 write(nb, f, version=4)
154
155 # create a text file
190 # create a text file
156 with io.open(pjoin(nbdir, d, '%s.txt' % name), 'w',
191 txt = self._txt_for_name(name)
157 encoding='utf-8') as f:
192 self.make_txt(u'{}/{}.txt'.format(d, name), txt)
158 f.write(self._txt_for_name(name))
193
159
160 # create a binary file
194 # create a binary file
161 with io.open(pjoin(nbdir, d, '%s.blob' % name), 'wb') as f:
195 blob = self._blob_for_name(name)
162 f.write(self._blob_for_name(name))
196 self.make_blob(u'{}/{}.blob'.format(d, name), blob)
163
197
164 self.api = API(self.base_url())
198 self.api = API(self.base_url())
165
199
166 def tearDown(self):
200 def tearDown(self):
167 nbdir = self.notebook_dir.name
168
169 for dname in (list(self.top_level_dirs) + self.hidden_dirs):
201 for dname in (list(self.top_level_dirs) + self.hidden_dirs):
170 shutil.rmtree(pjoin(nbdir, dname), ignore_errors=True)
202 self.delete_dir(dname)
171
203 self.delete_file('inroot.ipynb')
172 if os.path.isfile(pjoin(nbdir, 'inroot.ipynb')):
173 os.unlink(pjoin(nbdir, 'inroot.ipynb'))
174
204
175 def test_list_notebooks(self):
205 def test_list_notebooks(self):
176 nbs = notebooks_only(self.api.list().json())
206 nbs = notebooks_only(self.api.list().json())
@@ -204,11 +234,8 class APITest(NotebookTestBase):
204 self.assertEqual(nbnames, expected)
234 self.assertEqual(nbnames, expected)
205
235
206 def test_list_dirs(self):
236 def test_list_dirs(self):
207 print(self.api.list().json())
208 dirs = dirs_only(self.api.list().json())
237 dirs = dirs_only(self.api.list().json())
209 dir_names = {normalize('NFC', d['name']) for d in dirs}
238 dir_names = {normalize('NFC', d['name']) for d in dirs}
210 print(dir_names)
211 print(self.top_level_dirs)
212 self.assertEqual(dir_names, self.top_level_dirs) # Excluding hidden dirs
239 self.assertEqual(dir_names, self.top_level_dirs) # Excluding hidden dirs
213
240
214 def test_list_nonexistant_dir(self):
241 def test_list_nonexistant_dir(self):
@@ -261,8 +288,10 class APITest(NotebookTestBase):
261 self.assertIn('content', model)
288 self.assertIn('content', model)
262 self.assertEqual(model['format'], 'base64')
289 self.assertEqual(model['format'], 'base64')
263 self.assertEqual(model['type'], 'file')
290 self.assertEqual(model['type'], 'file')
264 b64_data = base64.encodestring(self._blob_for_name(name)).decode('ascii')
291 self.assertEqual(
265 self.assertEqual(model['content'], b64_data)
292 base64.decodestring(model['content'].encode('ascii')),
293 self._blob_for_name(name),
294 )
266
295
267 # Name that doesn't exist - should be a 404
296 # Name that doesn't exist - should be a 404
268 with assert_http_error(404):
297 with assert_http_error(404):
@@ -283,11 +312,8 class APITest(NotebookTestBase):
283 self.assertEqual(rjson['name'], path.rsplit('/', 1)[-1])
312 self.assertEqual(rjson['name'], path.rsplit('/', 1)[-1])
284 self.assertEqual(rjson['path'], path)
313 self.assertEqual(rjson['path'], path)
285 self.assertEqual(rjson['type'], type)
314 self.assertEqual(rjson['type'], type)
286 isright = os.path.isdir if type == 'directory' else os.path.isfile
315 isright = self.isdir if type == 'directory' else self.isfile
287 assert isright(pjoin(
316 assert isright(path)
288 self.notebook_dir.name,
289 path.replace('/', os.sep),
290 ))
291
317
292 def test_create_untitled(self):
318 def test_create_untitled(self):
293 resp = self.api.create_untitled(path=u'å b')
319 resp = self.api.create_untitled(path=u'å b')
@@ -451,7 +477,7 class APITest(NotebookTestBase):
451 self.assertEqual(resp.headers['Location'].split('/')[-1], 'z.ipynb')
477 self.assertEqual(resp.headers['Location'].split('/')[-1], 'z.ipynb')
452 self.assertEqual(resp.json()['name'], 'z.ipynb')
478 self.assertEqual(resp.json()['name'], 'z.ipynb')
453 self.assertEqual(resp.json()['path'], 'foo/z.ipynb')
479 self.assertEqual(resp.json()['path'], 'foo/z.ipynb')
454 assert os.path.isfile(pjoin(self.notebook_dir.name, 'foo', 'z.ipynb'))
480 assert self.isfile('foo/z.ipynb')
455
481
456 nbs = notebooks_only(self.api.list('foo').json())
482 nbs = notebooks_only(self.api.list('foo').json())
457 nbnames = set(n['name'] for n in nbs)
483 nbnames = set(n['name'] for n in nbs)
@@ -471,11 +497,6 class APITest(NotebookTestBase):
471 nbmodel= {'content': nb, 'type': 'notebook'}
497 nbmodel= {'content': nb, 'type': 'notebook'}
472 resp = self.api.save('foo/a.ipynb', body=json.dumps(nbmodel))
498 resp = self.api.save('foo/a.ipynb', body=json.dumps(nbmodel))
473
499
474 nbfile = pjoin(self.notebook_dir.name, 'foo', 'a.ipynb')
475 with io.open(nbfile, 'r', encoding='utf-8') as f:
476 newnb = read(f, as_version=4)
477 self.assertEqual(newnb.cells[0].source,
478 u'Created by test ³')
479 nbcontent = self.api.read('foo/a.ipynb').json()['content']
500 nbcontent = self.api.read('foo/a.ipynb').json()['content']
480 newnb = from_dict(nbcontent)
501 newnb = from_dict(nbcontent)
481 self.assertEqual(newnb.cells[0].source,
502 self.assertEqual(newnb.cells[0].source,
@@ -2,7 +2,6
2 """Tests for the notebook manager."""
2 """Tests for the notebook manager."""
3 from __future__ import print_function
3 from __future__ import print_function
4
4
5 import logging
6 import os
5 import os
7
6
8 from tornado.web import HTTPError
7 from tornado.web import HTTPError
@@ -17,11 +16,31 from IPython.html.utils import url_path_join
17 from IPython.testing import decorators as dec
16 from IPython.testing import decorators as dec
18
17
19 from ..filemanager import FileContentsManager
18 from ..filemanager import FileContentsManager
20 from ..manager import ContentsManager
19
20
21 def _make_dir(contents_manager, api_path):
22 """
23 Make a directory.
24 """
25 os_path = contents_manager._get_os_path(api_path)
26 try:
27 os.makedirs(os_path)
28 except OSError:
29 print("Directory already exists: %r" % os_path)
21
30
22
31
23 class TestFileContentsManager(TestCase):
32 class TestFileContentsManager(TestCase):
24
33
34 def symlink(self, contents_manager, src, dst):
35 """Make a symlink to src from dst
36
37 src and dst are api_paths
38 """
39 src_os_path = contents_manager._get_os_path(src)
40 dst_os_path = contents_manager._get_os_path(dst)
41 print(src_os_path, dst_os_path, os.path.isfile(src_os_path))
42 os.symlink(src_os_path, dst_os_path)
43
25 def test_root_dir(self):
44 def test_root_dir(self):
26 with TemporaryDirectory() as td:
45 with TemporaryDirectory() as td:
27 fm = FileContentsManager(root_dir=td)
46 fm = FileContentsManager(root_dir=td)
@@ -69,10 +88,44 class TestFileContentsManager(TestCase):
69 self.assertNotEqual(cp_dir, cp_subdir)
88 self.assertNotEqual(cp_dir, cp_subdir)
70 self.assertEqual(cp_dir, os.path.join(root, fm.checkpoint_dir, cp_name))
89 self.assertEqual(cp_dir, os.path.join(root, fm.checkpoint_dir, cp_name))
71 self.assertEqual(cp_subdir, os.path.join(root, subd, fm.checkpoint_dir, cp_name))
90 self.assertEqual(cp_subdir, os.path.join(root, subd, fm.checkpoint_dir, cp_name))
91
92 @dec.skip_win32
93 def test_bad_symlink(self):
94 with TemporaryDirectory() as td:
95 cm = FileContentsManager(root_dir=td)
96 path = 'test bad symlink'
97 _make_dir(cm, path)
72
98
99 file_model = cm.new_untitled(path=path, ext='.txt')
100
101 # create a broken symlink
102 self.symlink(cm, "target", '%s/%s' % (path, 'bad symlink'))
103 model = cm.get(path)
104 self.assertEqual(model['content'], [file_model])
105
106 @dec.skip_win32
107 def test_good_symlink(self):
108 with TemporaryDirectory() as td:
109 cm = FileContentsManager(root_dir=td)
110 parent = 'test good symlink'
111 name = 'good symlink'
112 path = '{0}/{1}'.format(parent, name)
113 _make_dir(cm, parent)
114
115 file_model = cm.new(path=parent + '/zfoo.txt')
116
117 # create a good symlink
118 self.symlink(cm, file_model['path'], path)
119 symlink_model = cm.get(path, content=False)
120 dir_model = cm.get(parent)
121 self.assertEqual(
122 sorted(dir_model['content'], key=lambda x: x['name']),
123 [symlink_model, file_model],
124 )
73
125
74 class TestContentsManager(TestCase):
75
126
127 class TestContentsManager(TestCase):
128
76 def setUp(self):
129 def setUp(self):
77 self._temp_dir = TemporaryDirectory()
130 self._temp_dir = TemporaryDirectory()
78 self.td = self._temp_dir.name
131 self.td = self._temp_dir.name
@@ -83,15 +136,12 class TestContentsManager(TestCase):
83 def tearDown(self):
136 def tearDown(self):
84 self._temp_dir.cleanup()
137 self._temp_dir.cleanup()
85
138
86 def make_dir(self, abs_path, rel_path):
139 def make_dir(self, api_path):
87 """make subdirectory, rel_path is the relative path
140 """make a subdirectory at api_path
88 to that directory from the location where the server started"""
141
89 os_path = os.path.join(abs_path, rel_path)
142 override in subclasses if contents are not on the filesystem.
90 try:
143 """
91 os.makedirs(os_path)
144 _make_dir(self.contents_manager, api_path)
92 except OSError:
93 print("Directory already exists: %r" % os_path)
94 return os_path
95
145
96 def add_code_cell(self, nb):
146 def add_code_cell(self, nb):
97 output = nbformat.new_output("display_data", {'application/javascript': "alert('hi');"})
147 output = nbformat.new_output("display_data", {'application/javascript': "alert('hi');"})
@@ -169,7 +219,7 class TestContentsManager(TestCase):
169
219
170 # Test in sub-directory
220 # Test in sub-directory
171 sub_dir = '/foo/'
221 sub_dir = '/foo/'
172 self.make_dir(cm.root_dir, 'foo')
222 self.make_dir('foo')
173 model = cm.new_untitled(path=sub_dir, ext='.ipynb')
223 model = cm.new_untitled(path=sub_dir, ext='.ipynb')
174 model2 = cm.get(sub_dir + name)
224 model2 = cm.get(sub_dir + name)
175 assert isinstance(model2, dict)
225 assert isinstance(model2, dict)
@@ -179,46 +229,59 class TestContentsManager(TestCase):
179 self.assertEqual(model2['name'], 'Untitled.ipynb')
229 self.assertEqual(model2['name'], 'Untitled.ipynb')
180 self.assertEqual(model2['path'], '{0}/{1}'.format(sub_dir.strip('/'), name))
230 self.assertEqual(model2['path'], '{0}/{1}'.format(sub_dir.strip('/'), name))
181
231
232 # Test with a regular file.
233 file_model_path = cm.new_untitled(path=sub_dir, ext='.txt')['path']
234 file_model = cm.get(file_model_path)
235 self.assertDictContainsSubset(
236 {
237 'content': u'',
238 'format': u'text',
239 'mimetype': u'text/plain',
240 'name': u'untitled.txt',
241 'path': u'foo/untitled.txt',
242 'type': u'file',
243 'writable': True,
244 },
245 file_model,
246 )
247 self.assertIn('created', file_model)
248 self.assertIn('last_modified', file_model)
249
182 # Test getting directory model
250 # Test getting directory model
251
252 # Create a sub-sub directory to test getting directory contents with a
253 # subdir.
254 self.make_dir('foo/bar')
183 dirmodel = cm.get('foo')
255 dirmodel = cm.get('foo')
184 self.assertEqual(dirmodel['type'], 'directory')
256 self.assertEqual(dirmodel['type'], 'directory')
257 self.assertIsInstance(dirmodel['content'], list)
258 self.assertEqual(len(dirmodel['content']), 3)
259 self.assertEqual(dirmodel['path'], 'foo')
260 self.assertEqual(dirmodel['name'], 'foo')
261
262 # Directory contents should match the contents of each individual entry
263 # when requested with content=False.
264 model2_no_content = cm.get(sub_dir + name, content=False)
265 file_model_no_content = cm.get(u'foo/untitled.txt', content=False)
266 sub_sub_dir_no_content = cm.get('foo/bar', content=False)
267 self.assertEqual(sub_sub_dir_no_content['path'], 'foo/bar')
268 self.assertEqual(sub_sub_dir_no_content['name'], 'bar')
269
270 for entry in dirmodel['content']:
271 # Order isn't guaranteed by the spec, so this is a hacky way of
272 # verifying that all entries are matched.
273 if entry['path'] == sub_sub_dir_no_content['path']:
274 self.assertEqual(entry, sub_sub_dir_no_content)
275 elif entry['path'] == model2_no_content['path']:
276 self.assertEqual(entry, model2_no_content)
277 elif entry['path'] == file_model_no_content['path']:
278 self.assertEqual(entry, file_model_no_content)
279 else:
280 self.fail("Unexpected directory entry: %s" % entry())
185
281
186 with self.assertRaises(HTTPError):
282 with self.assertRaises(HTTPError):
187 cm.get('foo', type='file')
283 cm.get('foo', type='file')
188
284
189
190 @dec.skip_win32
191 def test_bad_symlink(self):
192 cm = self.contents_manager
193 path = 'test bad symlink'
194 os_path = self.make_dir(cm.root_dir, path)
195
196 file_model = cm.new_untitled(path=path, ext='.txt')
197
198 # create a broken symlink
199 os.symlink("target", os.path.join(os_path, "bad symlink"))
200 model = cm.get(path)
201 self.assertEqual(model['content'], [file_model])
202
203 @dec.skip_win32
204 def test_good_symlink(self):
205 cm = self.contents_manager
206 parent = 'test good symlink'
207 name = 'good symlink'
208 path = '{0}/{1}'.format(parent, name)
209 os_path = self.make_dir(cm.root_dir, parent)
210
211 file_model = cm.new(path=parent + '/zfoo.txt')
212
213 # create a good symlink
214 os.symlink(file_model['name'], os.path.join(os_path, name))
215 symlink_model = cm.get(path, content=False)
216 dir_model = cm.get(parent)
217 self.assertEqual(
218 sorted(dir_model['content'], key=lambda x: x['name']),
219 [symlink_model, file_model],
220 )
221
222 def test_update(self):
285 def test_update(self):
223 cm = self.contents_manager
286 cm = self.contents_manager
224 # Create a notebook
287 # Create a notebook
@@ -240,9 +303,8 class TestContentsManager(TestCase):
240 # Test in sub-directory
303 # Test in sub-directory
241 # Create a directory and notebook in that directory
304 # Create a directory and notebook in that directory
242 sub_dir = '/foo/'
305 sub_dir = '/foo/'
243 self.make_dir(cm.root_dir, 'foo')
306 self.make_dir('foo')
244 model = cm.new_untitled(path=sub_dir, type='notebook')
307 model = cm.new_untitled(path=sub_dir, type='notebook')
245 name = model['name']
246 path = model['path']
308 path = model['path']
247
309
248 # Change the name in the model for rename
310 # Change the name in the model for rename
@@ -279,7 +341,7 class TestContentsManager(TestCase):
279 # Test in sub-directory
341 # Test in sub-directory
280 # Create a directory and notebook in that directory
342 # Create a directory and notebook in that directory
281 sub_dir = '/foo/'
343 sub_dir = '/foo/'
282 self.make_dir(cm.root_dir, 'foo')
344 self.make_dir('foo')
283 model = cm.new_untitled(path=sub_dir, type='notebook')
345 model = cm.new_untitled(path=sub_dir, type='notebook')
284 name = model['name']
346 name = model['name']
285 path = model['path']
347 path = model['path']
@@ -301,6 +363,9 class TestContentsManager(TestCase):
301 # Delete the notebook
363 # Delete the notebook
302 cm.delete(path)
364 cm.delete(path)
303
365
366 # Check that deleting a non-existent path raises an error.
367 self.assertRaises(HTTPError, cm.delete, path)
368
304 # Check that a 'get' on the deleted notebook raises and error
369 # Check that a 'get' on the deleted notebook raises and error
305 self.assertRaises(HTTPError, cm.get, path)
370 self.assertRaises(HTTPError, cm.get, path)
306
371
@@ -309,9 +374,9 class TestContentsManager(TestCase):
309 parent = u'å b'
374 parent = u'å b'
310 name = u'nb √.ipynb'
375 name = u'nb √.ipynb'
311 path = u'{0}/{1}'.format(parent, name)
376 path = u'{0}/{1}'.format(parent, name)
312 os.mkdir(os.path.join(cm.root_dir, parent))
377 self.make_dir(parent)
313 orig = cm.new(path=path)
314
378
379 orig = cm.new(path=path)
315 # copy with unspecified name
380 # copy with unspecified name
316 copy = cm.copy(path)
381 copy = cm.copy(path)
317 self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy1.ipynb'))
382 self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy1.ipynb'))
@@ -366,3 +431,4 class TestContentsManager(TestCase):
366 cm.mark_trusted_cells(nb, path)
431 cm.mark_trusted_cells(nb, path)
367 cm.check_and_sign(nb, path)
432 cm.check_and_sign(nb, path)
368 assert cm.notary.check_signature(nb)
433 assert cm.notary.check_signature(nb)
434
@@ -30,6 +30,7 class NotebookTestBase(TestCase):
30 """
30 """
31
31
32 port = 12341
32 port = 12341
33 config = None
33
34
34 @classmethod
35 @classmethod
35 def wait_until_alive(cls):
36 def wait_until_alive(cls):
@@ -65,6 +66,7 class NotebookTestBase(TestCase):
65 open_browser=False,
66 open_browser=False,
66 ipython_dir=cls.ipython_dir.name,
67 ipython_dir=cls.ipython_dir.name,
67 notebook_dir=cls.notebook_dir.name,
68 notebook_dir=cls.notebook_dir.name,
69 config=cls.config,
68 )
70 )
69
71
70 # clear log handlers and propagate to root for nose to capture it
72 # clear log handlers and propagate to root for nose to capture it
General Comments 0
You need to be logged in to leave comments. Login now