Right way to clean up a temporary folder in Python class
Caveat: you can never guarantee that the temp folder will be deleted, because the user could always hard kill your process and then it can't run anything else.
That said, do
temp_dir = tempfile.mkdtemp()
try:
<some code>
finally:
shutil.rmtree(temp_dir)
Since this is a very common operation, Python has a special way to encapsulate "do something, execute code, clean up": a context manager. You can write your own as follows:
@contextlib.contextmanager
def make_temp_directory():
temp_dir = tempfile.mkdtemp()
try:
yield temp_dir
finally:
shutil.rmtree(temp_dir)
and use it as
with make_temp_directory() as temp_dir:
<some code>
(Note that this uses the @contextlib.contextmanager
shortcut to make a context manager. If you want to implement one the original way, you need to make a custom class with __enter__
and __exit__
methods; the __enter__
would create and return the temp directory and the __exit__
delete it.
Another alternative using contextlib
is to make your object closable, and use the closing
context manager.
class MyClass:
def __init__(self):
self.tempfolder = tempfile.mkdtemp()
def do_stuff():
pass
def close(self):
if os.path.exists(self.tempfolder):
shutil.rmtree(self.tempfolder)
Then with the context manager:
from contextlib import closing
with closing(MyClass()) as my_object:
my_object.do_stuff()
Other answers have noted that you can use a contextmanager or require your users to explicitly call some type of clean up function. These are great to do if you can. However, sometimes there's no where to hook up this cleanup because you are inside a large application and you are nested multiple layers down, and no one above you has cleanup methods or context managers.
In that case, you can use atexit: https://docs.python.org/2/library/atexit.html
import atexit
class MyClass:
def __init__(self):
self.tempfolder = tempfile.mkdtemp()
atexit.register(shutil.rmtree, self.tempfolder)
def ... #other stuff
A nice way to deal with temporary files and directories is via a context manager. This is how you can use tempfile.TemporaryFile or tempfile.NamedTemporaryFile -- once you've exited the with
statement (via normal exit, return, exception, or anything else) the file/directory and it's contents will be removed from the filesystem.
For Python 3.2+, this is built in as tempfile.TemporaryDirectory:
import tempfile
with tempfile.TemporaryDirectory() as temp_dir:
... do stuff ...
For earlier Python versions you can easily create your own context manager to do exactly the same thing. The differences here from @katrielalex answer are the passing of args to mkdtemp()
and the try/finally block to make sure the directory gets cleaned up if an exception is raised.
import contextlib
import shutil
@contextlib.contextmanager
def temporary_directory(*args, **kwargs):
d = tempfile.mkdtemp(*args, **kwargs)
try:
yield d
finally:
shutil.rmtree(d)
# use it
with temporary_directory() as temp_dir:
... do stuff ...
Note that if your process is hard-killed (eg. kill -9
) then the directories won't get cleaned up.