tempfile: changing 'delete' property of NamedTemporaryFile after creation

Sometimes, one creates a file that should be persisted somewhere, but only after lots of work and/or sanity checks. For that, it would be useful to be able to create a tempfile.NamedTemporaryFile with the default delete=True, but then, once all the work is done and the file is to be kept, one should be able to do

os.rename(f.name, final_location)
f.set_delete(False) # this 
f.close()

In fact, since the object one gets from the NamedTemporaryFile() call has a .delete property, one is easily led to believe that it’s possible to modify that with the expected result, in the same way that .name is a public property. But the current implementation copies the delete flag to the closer helper object, and obviously user code should not do f._closer.delete = False.

So I’d like to have either a set_delete() method on the _TemporaryFileWrapper object, or alternatively that assigning directly to its .delete property should have the expected effect.

Perl’s corresponding File::Temp provides this via an ->unlink_on_destroy method.

2 Likes

It would be much easier to create it with delete=False and then delete it if you no longer need it using os.remove(temp_file.name)

Is that still true if the temporary file is used as a context manager (as it should be imo)? You’d have to wrap it all in a careful try-except, which seems error prone.

The closure of the file is managed by _TemporaryFileCloser

import tempfile
import os
import time
import shutil

# Create a temporary file with delete=False
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
    # Do some operations with the temporary file
    temp_file.write(b"Hello, World!")
    temp_file.seek(0)
    data = temp_file.read()
    print("Data from temporary file:", data)
    
    print("Temporary file path:", temp_file.name)

time.sleep(10.0)

# Copy file
shutil.copy(temp_file.name, 'tmp_file')

# Delete the temporary file manually when you're done with it
os.remove(temp_file.name)

In my opinion, it’s better for all bracketing patterns to be context managers. Otherwise, as in your code, if copy raises an exception, then the file won’t be deleted.

Note that on Windows the file is deleted by the OS and Python cannot change this once the file is created.

My experience has led me to always implement the following workflow:

  1. Create a temporary directory (using TemporaryDirectory context manager) on at least the same mount as the intended final location (easiest choice is the same directory as the intended final location but not always possible for some workflows)
  2. Create the file with the same name as the intended final name inside the temporary directory
  3. Do any work required
  4. If keeping the file move it to the correct directory
  5. If not keeping the file do not move
  6. Let the context manager exit, so the temporary directory and any of it’s contents are cleaned up

Personally I have found this works well regardless of platform.

1 Like