Python: How do I make temporary files in my test suite?

34,152

Solution 1

See the tempfile module in the standard library -- should be all you need.

Solution 2

FWIW using py.test you can write:

def test_function(tmpdir):
    # tmpdir is a unique-per-test-function invocation temporary directory

Each test function using the "tmpdir" function argument will get a clean empty directory, created as a sub directory of "/tmp/pytest-NUM" (linux, win32 has different path) where NUM is increased for each test run. The last three directories are kept to ease inspection and older ones are automatically deleted. You can also set the base temp directory with py.test --basetemp=mytmpdir.

The tmpdir object is a py.path.local object which can also use like this:

sub = tmpdir.mkdir("sub")
sub.join("testfile.txt").write("content")

But it's also fine to just convert it to a "string" path:

tmpdir = str(tmpdir)

Solution 3

Instead of using tempfile directly I suggest using a context manager wrapper for it - the context manager takes care of removing the directory in all cases (success/failure/exception) with basically no boilerplate.

Here is how it can be used:

from tempfile import TempDir    # "tempfile" is a module in the standard library
...

# in some test:
with TempDir() as d:
    temp_file_name = os.path.join(d.name, 'your_temp_file.name')
    # create file...
    # ...
    # asserts...

I have been using a home grown version (the implementation is rather short - under 20 lines) up to the point, when I needed to use it somewhere else as well, so I looked around if there is a package ready to install, and indeed there is: tempfile


Note: the code snippet above is a little out-dated.

Solution 4

To create a temporary file with custom content for your tests you can use this class:

import os, tempfile

class TestFileContent:                                                                                                  
    def __init__(self, content):                                                                                        

        self.file = tempfile.NamedTemporaryFile(mode='w', delete=False)                                                 

        with self.file as f:                                                                                            
            f.write(content)                                                                                            

    @property                                                                                                           
    def filename(self):                                                                                                 
        return self.file.name                                                                                           

    def __enter__(self):                                                                                                
        return self                                                                                                     

    def __exit__(self, type, value, traceback):                                                                         
        os.unlink(self.filename)                                                                                        

This class will create a temporary file, write your content inside it and then close the file. You use it inside a with statement to ensure that the file is deleted after usage like this:

    with TestFileContent(
'''Hello, world
'''
    ) as test_file:

        # Here, a temporary file has been created in the file named test_file.filename with the specified content
        # This file will be deleted once you leave the with block

Solution 5

For people who come across this in the future, but also refuse to use pytest for some reason:

I wrote tempcase, a small library which provides a unittest.TestCase subclass with convenience methods for handling temporary directories. No directories are created until you request the path to them, and they are namespaced to the project, TestCase class, timestamp, and test method. They are automatically cleaned up afterwards. You can disable cleanup to inspect the output by setting a property.

There is also a decorator which can be applied to individual test cases, if you're porting code gradually.

Share:
34,152
Ram Rachum
Author by

Ram Rachum

Israeli Python developer.

Updated on November 13, 2020

Comments

  • Ram Rachum
    Ram Rachum over 3 years

    (I'm using Python 2.6 and nose.)

    I'm writing tests for my Python app. I want one test to open a new file, close it, and then delete it. Naturally, I prefer that this will happen inside a temporary directory, because I don't want to trash the user's filesystem. And, it needs to be cross-OS.

    How do I do it?