support deleting empty directories

can’t copy directories
This commit is contained in:
MinRK 2014-06-16 12:47:35 -07:00
parent 260afd76ae
commit 93b300adda
3 changed files with 40 additions and 6 deletions

View File

@ -357,7 +357,13 @@ class FileContentsManager(ContentsManager):
"""Delete file by name and path."""
path = path.strip('/')
os_path = self._get_os_path(name, path)
if not os.path.isfile(os_path):
rm = os.unlink
if os.path.isdir(os_path):
listing = os.listdir(os_path)
# don't delete non-empty directories (checkpoints dir doesn't count)
if listing and listing != ['.ipynb_checkpoints']:
raise web.HTTPError(400, u'Directory %s not empty' % os_path)
elif not os.path.isfile(os_path):
raise web.HTTPError(404, u'File does not exist: %s' % os_path)
# clear checkpoints
@ -368,8 +374,12 @@ class FileContentsManager(ContentsManager):
self.log.debug("Unlinking checkpoint %s", cp_path)
os.unlink(cp_path)
self.log.debug("Unlinking file %s", os_path)
os.unlink(os_path)
if os.path.isdir(os_path):
self.log.debug("Removing directory %s", os_path)
shutil.rmtree(os_path)
else:
self.log.debug("Unlinking file %s", os_path)
rm(os_path)
def rename(self, old_name, old_path, new_name, new_path):
"""Rename a file."""

View File

@ -7,6 +7,8 @@ from fnmatch import fnmatch
import itertools
import os
from tornado.web import HTTPError
from IPython.config.configurable import LoggingConfigurable
from IPython.nbformat import current, sign
from IPython.utils.traitlets import Instance, Unicode, List
@ -187,6 +189,8 @@ class ContentsManager(LoggingConfigurable):
"""
path = path.strip('/')
model = self.get_model(from_name, path)
if model['type'] == 'directory':
raise HTTPError(400, "Can't copy directories")
if not to_name:
base, ext = os.path.splitext(from_name)
copy_name = u'{0}-Copy{1}'.format(base, ext)

View File

@ -69,6 +69,9 @@ class API(object):
def upload(self, name, body, path='/'):
return self._req('PUT', url_path_join(path, name), body)
def mkdir(self, name, path='/'):
return self._req('PUT', url_path_join(path, name), json.dumps({'type': 'directory'}))
def copy(self, copy_from, copy_to, path='/'):
body = json.dumps({'copy_from':copy_from})
return self._req('PUT', url_path_join(path, copy_to), body)
@ -299,9 +302,7 @@ class APITest(NotebookTestBase):
self._check_created(resp, u'Upload tést.ipynb', u'å b')
def test_mkdir(self):
model = {'type': 'directory'}
resp = self.api.upload(u'New ∂ir', path=u'å b',
body=json.dumps(model))
resp = self.api.mkdir(u'New ∂ir', path=u'å b')
self._check_created(resp, u'New ∂ir', u'å b', type='directory')
def test_upload_txt(self):
@ -362,6 +363,11 @@ class APITest(NotebookTestBase):
resp = self.api.copy(u'ç d.ipynb', u'cøpy.ipynb', path=u'å b')
self._check_created(resp, u'cøpy.ipynb', u'å b')
def test_copy_dir_400(self):
# can't copy directories
with assert_http_error(400):
resp = self.api.copy(u'å b', u'å c')
def test_delete(self):
for d, name in self.dirs_nbs:
resp = self.api.delete('%s.ipynb' % name, d)
@ -371,6 +377,20 @@ class APITest(NotebookTestBase):
nbs = notebooks_only(self.api.list(d).json())
self.assertEqual(len(nbs), 0)
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:
self.api.delete(model['name'], model['path'])
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')
def test_rename(self):
resp = self.api.rename('a.ipynb', 'foo', 'z.ipynb')
self.assertEqual(resp.headers['Location'].split('/')[-1], 'z.ipynb')