diff --git a/IPython/html/services/contents/handlers.py b/IPython/html/services/contents/handlers.py index ea629c9..1e8bd33 100644 --- a/IPython/html/services/contents/handlers.py +++ b/IPython/html/services/contents/handlers.py @@ -117,13 +117,19 @@ class ContentsHandler(IPythonHandler): format = self.get_query_argument('format', default=None) if format not in {None, 'text', 'base64'}: raise web.HTTPError(400, u'Format %r is invalid' % format) - - model = yield gen.maybe_future(self.contents_manager.get(path=path, type=type, format=format)) - if model['type'] == 'directory': + content = self.get_query_argument('content', default='1') + if content not in {'0', '1'}: + raise web.HTTPError(400, u'Content %r is invalid' % content) + content = int(content) + + model = yield gen.maybe_future(self.contents_manager.get( + path=path, type=type, format=format, content=content, + )) + if model['type'] == 'directory' and content: # group listing by type, then by name (case-insensitive) # FIXME: sorting should be done in the frontends model['content'].sort(key=sort_key) - validate_model(model, expect_content=True) + validate_model(model, expect_content=content) self._finish_model(model, location=False) @web.authenticated diff --git a/IPython/html/services/contents/tests/test_contents_api.py b/IPython/html/services/contents/tests/test_contents_api.py index db46cb6..34e82cc 100644 --- a/IPython/html/services/contents/tests/test_contents_api.py +++ b/IPython/html/services/contents/tests/test_contents_api.py @@ -51,12 +51,14 @@ class API(object): def list(self, path='/'): return self._req('GET', path) - def read(self, path, type=None, format=None): + def read(self, path, type=None, format=None, content=None): params = {} if type is not None: params['type'] = type if format is not None: params['format'] = format + if content == False: + params['content'] = '0' return self._req('GET', path, params=params) def create_untitled(self, path='/', ext='.ipynb'): @@ -243,6 +245,14 @@ class APITest(NotebookTestBase): dir_names = {normalize('NFC', d['name']) for d in dirs} self.assertEqual(dir_names, self.top_level_dirs) # Excluding hidden dirs + 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) + def test_list_nonexistant_dir(self): with assert_http_error(404): self.api.list('nonexistant') @@ -256,10 +266,19 @@ class APITest(NotebookTestBase): self.assertEqual(nb['type'], 'notebook') self.assertIn('content', nb) self.assertEqual(nb['format'], 'json') - self.assertIn('content', nb) self.assertIn('metadata', nb['content']) self.assertIsInstance(nb['content']['metadata'], dict) + 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) + def test_get_contents_no_such_file(self): # Name that doesn't exist - should be a 404 with assert_http_error(404): diff --git a/IPython/html/static/services/contents.js b/IPython/html/static/services/contents.js index 035e2ee..263c052 100644 --- a/IPython/html/static/services/contents.js +++ b/IPython/html/static/services/contents.js @@ -72,13 +72,12 @@ define(function(require) { /** * Get a file. * - * Calls success with file JSON model, or error with error. - * * @method get * @param {String} path * @param {Object} options * type : 'notebook', 'file', or 'directory' * format: 'text' or 'base64'; only relevant for type: 'file' + * content: true or false; // whether to include the content */ Contents.prototype.get = function (path, options) { /** @@ -94,6 +93,7 @@ define(function(require) { var params = {}; if (options.type) { params.type = options.type; } if (options.format) { params.format = options.format; } + if (options.content === false) { params.content = '0'; } return utils.promising_ajax(url + '?' + $.param(params), settings); };