Reputation: 523
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.
Upvotes: 6
Views: 6829
Reputation: 136605
You can use NamedTemporaryFile as a context manager:
from tempfile import NamedTemporaryFile
with NamedTemporaryFile() as tmp:
tmp.write(b'Hi')
p = Popen(['cmd', '/c', 'type', tmp.name])
p.wait()
# Here the file is closed and thus deleted
Upvotes: 14
Reputation: 349
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)
Upvotes: 5