在ubuntu服务器上开了jupyter,远程访问的时候,在UI界面上删除某个文件,前端提示Delete Failed Invalid response: 500 Internal Server Error。
服务器后端报错信息如下:
[W 11:14:20.929 LabApp] delete /data/jiangtan/untitled.txt
[E 11:14:20.931 LabApp] Uncaught exception DELETE
Traceback (most recent call last):
File "/home/jiangtanzju/software/anaconda3/lib/python3.7/site-packages/tornado/web.py", line 1592, in _execute
result = yield result
File "/home/jiangtanzju/software/anaconda3/lib/python3.7/site-packages/tornado/gen.py", line 1133, in run
value = future.result()
File "/home/jiangtanzju/software/anaconda3/lib/python3.7/site-packages/tornado/gen.py", line 326, in wrapper
yielded = next(result)
File "/home/jiangtanzju/software/anaconda3/lib/python3.7/site-packages/notebook/services/contents/handlers.py", line 235, in delete
yield gen.maybe_future(cm.delete(path))
File "/home/jiangtanzju/software/anaconda3/lib/python3.7/site-packages/notebook/services/contents/manager.py", line 279, in delete
self.delete_file(path)
File "/home/jiangtanzju/software/anaconda3/lib/python3.7/site-packages/notebook/services/contents/filemanager.py", line 540, in delete_file
send2trash(os_path)
File "/home/jiangtanzju/software/anaconda3/lib/python3.7/site-packages/send2trash/plat_other.py", line 192, in send2trash
trash_move(path_b, dest_trash, topdir)
File "/home/jiangtanzju/software/anaconda3/lib/python3.7/site-packages/send2trash/plat_other.py", line 103, in trash_move
os.rename(src, op.join(filespath, destname))
OSError: [Errno 18] Invalid cross-device link: b'/data/jiangtan/untitled.txt' -> b'/home/jiangtanzju/.local/share/Trash/files/untitled 1.txt'
解决方案
在.jupyter/jupyter_notebook_config.py
文件中加入(会导致删除后的文件无法恢复):
c.FileContentsManager.delete_to_trash = False
保存后重新启动jupyter即可
原因
在jupyter的前端删除一个文件时,开发者希望能够把文件移动到垃圾箱里(原因见此撕逼记录),于是他们使用了send2trash这个python包来实现。但这个包的使用有众多的限制,例如要求在linux平台下被删除的文件必须和用户主目录位于同一设备上,否则就会报我上面贴的那个OSError: [Errno 18]这个error。
于是在这种情况下,后端会在用户删除文件的时候,粗略的检查一下该情况下是否能使用send2trash(源码):
但这种粗略的判断会遗漏掉很多情况,例如开启jupyter的用户,其主目录是位于一个docker容器内。在这种情况下,删除文件的路径和用户主目录并不在同一设备下,而这种判断方式却认为是在同一设备中,从而导致了send2trash的误用。
我推断上方的解决方案中加入的c.FileContentsManager.delete_to_trash = False
就是让这里的self.delete_to_trash变成了False,从而强制不使用send2trash,强制删除文件而不是移动文件到垃圾箱,于是避免了error。
开发者同样在一个issue里指出了这一个小BUG:
不过看了看当时开发者提PR的comments,感觉这个BUG是不会修复了…
不过讲道理,我觉得这个主要是os.rename的锅,也就是send2trash这个包的问题,同样也有人提了相关issue,如jupyterlab#5781,不过尚未得到有效回复和解决。