From fe3e6d1b76c8d8a9602a51af502036a641d493df Mon Sep 17 00:00:00 2001 From: Zackery Spytz Date: Thu, 12 Dec 2019 03:18:31 -0700 Subject: [PATCH 1/4] bpo-6699: IDLE: Warn the user if a file will be overwritten when saving Co-Authored-By: Guilherme Polo Co-Authored-By: Priya Pappachan --- Lib/idlelib/iomenu.py | 20 +++++++++++++++++++ .../2019-12-12-03-18-02.bpo-6699.1CqJFG.rst | 1 + 2 files changed, 21 insertions(+) create mode 100644 Misc/NEWS.d/next/IDLE/2019-12-12-03-18-02.bpo-6699.1CqJFG.rst diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py index 4b2833b8ca56f3..832a32cf366e73 100644 --- a/Lib/idlelib/iomenu.py +++ b/Lib/idlelib/iomenu.py @@ -148,14 +148,20 @@ def set_filename_change_hook(self, hook): self.filename_change_hook = hook filename = None + file_timestamp = None dirname = None def set_filename(self, filename): if filename and os.path.isdir(filename): self.filename = None + self.file_timestamp = None self.dirname = filename else: self.filename = filename + if filename is not None: + self.file_timestamp = os.stat(filename).st_mtime + else: + self.file_timestamp = None self.dirname = None self.set_saved(1) if self.filename_change_hook: @@ -339,7 +345,21 @@ def save(self, event): if not self.filename: self.save_as(event) else: + # Check the time of most recent content modification so the + # user doesn't accidentally overwrite a newer version of the file. + if self.file_timestamp != os.stat(self.filename).st_mtime: + confirm = tkMessageBox.askokcancel( + title="File has changed", + message=( + "The file has changed on disk since reading it!\n\n" + "Do you really want to overwrite it?"), + default=tkMessageBox.CANCEL, + parent=self.text) + if not confirm: + return + if self.writefile(self.filename): + self.file_timestamp = os.stat(self.filename).st_mtime self.set_saved(True) try: self.editwin.store_file_breaks() diff --git a/Misc/NEWS.d/next/IDLE/2019-12-12-03-18-02.bpo-6699.1CqJFG.rst b/Misc/NEWS.d/next/IDLE/2019-12-12-03-18-02.bpo-6699.1CqJFG.rst new file mode 100644 index 00000000000000..e7fb9bf1b3bdf6 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2019-12-12-03-18-02.bpo-6699.1CqJFG.rst @@ -0,0 +1 @@ +Warn the user if a file will be overwritten when saving. From 037c49ab61638a92797b95580aedfc96b671a08e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 27 Dec 2023 12:26:50 +0200 Subject: [PATCH 2/4] Fix errors. --- Lib/idlelib/iomenu.py | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py index ea094ab9f31e2a..8b7df210a883dc 100644 --- a/Lib/idlelib/iomenu.py +++ b/Lib/idlelib/iomenu.py @@ -67,14 +67,9 @@ def set_filename_change_hook(self, hook): def set_filename(self, filename): if filename and os.path.isdir(filename): self.filename = None - self.file_timestamp = None self.dirname = filename else: self.filename = filename - if filename is not None: - self.file_timestamp = os.stat(filename).st_mtime - else: - self.file_timestamp = None self.dirname = None self.set_saved(1) if self.filename_change_hook: @@ -133,6 +128,7 @@ def loadfile(self, filename): chars = f.read() fileencoding = f.encoding eol_convention = f.newlines + file_timestamp = os.stat(filename).st_mtime converted = False except (UnicodeDecodeError, SyntaxError): # Wait for the editor window to appear @@ -148,6 +144,7 @@ def loadfile(self, filename): chars = f.read() fileencoding = f.encoding eol_convention = f.newlines + file_timestamp = os.stat(filename).st_mtime converted = True except OSError as err: messagebox.showerror("I/O Error", str(err), parent=self.text) @@ -176,6 +173,7 @@ def loadfile(self, filename): self.text.insert("1.0", chars) self.reset_undo() self.set_filename(filename) + self.file_timestamp = file_timestamp if converted: # We need to save the conversion results first # before being able to execute the code @@ -214,16 +212,21 @@ def save(self, event): else: # Check the time of most recent content modification so the # user doesn't accidentally overwrite a newer version of the file. - if self.file_timestamp != os.stat(self.filename).st_mtime: - confirm = tkMessageBox.askokcancel( - title="File has changed", - message=( - "The file has changed on disk since reading it!\n\n" - "Do you really want to overwrite it?"), - default=tkMessageBox.CANCEL, - parent=self.text) - if not confirm: - return + try: + file_timestamp = os.stat(self.filename).st_mtime + except OSError: + pass + else: + if self.file_timestamp != file_timestamp: + confirm = messagebox.askokcancel( + title="File has changed", + message=( + "The file has changed on disk since reading it!\n\n" + "Do you really want to overwrite it?"), + default=messagebox.CANCEL, + parent=self.text) + if not confirm: + return if self.writefile(self.filename): self.file_timestamp = os.stat(self.filename).st_mtime @@ -239,6 +242,7 @@ def save_as(self, event): filename = self.asksavefile() if filename: if self.writefile(filename): + self.file_timestamp = os.stat(filename).st_mtime self.set_filename(filename) self.set_saved(1) try: From dfaf0097689d93eca0112cdc4ee0bf7a77a235ab Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 10 May 2025 19:19:11 +0300 Subject: [PATCH 3/4] Event handler should return "break". --- Lib/idlelib/iomenu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py index 8b7df210a883dc..4f767e63ff02ed 100644 --- a/Lib/idlelib/iomenu.py +++ b/Lib/idlelib/iomenu.py @@ -226,7 +226,7 @@ def save(self, event): default=messagebox.CANCEL, parent=self.text) if not confirm: - return + return "break" if self.writefile(self.filename): self.file_timestamp = os.stat(self.filename).st_mtime From 2f087a3d17cee80149169372c3aff4ac423d2518 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 10 May 2025 19:30:32 +0300 Subject: [PATCH 4/4] Refactoring. --- Lib/idlelib/iomenu.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py index 4f767e63ff02ed..fc502f7fde1780 100644 --- a/Lib/idlelib/iomenu.py +++ b/Lib/idlelib/iomenu.py @@ -128,7 +128,7 @@ def loadfile(self, filename): chars = f.read() fileencoding = f.encoding eol_convention = f.newlines - file_timestamp = os.stat(filename).st_mtime + file_timestamp = self.getmtime(filename) converted = False except (UnicodeDecodeError, SyntaxError): # Wait for the editor window to appear @@ -144,7 +144,7 @@ def loadfile(self, filename): chars = f.read() fileencoding = f.encoding eol_convention = f.newlines - file_timestamp = os.stat(filename).st_mtime + file_timestamp = self.getmtime(filename) converted = True except OSError as err: messagebox.showerror("I/O Error", str(err), parent=self.text) @@ -213,7 +213,7 @@ def save(self, event): # Check the time of most recent content modification so the # user doesn't accidentally overwrite a newer version of the file. try: - file_timestamp = os.stat(self.filename).st_mtime + file_timestamp = self.getmtime(self.filename) except OSError: pass else: @@ -229,7 +229,7 @@ def save(self, event): return "break" if self.writefile(self.filename): - self.file_timestamp = os.stat(self.filename).st_mtime + self.file_timestamp = self.getmtime(self.filename) self.set_saved(True) try: self.editwin.store_file_breaks() @@ -242,7 +242,7 @@ def save_as(self, event): filename = self.asksavefile() if filename: if self.writefile(filename): - self.file_timestamp = os.stat(filename).st_mtime + self.file_timestamp = self.getmtime(filename) self.set_filename(filename) self.set_saved(1) try: @@ -275,6 +275,9 @@ def writefile(self, filename): parent=self.text) return False + def getmtime(self, filename): + return os.stat(filename).st_mtime + def fixnewlines(self): """Return text with os eols.