Show More
@@ -255,13 +255,18 b' class FileContentsManager(ContentsManager):' | |||||
255 | self.validate_notebook_model(model) |
|
255 | self.validate_notebook_model(model) | |
256 | return model |
|
256 | return model | |
257 |
|
257 | |||
258 | def get_model(self, path, content=True): |
|
258 | def get_model(self, path, content=True, type_=None): | |
259 | """ Takes a path for an entity and returns its model |
|
259 | """ Takes a path for an entity and returns its model | |
260 |
|
260 | |||
261 | Parameters |
|
261 | Parameters | |
262 | ---------- |
|
262 | ---------- | |
263 | path : str |
|
263 | path : str | |
264 | the API path that describes the relative path for the target |
|
264 | the API path that describes the relative path for the target | |
|
265 | content : bool | |||
|
266 | Whether to include the contents in the reply | |||
|
267 | type_ : str, optional | |||
|
268 | The requested type - 'file', 'notebook', or 'directory'. | |||
|
269 | Will raise HTTPError 406 if the content doesn't match. | |||
265 |
|
270 | |||
266 | Returns |
|
271 | Returns | |
267 | ------- |
|
272 | ------- | |
@@ -276,10 +281,16 b' class FileContentsManager(ContentsManager):' | |||||
276 |
|
281 | |||
277 | os_path = self._get_os_path(path) |
|
282 | os_path = self._get_os_path(path) | |
278 | if os.path.isdir(os_path): |
|
283 | if os.path.isdir(os_path): | |
|
284 | if type_ not in (None, 'directory'): | |||
|
285 | raise web.HTTPError(400, | |||
|
286 | u'%s is a directory, not a %s' % (path, type_)) | |||
279 | model = self._dir_model(path, content=content) |
|
287 | model = self._dir_model(path, content=content) | |
280 | elif path.endswith('.ipynb'): |
|
288 | elif type_ == 'notebook' or (type_ is None and path.endswith('.ipynb')): | |
281 | model = self._notebook_model(path, content=content) |
|
289 | model = self._notebook_model(path, content=content) | |
282 | else: |
|
290 | else: | |
|
291 | if type_ == 'directory': | |||
|
292 | raise web.HTTPError(400, | |||
|
293 | u'%s is not a directory') | |||
283 | model = self._file_model(path, content=content) |
|
294 | model = self._file_model(path, content=content) | |
284 | return model |
|
295 | return model | |
285 |
|
296 |
@@ -58,7 +58,11 b' class ContentsHandler(IPythonHandler):' | |||||
58 | of the files and directories it contains. |
|
58 | of the files and directories it contains. | |
59 | """ |
|
59 | """ | |
60 | path = path or '' |
|
60 | path = path or '' | |
61 | model = self.contents_manager.get_model(path=path) |
|
61 | type_ = self.get_query_argument('type', default=None) | |
|
62 | if type_ not in {None, 'directory', 'file', 'notebook'}: | |||
|
63 | raise web.HTTPError(400, u'Type %r is invalid' % type_) | |||
|
64 | ||||
|
65 | model = self.contents_manager.get_model(path=path, type_=type_) | |||
62 | if model['type'] == 'directory': |
|
66 | if model['type'] == 'directory': | |
63 | # group listing by type, then by name (case-insensitive) |
|
67 | # group listing by type, then by name (case-insensitive) | |
64 | # FIXME: sorting should be done in the frontends |
|
68 | # FIXME: sorting should be done in the frontends |
@@ -135,7 +135,7 b' class ContentsManager(LoggingConfigurable):' | |||||
135 | """ |
|
135 | """ | |
136 | return self.file_exists(path) or self.dir_exists(path) |
|
136 | return self.file_exists(path) or self.dir_exists(path) | |
137 |
|
137 | |||
138 | def get_model(self, path, content=True): |
|
138 | def get_model(self, path, content=True, type_=None): | |
139 | """Get the model of a file or directory with or without content.""" |
|
139 | """Get the model of a file or directory with or without content.""" | |
140 | raise NotImplementedError('must be implemented in a subclass') |
|
140 | raise NotImplementedError('must be implemented in a subclass') | |
141 |
|
141 |
@@ -46,7 +46,9 b' class API(object):' | |||||
46 | def list(self, path='/'): |
|
46 | def list(self, path='/'): | |
47 | return self._req('GET', path) |
|
47 | return self._req('GET', path) | |
48 |
|
48 | |||
49 | def read(self, path): |
|
49 | def read(self, path, type_=None): | |
|
50 | if type_ is not None: | |||
|
51 | path += '?type=' + type_ | |||
50 | return self._req('GET', path) |
|
52 | return self._req('GET', path) | |
51 |
|
53 | |||
52 | def create_untitled(self, path='/', ext='.ipynb'): |
|
54 | def create_untitled(self, path='/', ext='.ipynb'): | |
@@ -259,6 +261,13 b' class APITest(NotebookTestBase):' | |||||
259 | with assert_http_error(404): |
|
261 | with assert_http_error(404): | |
260 | self.api.read('foo/q.txt') |
|
262 | self.api.read('foo/q.txt') | |
261 |
|
263 | |||
|
264 | def test_get_bad_type(self): | |||
|
265 | with assert_http_error(400): | |||
|
266 | self.api.read(u'unicodΓ©', type_='file') # this is a directory | |||
|
267 | ||||
|
268 | with assert_http_error(400): | |||
|
269 | self.api.read(u'unicodΓ©/innonascii.ipynb', type_='directory') | |||
|
270 | ||||
262 | def _check_created(self, resp, path, type='notebook'): |
|
271 | def _check_created(self, resp, path, type='notebook'): | |
263 | self.assertEqual(resp.status_code, 201) |
|
272 | self.assertEqual(resp.status_code, 201) | |
264 | location_header = py3compat.str_to_unicode(resp.headers['Location']) |
|
273 | location_header = py3compat.str_to_unicode(resp.headers['Location']) |
@@ -159,6 +159,12 b' class TestContentsManager(TestCase):' | |||||
159 | self.assertEqual(model['name'], name) |
|
159 | self.assertEqual(model['name'], name) | |
160 | self.assertEqual(model['path'], path) |
|
160 | self.assertEqual(model['path'], path) | |
161 |
|
161 | |||
|
162 | nb_as_file = cm.get_model(path, content=True, type_='file') | |||
|
163 | self.assertEqual(nb_as_file['path'], path) | |||
|
164 | self.assertEqual(nb_as_file['type'], 'file') | |||
|
165 | self.assertEqual(nb_as_file['format'], 'text') | |||
|
166 | self.assertNotIsInstance(nb_as_file['content'], dict) | |||
|
167 | ||||
162 | # Test in sub-directory |
|
168 | # Test in sub-directory | |
163 | sub_dir = '/foo/' |
|
169 | sub_dir = '/foo/' | |
164 | self.make_dir(cm.root_dir, 'foo') |
|
170 | self.make_dir(cm.root_dir, 'foo') | |
@@ -170,6 +176,14 b' class TestContentsManager(TestCase):' | |||||
170 | self.assertIn('content', model2) |
|
176 | self.assertIn('content', model2) | |
171 | self.assertEqual(model2['name'], 'Untitled0.ipynb') |
|
177 | self.assertEqual(model2['name'], 'Untitled0.ipynb') | |
172 | self.assertEqual(model2['path'], '{0}/{1}'.format(sub_dir.strip('/'), name)) |
|
178 | self.assertEqual(model2['path'], '{0}/{1}'.format(sub_dir.strip('/'), name)) | |
|
179 | ||||
|
180 | # Test getting directory model | |||
|
181 | dirmodel = cm.get_model('foo') | |||
|
182 | self.assertEqual(dirmodel['type'], 'directory') | |||
|
183 | ||||
|
184 | with self.assertRaises(HTTPError): | |||
|
185 | cm.get_model('foo', type_='file') | |||
|
186 | ||||
173 |
|
187 | |||
174 | @dec.skip_win32 |
|
188 | @dec.skip_win32 | |
175 | def test_bad_symlink(self): |
|
189 | def test_bad_symlink(self): |
General Comments 0
You need to be logged in to leave comments.
Login now