`shutil.rmtree` не работает с` tempfile.TeilitaryDirectory () ` - PullRequest
0 голосов
/ 01 июня 2018

Рассмотрим этот тест

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.

Согласно исходный код 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))

И я не использую его в контексте, поэтому __exit__() не следует вызывать настолько, насколькоЯ понимаю.

Что происходит?

Ответы [ 2 ]

0 голосов
/ 01 июня 2018

Это не связано с контекстом:

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, объект собирается икаталог удаляется, поскольку документация гласит:

По завершении контекста или уничтожении объекта временного каталога вновь созданный временный каталог и всеего содержимое удаляется из файловой системы.

Раскомментирование 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()

или вообще ничего, пусть объект очистит каталог при удалении.

0 голосов
/ 01 июня 2018

Не очищайте их с помощью shutil.Класс tempfile.TemporaryDirectory предоставляет метод cleanup(), просто вызовите его, если вы хотите включить явную очистку.

Причина, по которой вы получаете сбой в своем коде, заключается в том, что класс TemporaryDirectoryпредназначен для очистки после себя, как только он выходит из области видимости (ref count to zero).Однако, поскольку вы уже удалили каталог из вашей файловой системы вручную, разборка завершается неудачно, когда экземпляр впоследствии пытается удалить себя.Ошибка "Нет такого файла или каталога" произошла из собственного TemporaryDirectory, это не из вашей строки shutil.rmtree!

...