8

What is the way to rename the following tempfile

pdf = render_me_some_pdf() #PDF RENDER
f = tempfile.NamedTemporaryFile()
f.write(pdf)
f.flush()

I read somethings about os.rename but I don't really now how to apply it

nelsonvarela
  • 2,310
  • 7
  • 27
  • 43
  • possible duplicate of [How do I persist to disk a temporary file using Python?](http://stackoverflow.com/questions/94153/how-do-i-persist-to-disk-a-temporary-file-using-python) – ThiefMaster May 11 '12 at 08:27
  • how is this a duplicate? it's entirely different question – Feline Aug 16 '21 at 15:17

2 Answers2

39

The best way is copying the file and letting python delete the temporary one when it's closed:

I actually think you would be better off using os.link:

with tempfile.NamedTemporaryFile(dir=os.path.dirname(actual_name)) as f:
  f.write(pdf)
  os.link(f.name, actual_name)

This uses os.link to create a hard link to the temporary file, which will persist after the temporary file is automatically deleted.

This code has several advantages:

  • We're using the tempfile object as a context manager, so we don't need to worry about closing it explicitly.
  • Since we're creating a hardlink to the file, rather than copying it, we don't need to worry about disk space or time consumption due to copying a large file.
  • Since we're not copying the data, we don't need to call f.flush(). The file will be flushed automatically when it's closed.
larsks
  • 277,717
  • 41
  • 399
  • 399
  • 1
    There is a limitation: In Unix/Linux hard links are only allowed on the same file system. – spatar Dec 24 '19 at 20:04
  • 2
    @spatar this is dealt with by specifying the `dir` parameter and putting the file in the same directory you want the end file to be in. This way there is no attempt to link across file systems. – tresni Apr 26 '20 at 01:39
  • 5
    Limitation: this can't be used to overwrite an existing file, and will instead fail with EEXIST – Gavin S. Yancey Oct 07 '20 at 08:03
  • 1
    @Feline It doesn't, actually: this is a pretty common thing to do. You create a temporary file, send your output to it, etc, and only if everything works do you rename it to the final destination. If you encounter some sort of error, you just abort and delete the tempfile. There are a lot of tools that work exactly like this. – larsks Aug 16 '21 at 15:22
  • It is worth noting that this does not work on macOS. Per `man 2 link`: `link() will fail and no link will be created if: ... [EEXIST] The link named by path2 already exists.` – Kevin M Granger Jan 12 '22 at 12:45
  • In this example, `path2` should not already exist. – larsks Jan 12 '22 at 12:53
  • Seems like it might be possible that the write is buffered and the link is created and then something fails before or even after the close and the data is not written. Seems like the best case would be f.write(pdf); f.flush(); os.fsync(f); os.link(f.name, actual_name) where the tempfile is on same fs. Then the tempfile will be closed and deleted after the link is created to the fully written tempfile. – Ian Wilson Jun 25 '22 at 22:45
10

You can access the filename via f.name. However, unless you use delete=False python will (try to) delete the temporary file automatically as soon as it is closed. Disabling auto deletion will keep the tempfile even if you do not save it - so that's not such a good idea.

The best way is copying the file and letting python delete the temporary one when it's closed:

import shutil
shutil.copy(f.name, 'new-name')
ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • 1
    Looking good. What if i want to attach the templile in an email email.attach_file(f.name) – nelsonvarela May 11 '12 at 08:43
  • @iAmTheOneAndOnly I don't know about `email.attach_file()`, but if there is also a version without `_file`, you maybe can omit the file generation altogether and just do a `email.attach(pdf)` on order to attach the PDF data itself. – glglgl May 11 '12 at 09:49
  • @ThiefMaster doesn't `shutil.copy` create a new file that then won't be deleted, more or less nullifying the use of a temporary file? – Jonathan Feb 01 '19 at 09:15
  • 5
    This solution also loses the atomicity of the rename. See https://stackoverflow.com/questions/20873723/is-pythons-shutil-copyfile-atomic – Paul Rubel Jul 16 '19 at 21:47
  • More detail here: https://stackoverflow.com/q/94153 – djvg Feb 07 '22 at 16:33