From 2f568643f0fc9dcc0c1f2e54330c8cd168ee6fd8 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 10 Jan 2022 11:58:22 +1100 Subject: [PATCH] Do not write new image to disk until it is successfully completed --- Tests/test_image.py | 9 +++++++++ src/PIL/Image.py | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/Tests/test_image.py b/Tests/test_image.py index 2d46d760d..7c1caee1f 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -641,6 +641,15 @@ class TestImage: im.save(temp_file) assert not record + def test_no_new_file_on_error(self, tmp_path): + temp_file = str(tmp_path / "temp.jpg") + + im = Image.new("RGB", (0, 0)) + with pytest.raises(SystemError): + im.save(temp_file) + + assert not os.path.exists(temp_file) + def test_load_on_nonexclusive_multiframe(self): with open("Tests/images/frozenpond.mpo", "rb") as fp: diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 69089a290..cf3be4b91 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -2202,16 +2202,23 @@ class Image: else: save_handler = SAVE[format.upper()] + new_file = False if open_fp: if params.get("append", False): # Open also for reading ("+"), because TIFF save_all # writer needs to go back and edit the written data. fp = builtins.open(filename, "r+b") + elif not os.path.exists(filename): + new_file = True + fp = io.BytesIO() else: fp = builtins.open(filename, "w+b") try: save_handler(self, fp, filename) + if new_file: + with builtins.open(filename, "w+b") as new_file_fp: + new_file_fp.write(fp.getvalue()) finally: # do what we can to clean up if open_fp: