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

Question:

(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?

Asked By: Ram Rachum

||

Answers:

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

Answered By: bgporter

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)
Answered By: hpk42

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.

Answered By: Krisztian Fekete

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
Answered By: leszek.hanusz

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.

Answered By: Chris L. Barnes

Python 3.2+

tempfile library TemporaryDirectory() hand in hand with context manager with is the way to go. However DO note, that this PHYSICALLY creates the temporary directory (in some OS dir for temp. files (on linux probably /tmp)) – files there would actually use the storage device/disk – it may not be a problem for you, but it is something to consider when that usage would be heavy on e.g. a paid service (for alternatives see the the end of this answer post).

I also suggest using os library os.path.join() to put stuff there and to use it in general to avoid cross-platform bugs regarding or / paths.

Note: When used without context manager with you get object of TemporaryDirectory class and retrieve the name with .name
, when used in context manager you get the name string assigned to your as variable.

TL;DR : The code

import tempfile
import os
with tempfile.TemporaryDirectory() as tempdir:
  # you can e.g. create a file here:
  tmpfilepath = os.path.join(tempdir, 'someFileInTmpDir.txt')
  with open(tmpfilepath, 'w') as tmpfile:
    tmpfile.write("something")

Change the temporary directory location

Here you must a dig a bit deeper, since documentation is kind of fuzzy here: it does not document its arguments at all, but, it sends you to mkdtemp() which should use same rules and there it sends you to mkstemp() where you can finally sort of ensure yourself, that the dir argument is used to override the default directory placement.

Do you want to completely fake the I/O (input/output) operations on your filesystem?

You can try using pyfakefs as suggested in this answer: https://stackoverflow.com/a/46817032/1835470

Which one is better? faking filesystem or a physical temporary dir?

Depends on the usage – usually a combination can be a good compromise – test each filesystem operation on its own with real directories and files so you know it really works, but for your custom heavy-usage stuff use faking/mocking filesystem operations 🙂 Also for testing permissions coming from within the OS for example – it would probably be better to use the physical way.

You must always evaluate beforehand how much performance and durability is available to you and if it makes sense to make an extra testing or not.

Answered By: jave.web