186

Answers to Best way to generate random file names in Python show how to create temporary files in Python.

I only need to have a temporary file name in my case.
Calling tempfile.NamedTemporaryFile() returns a file handle after actual file creation.

Is there a way to get a filename only? I tried this:

# Trying to get temp file path
tf = tempfile.NamedTemporaryFile()
temp_file_name = tf.name
tf.close()
# Here is my real purpose to get the temp_file_name
f = gzip.open(temp_file_name ,'wb')
...
7
  • 7
    NamedTemporaryFile guarantees a unique name, (probably) by trying it and retrying if it exists. Getting just a name won't guarantee that you can actually create the file later, you're opening to the race condition of someone else using the same name before you. Commented Oct 24, 2014 at 4:24
  • 7
    @Joachim True, there is a race condition here and it would be preferred to avoid that. However, sometimes you have to pass a temporary file name to a function (file open happening internally.) Having a nicely random name gives a much better probability that the race condition will be a non-issue. I think there is a valid need to provide a good temporary filename to minimize the chance of a race condition failure. Of course adding a good prefix and suffix based on the running process and task being performed will provide even less chance of a collision. Commented Apr 6, 2015 at 18:47
  • 1
    @PolyMesh You can avoid the race condition by creating a temporary directory then using a fixed name file within it. So your function accepts a directory, rather than a file, and always creates the same file. Commented Dec 7, 2018 at 19:08
  • use tarfile and pass it the fileobj Commented May 8, 2019 at 18:58
  • 1
    @DylanYoung: While clever, isolating work to a temporary directory still exposes your code to races. Even if you explicitly change permissions on that directory to exclude competing users, you can never exclude superusers or competing processes of the same user – and, of course, you'd only be introducing even more subtle races (e.g., if a competing process creates the same temporary directory and changes that directory's permissions before you get the chance). It's probably saner just to obfuscate the temporary filename and tightly clutch your GNU manual with a white-knuckle grip. Commented Oct 21, 2021 at 6:21

10 Answers 10

122

I think the easiest, most secure way of doing this is something like:

path = os.path.join(tempfile.mkdtemp(), 'something')

A temporary directory is created that only you can access, so there should be no security issues, but there will be no files created in it, so you can just pick any filename you want to create in that directory. Remember that you do still have to delete the folder after.

edit: In Python 3 you can now use tempfile.TemporaryDirectory() as a context manager to handle deletion for you:

with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, 'something')
  # use path
Sign up to request clarification or add additional context in comments.

3 Comments

As Daniel Braun mentioned above: It is important to remember when using tempfile.mkdtemp the user is responsible for deleting the temporary directory and its contents when done with it.
If you use tempfile.TemporaryDirectory() as a context manager, it will be deleted for you.
I really like this because it handles deletion automatically. In my case, it was useful to make a temporary filename for shutil.make_archive function because it requires the archive's basename as input, not a file-like object.
100

If you want a temp file name only you can call inner tempfile function _get_candidate_names():

import tempfile

temp_name = next(tempfile._get_candidate_names())
% e.g. px9cp65s

Calling next again, will return another name, etc. This does not give you the path to temp folder. To get default 'tmp' directory, use:

defult_tmp_dir = tempfile._get_default_tempdir()
% results in: /tmp 

4 Comments

better way to create a temp directory is temp_dir = tempfile.mkdtemp(prefix='some-prefix_') which will safely create a temporary directory and return a string with the absolute path.
It's important to point out that next(tempfile._get_candidate_names()) does not necessarily return a non-existant path, that's why user-level tempfile interfaces can try several names until an unused one is found:
One could use public tempfile.gettempdir() instead of private tempfile._get_default_tempdir().
@EmanuelEy It is important to remember when using tempfile.mkdtemp the user is responsible for deleting the temporary directory and its contents when done with it.
14

tempfile.mktemp() do this.

But note that it's deprecated. However it will not create the file and it is a public function in tempfile compared to using the _get_candidate_names().

The reason it's deprecated is due to the time gap between calling this and actually trying to create the file. However in my case the chance of that is so slim and even if it would fail that would be acceptable. But it's up to you to evaluate for your usecase.

2 Comments

“even if it would fail that would be acceptable”; the race condition is not merely a risk of failure, it is a security risk (see the tempfile.mktemp documentation). So that should not be considered acceptable.
@bignose It's a potential security issue. It depends on what you want to do, the execution environment you're in, etc. That said: it may be more secure to do something like os.path.join(tempfile.mkdtemp(), 'something') There at least the directory is created (and owned by you, I presume).
13

Let's try not to overthink it:

import os, uuid, tempfile as tf

def make_temp_name(dir = tf.gettempdir()):
    return os.path.join(dir, str(uuid.uuid1()))

Comments

8

It may be a little late, but is there anything wrong with this?

import tempfile
with tempfile.NamedTemporaryFile(dir='/tmp', delete=False) as tmpfile:
    temp_file_name = tmpfile.name
f = gzip.open(temp_file_name ,'wb')

2 Comments

This code will actually create the temporary file in order to get its name, whereas in the question it says without creating actual file in Python.
This doesn't answer the question
7

Combining the previous answers, my solution is:

def get_tempfile_name(some_id):
    return os.path.join(tempfile.gettempdir(), next(tempfile._get_candidate_names()) + "_" + some_id)

Make some_id optional if not needed for you.

2 Comments

Again, the candidate names might not be actually available. This is the correct answer: stackoverflow.com/a/45803022/6387880
However, likely one needs to create random names. Nonetheless, to be sure, if _get_candidate_names() does not exist, one can default to some semi-random string generator. For example some uuid.
6

I would do it this way:

import tempfile
import os.path
import random
import string

def generate_temp_filename() -> str:
    random_string = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10))
    return os.path.join(tempfile.gettempdir(), random_string)

Advantage over other answers:

  • Does not rely on private functions (functions starting with _)
  • Does not create a file or directory
  • Does not use deprecated functions

2 Comments

...not bad, young Padawan. You're still racing competing processes, but at least you're no longer demolishing your own codebase with deprecated and/or private stdlib utility functions. If directory creation isn't a compelling concern, I'd give the tempfile.TemporaryDirectory() approach a slight nudge over this one. It's a matter of pick-your-poison at this point, really.
Deserves more upvotes. This is what I went for.
5

As Joachim Isaksson said in the comments, if you just get a name you may have problems if some other program happens to use that name before your program does. The chances are slim, but not impossible.

So the safe thing to do in this situation is to use the full GzipFile() constructor, which has the signature

GzipFile( [filename[, mode[, compresslevel[, fileobj]]]])

So you can pass it the open fileobj, and a filename as well, if you like. See the gzip docs for details.

Comments

0
from random import sample
from string import digits, ascii_letters
from tempfile import gettempdir
from pathlib import Path

filename = Path(gettempdir()) / ''.join(sample(ascii_letters + digits, 10))
## PosixPath('/tmp/fHyMSeVsY8') or
## 
filename = Path(gettempdir()).joinpath(''.join(sample(ascii_letters + digits, 10))).as_posix()
## '/tmp/fHyMSeVsY8'

f = gzip.open(filename ,'wb')

Comments

0

Native implementation of tempfile._get_candidate_names():

import os
import time
from random import Random


def generate_filename():
    rng = Random()
    rng.seed(os.getpid() + int(time.time()))
    characters = "abcdefghijklmnopqrstuvwxyz0123456789_"
    return ''.join(rng.choices(characters, k=8))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.