Use tempfile for write_text_file

This is more atomic and allows for checking `filepath`
before replacing the original file.
This commit is contained in:
tcely 2024-12-19 20:32:52 -05:00 committed by GitHub
parent 52865cb5b4
commit e204dea3e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -3,6 +3,7 @@ import re
import math import math
from operator import itemgetter from operator import itemgetter
from pathlib import Path from pathlib import Path
from tempfile import NamedTemporaryFile
import requests import requests
from PIL import Image from PIL import Image
from django.conf import settings from django.conf import settings
@ -114,9 +115,18 @@ def file_is_editable(filepath):
def write_text_file(filepath, filedata): def write_text_file(filepath, filedata):
if not isinstance(filedata, str): if not isinstance(filedata, str):
raise ValueError(f'filedata must be a str, got "{type(filedata)}"') raise TypeError(f'filedata must be a str, got "{type(filedata)}"')
with open(filepath, 'wt') as f: filepath_dir = str(Path(filepath).parent)
with NamedTemporaryFile(mode='wt', suffix='.tmp', prefix='', dir=filepath_dir, delete=False) as f:
new_filepath = Path(f.name)
bytes_written = f.write(filedata) bytes_written = f.write(filedata)
# chmod a+r temp_file
old_mode = new_filepath.stat().st_mode
new_filepath.chmod(0o444 | old_mode)
if not file_is_editable(new_filepath):
new_filepath.unlink()
raise ValueError(f'File cannot be edited or removed: {filepath}')
new_filepath.replace(filepath)
return bytes_written return bytes_written