diff --git a/notebook/services/contents/filemanager.py b/notebook/services/contents/filemanager.py index aa89e0ab1d..f8ad4c9a00 100644 --- a/notebook/services/contents/filemanager.py +++ b/notebook/services/contents/filemanager.py @@ -14,6 +14,7 @@ import mimetypes import nbformat +from send2trash import send2trash from tornado import web from .filecheckpoints import FileCheckpoints @@ -149,6 +150,11 @@ def _validate_root_dir(self, proposal): def _checkpoints_class_default(self): return FileCheckpoints + delete_to_trash = Bool(True, config=True, + help="""If True (default), deleting files will send them to the + platform's trash/recycle bin, where they can be recovered. If False, + deleting files really deletes them.""") + @default('files_handler_class') def _files_handler_class_default(self): return AuthenticatedFileHandler @@ -493,6 +499,14 @@ def delete_file(self, path): elif not os.path.isfile(os_path): raise web.HTTPError(404, u'File does not exist: %s' % os_path) + if self.delete_to_trash: + self.log.debug("Sending %s to trash", os_path) + # Looking at the code in send2trash, I don't think the errors it + # raises let us distinguish permission errors from other errors in + # code. So for now, just let them all get logged as server errors. + send2trash(os_path) + return + if os.path.isdir(os_path): self.log.debug("Removing directory %s", os_path) with self.perm_to_403(): diff --git a/setup.py b/setup.py index 1bab382833..7add23d2bb 100755 --- a/setup.py +++ b/setup.py @@ -152,6 +152,7 @@ 'nbformat', 'nbconvert', 'ipykernel', # bless IPython kernel for now + 'Send2Trash', ] extras_require = { ':sys_platform != "win32"': ['terminado>=0.3.3'],