##// END OF EJS Templates
support deleting empty directories...
MinRK -
Show More
@@ -357,7 +357,13 b' class FileContentsManager(ContentsManager):'
357 357 """Delete file by name and path."""
358 358 path = path.strip('/')
359 359 os_path = self._get_os_path(name, path)
360 if not os.path.isfile(os_path):
360 rm = os.unlink
361 if os.path.isdir(os_path):
362 listing = os.listdir(os_path)
363 # don't delete non-empty directories (checkpoints dir doesn't count)
364 if listing and listing != ['.ipynb_checkpoints']:
365 raise web.HTTPError(400, u'Directory %s not empty' % os_path)
366 elif not os.path.isfile(os_path):
361 367 raise web.HTTPError(404, u'File does not exist: %s' % os_path)
362 368
363 369 # clear checkpoints
@@ -368,8 +374,12 b' class FileContentsManager(ContentsManager):'
368 374 self.log.debug("Unlinking checkpoint %s", cp_path)
369 375 os.unlink(cp_path)
370 376
371 self.log.debug("Unlinking file %s", os_path)
372 os.unlink(os_path)
377 if os.path.isdir(os_path):
378 self.log.debug("Removing directory %s", os_path)
379 shutil.rmtree(os_path)
380 else:
381 self.log.debug("Unlinking file %s", os_path)
382 rm(os_path)
373 383
374 384 def rename(self, old_name, old_path, new_name, new_path):
375 385 """Rename a file."""
@@ -7,6 +7,8 b' from fnmatch import fnmatch'
7 7 import itertools
8 8 import os
9 9
10 from tornado.web import HTTPError
11
10 12 from IPython.config.configurable import LoggingConfigurable
11 13 from IPython.nbformat import current, sign
12 14 from IPython.utils.traitlets import Instance, Unicode, List
@@ -187,6 +189,8 b' class ContentsManager(LoggingConfigurable):'
187 189 """
188 190 path = path.strip('/')
189 191 model = self.get_model(from_name, path)
192 if model['type'] == 'directory':
193 raise HTTPError(400, "Can't copy directories")
190 194 if not to_name:
191 195 base, ext = os.path.splitext(from_name)
192 196 copy_name = u'{0}-Copy{1}'.format(base, ext)
@@ -69,6 +69,9 b' class API(object):'
69 69 def upload(self, name, body, path='/'):
70 70 return self._req('PUT', url_path_join(path, name), body)
71 71
72 def mkdir(self, name, path='/'):
73 return self._req('PUT', url_path_join(path, name), json.dumps({'type': 'directory'}))
74
72 75 def copy(self, copy_from, copy_to, path='/'):
73 76 body = json.dumps({'copy_from':copy_from})
74 77 return self._req('PUT', url_path_join(path, copy_to), body)
@@ -299,9 +302,7 b' class APITest(NotebookTestBase):'
299 302 self._check_created(resp, u'Upload tést.ipynb', u'å b')
300 303
301 304 def test_mkdir(self):
302 model = {'type': 'directory'}
303 resp = self.api.upload(u'New ∂ir', path=u'å b',
304 body=json.dumps(model))
305 resp = self.api.mkdir(u'New ∂ir', path=u'å b')
305 306 self._check_created(resp, u'New ∂ir', u'å b', type='directory')
306 307
307 308 def test_upload_txt(self):
@@ -362,6 +363,11 b' class APITest(NotebookTestBase):'
362 363 resp = self.api.copy(u'ç d.ipynb', u'cøpy.ipynb', path=u'å b')
363 364 self._check_created(resp, u'cøpy.ipynb', u'å b')
364 365
366 def test_copy_dir_400(self):
367 # can't copy directories
368 with assert_http_error(400):
369 resp = self.api.copy(u'å b', u'å c')
370
365 371 def test_delete(self):
366 372 for d, name in self.dirs_nbs:
367 373 resp = self.api.delete('%s.ipynb' % name, d)
@@ -371,6 +377,20 b' class APITest(NotebookTestBase):'
371 377 nbs = notebooks_only(self.api.list(d).json())
372 378 self.assertEqual(len(nbs), 0)
373 379
380 def test_delete_dirs(self):
381 # depth-first delete everything, so we don't try to delete empty directories
382 for name in sorted(self.dirs + ['/'], key=len, reverse=True):
383 listing = self.api.list(name).json()['content']
384 for model in listing:
385 self.api.delete(model['name'], model['path'])
386 listing = self.api.list('/').json()['content']
387 self.assertEqual(listing, [])
388
389 def test_delete_non_empty_dir(self):
390 """delete non-empty dir raises 400"""
391 with assert_http_error(400):
392 self.api.delete(u'å b')
393
374 394 def test_rename(self):
375 395 resp = self.api.rename('a.ipynb', 'foo', 'z.ipynb')
376 396 self.assertEqual(resp.headers['Location'].split('/')[-1], 'z.ipynb')
General Comments 0
You need to be logged in to leave comments. Login now