考虑这个测试
import shutil, tempfile
from os import path
import unittest
from pathlib import Path
class TestExample(unittest.TestCase):
def setUp(self):
# Create a temporary directory
self.test_dir = tempfile.TemporaryDirectory()
self.test_dir2 = tempfile.mkdtemp()
def tearDown(self):
# Remove the directory after the test
shutil.rmtree(self.test_dir2)
shutil.rmtree(self.test_dir.name) #throws error
def test_something(self):
self.assertTrue(Path(self.test_dir.name).is_dir())
self.assertTrue(Path(self.test_dir2).is_dir())
if __name__ == '__main__':
unittest.main()
但是在tearDown
中会出现错误
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmpxz7ts7a7'
指的是self.test_dir.name
。
根据the source code for tempfile
,两个元素都是相同的。
def __init__(self, suffix=None, prefix=None, dir=None):
self.name = mkdtemp(suffix, prefix, dir)
self._finalizer = _weakref.finalize(
self, self._cleanup, self.name,
warn_message="Implicitly cleaning up {!r}".format(self))
我没有在上下文中使用它,所以{I} __exit__()
不应该被调用。
发生了什么事?
答案 0 :(得分:5)
不要使用shutil
清除这些内容。 tempfile.TemporaryDirectory
类提供了cleanup()
方法,如果您想要选择加入明确的清理,只需调用它。
你的代码崩溃的原因是TemporaryDirectory
类被设计为一旦超出范围(ref count为零)就自行清理。但是,由于您已经手动从文件系统中删除了目录,因此当实例随后尝试删除自身时,拆除将失败。 "没有这样的文件或目录"错误来自TemporaryDirectory
自己的拆除,而不是来自shutil.rmtree
行!
答案 1 :(得分:5)
与上下文无关:
import tempfile,os
t = tempfile.TemporaryDirectory()
s = t.name
print(os.path.isdir(s))
# os.rmdir(s) called here triggers error on the next line
t = None
print(os.path.isdir(s))
打印
True
False
因此,只要t
的引用设置为None
,就会对对象进行垃圾回收并删除目录,如documentation所示:
完成上下文或销毁临时目录对象后,新创建的临时目录及其所有内容将从文件系统中删除。
取消注释下面的代码段中的os.rmdir(s)
会在对象完成时抛出异常:
Exception ignored in: <finalize object at 0x20b20f0; dead>
Traceback (most recent call last):
File "L:\Python34\lib\weakref.py", line 519, in __call__
return info.func(*info.args, **(info.kwargs or {}))
File "L:\Python34\lib\tempfile.py", line 698, in _cleanup
_shutil.rmtree(name)
File "L:\Python34\lib\shutil.py", line 482, in rmtree
return _rmtree_unsafe(path, onerror)
File "L:\Python34\lib\shutil.py", line 364, in _rmtree_unsafe
onerror(os.listdir, path, sys.exc_info())
File "L:\Python34\lib\shutil.py", line 362, in _rmtree_unsafe
names = os.listdir(path)
所以你的调用可能会成功,但是你在对象的最终确定中获得了异常(之后)
调用cleanup()
对象方法而不是rmtree
解决了这个问题,因为对象内部状态已更新为而不是以在最终确定时尝试删除目录(如果您要求我,对象应该测试目录是否存在,然后再尝试清理它,但即使这样也不总是有效,因为它不是原子操作)
所以替换
shutil.rmtree(self.test_dir.name)
通过
self.test_dir.cleanup()
或者什么都不做,让对象在删除时清理目录。