Skip to content

Commit 5a78710

Browse files
committed
gh-153480: Stop IDLE crashing when a file open in the editor is deleted
EditorWindow.focus_in_event calls last_mtime on every <FocusIn> event, which passed the open file path to os.path.getmtime with no guard. When another program deleted or renamed the file, refocusing the IDLE window let a FileNotFoundError escape the Tk event handler. last_mtime now returns the last known mtime when the path is inaccessible, so refocusing no longer raises and does not prompt to reload a file that is gone.
1 parent d83d267 commit 5a78710

3 files changed

Lines changed: 32 additions & 1 deletion

File tree

Lib/idlelib/editor.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,13 @@ def _close(self):
11181118

11191119
def last_mtime(self):
11201120
file = self.io.filename
1121-
return os.path.getmtime(file) if file else 0
1121+
if not file:
1122+
return 0
1123+
try:
1124+
return os.path.getmtime(file)
1125+
except OSError:
1126+
# File gone or inaccessible: keep the last known mtime.
1127+
return self.mtime
11221128

11231129
def focus_in_event(self, event):
11241130
mtime = self.last_mtime()

Lib/idlelib/idle_test/test_editor.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
"Test editor, coverage 53%."
22

33
from idlelib import editor
4+
import os
5+
import tempfile
6+
import types
47
import unittest
58
from collections import namedtuple
69
from test.support import requires
@@ -237,5 +240,25 @@ def test_rclick(self):
237240
pass
238241

239242

243+
class LastMtimeTest(unittest.TestCase):
244+
# Exercise last_mtime as an unbound method on a stub; no GUI needed.
245+
246+
def test_deleted_file_does_not_raise(self):
247+
with tempfile.TemporaryDirectory() as d:
248+
p = os.path.join(d, 'gone.py')
249+
open(p, 'w').close()
250+
mtime = os.path.getmtime(p)
251+
os.remove(p)
252+
stub = types.SimpleNamespace(
253+
io=types.SimpleNamespace(filename=p), mtime=mtime)
254+
# Must not raise; returns the last known mtime.
255+
self.assertEqual(Editor.last_mtime(stub), mtime)
256+
257+
def test_no_filename_returns_zero(self):
258+
stub = types.SimpleNamespace(
259+
io=types.SimpleNamespace(filename=None), mtime=123)
260+
self.assertEqual(Editor.last_mtime(stub), 0)
261+
262+
240263
if __name__ == '__main__':
241264
unittest.main(verbosity=2)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
IDLE no longer crashes with a traceback when a file open in the editor is
2+
deleted or renamed by another program and the editor window is refocused.

0 commit comments

Comments
 (0)