vedar vedar - 5 months ago 18
Python Question

Context manager to remove tempfile

I'm trying to write context manager to conditionally cleanup tempfile after processing. Simplified:

import os
from contextlib import contextmanager
from subprocess import Popen
from tempfile import NamedTemporaryFile


@contextmanager
def temp(cleanup=True):
tmp = NamedTemporaryFile(delete=False)
try:
yield tmp
finally:
cleanup and os.remove(tmp.name)

with temp() as tmp:
tmp.write(b'Hi')
p = Popen(['cmd', '/c', 'type', tmp.name])
p.wait()


Trying this script raises:

Traceback (most recent call last):
File "C:\temp\test.py", line 18, in <module>
p.wait()
File "C:\Python35\lib\contextlib.py", line 66, in __exit__
next(self.gen)
File "C:\temp\test.py", line 13, in temp
cleanup and os.remove(tmp.name)
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\Temp\\tmp79su99sg'


I would expect that tempfile is freed at the end of with statement cycle, while apparently it is not.

Answer

Indeed your file is open when you are trying to remove it. You'll have to close the file first before removing it:

@contextmanager
def temp(cleanup=True):
    tmp = NamedTemporaryFile(delete=False)
    try:
        yield tmp
    finally:
        tmp.close() #closes the file, so we can right remove it
        cleanup and os.remove(tmp.name)

Another option is to wrap the file-object with a context-manager:

@contextmanager
def temp(cleanup=True):
    tmp = NamedTemporaryFile(delete=False)
    try:
        with tmp:
            yield tmp
    finally:
        cleanup and os.remove(tmp.name)
Comments