GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-153480: Stop IDLE crashing when a file open in the editor is deleted by tonghuaroot · Pull Request #153481 · python/cpython

Conversation

@tonghuaroot

@tonghuaroot tonghuaroot commented Jul 10, 2026 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

EditorWindow.focus_in_event runs on every <FocusIn> event and calls last_mtime, which called os.path.getmtime(self.io.filename) with no error handling. When the open file had been deleted or renamed by another program, refocusing the editor window let a FileNotFoundError escape the Tk event handler and broke the modified-on-disk reload check.

last_mtime now guards getmtime with try/except OSError and returns the last known mtime, so focus_in_event sees no change and does not prompt to reload a file that is gone. The regression test drives last_mtime as an unbound method against a duck-typed stub (no GUI) for both the deleted-file and no-filename cases.

  • Issue: IDLE fails to start or raises when an editor window's file does not exist #153480

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@tonghuaroot
pythongh-153480: Stop IDLE crashing when a file open in the editor is…
5a78710
… 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.
@tonghuaroot
tonghuaroot requested a review from terryjreedy as a code owner July 10, 2026 04:52
@bedevere-app bedevere-app Bot added the awaiting review label Jul 10, 2026
@bedevere-app bedevere-app Bot mentioned this pull request Jul 10, 2026
IDLE fails to start or raises when an editor window's file does not exist #153480
Closed
@serhiy-storchaka
Merge branch 'main' into idlelib-editor-last-mtime-oserror
2f20bc2
serhiy-storchaka
serhiy-storchaka requested changes Sep 15, 2026
View reviewed changes

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR — the FocusIn traceback is real, but the fallback return self.mtime runs too early in one case.

EditorWindow.__init__ calls io.set_filename(filename) for a filename that does not exist yet (python -m idlelib new.py), which goes set_saved(True) → last_mtime() before self.mtime is assigned at line 315. On main that already aborts IDLE at startup with FileNotFoundError (a regression from gh-94523, shipped in 3.13.15, 3.14.7 and 3.15.0b1); with this patch it aborts with AttributeError: 'EditorWindow' object has no attribute 'mtime' instead.

last_mtime() should return None when there is no file or it cannot be stat'ed (not 0, which is a valid mtime on filesystems that do not keep timestamps). A new file then opens with mtime = None, and a file that is created by another program after opening still triggers the existing reload prompt.

When the file was there and is now gone (self.mtime is not None and mtime is None), "modified by another program, reload?" is the wrong question — reloading can only fail. Ask instead what to do with the buffer: Close, Save As or Ignore, with Save As as the default. tkinter.simpledialog.SimpleDialog(..., buttons=('Close', 'Save As', 'Ignore'), default=1, cancel=2) gives such a box; .go() returns the button index. Close → self.close(). Save As → self.io.save_as(event). Ignore → set self.mtime = None and self.set_saved(False), so the window is marked as unsaved but the question is not repeated on the next FocusIn.

This is an approximate plan; details can be changed later.

Please add a test for the not-yet-existing filename (a SimpleNamespace stub without mtime is enough to catch the AttributeError), expect None in test_deleted_file_does_not_raise, and tests for the deleted-file branch with the dialog mocked.

Two smaller things: the NEWS file belongs in Misc/NEWS.d/next/IDLE/, not Library/, and open(p, 'w').close() in the test can be Path(p).touch() or a with.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@bedevere-app bedevere-app Bot added awaiting changes and removed awaiting review labels Sep 15, 2026
@tonghuaroot
pythongh-153480: Return None from last_mtime() and handle a deleted file
a57c59b
last_mtime() now returns None for a missing or un-stat-able file, which
also fixes the startup path where it runs before self.mtime is set. The
vanished-file case now offers Close, Save As or Ignore instead of a
reload that could only fail. Tests updated; NEWS moved to IDLE/.
@tonghuaroot

tonghuaroot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

Done: last_mtime() now returns None for a missing or un-stat-able file (this also fixes the startup path where it runs before self.mtime is set), and the vanished-file case shows the Close/Save As/Ignore dialog. Tests and the NEWS (moved to IDLE/) updated.

I have made the requested changes; please review again

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot added awaiting change review and removed awaiting changes labels Sep 17, 2026
@bedevere-app

bedevere-app Bot commented Sep 17, 2026

Copy link
Copy Markdown

Thanks for making the requested changes!

@serhiy-storchaka: please review the changes made to this pull request.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app
bedevere-app Bot requested a review from serhiy-storchaka September 17, 2026 04:52
@tonghuaroot
Fix end-of-file newline in editor.py and test_editor.py
e84056b
serhiy-storchaka
serhiy-storchaka reviewed Sep 17, 2026
View reviewed changes

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this works for me now: starting with a not yet existing file, Ignore, reload after the file is recreated, Close. One remaining problem with a cancelled Save As, see the comment.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/idlelib/editor.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Misc/NEWS.d/next/IDLE/2026-07-10-19-41-00.gh-issue-153480.EdMt1x.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

@tonghuaroot
pythongh-153480: Clear mtime in the deleted-file dialog before Save As
ceffab2
A cancelled Save As kept the old mtime and reprompted on every focus.
Forget the mtime for both Save As and Ignore; a successful Save As
restores it via set_saved(True). Reword the NEWS per review.
@tonghuaroot

tonghuaroot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

Fixed: the dialog now forgets the mtime for both Save As and Ignore, so a cancelled Save As no longer reprompts (a successful one restores it via set_saved(True)). Dropped the set_saved(False), applied your NEWS wording, and adjusted the tests.

I have made the requested changes; please review again

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app

bedevere-app Bot commented Sep 17, 2026

Copy link
Copy Markdown

Thanks for making the requested changes!

@serhiy-storchaka: please review the changes made to this pull request.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app
bedevere-app Bot requested a review from serhiy-storchaka September 17, 2026 10:38
serhiy-storchaka
serhiy-storchaka previously requested changes Sep 17, 2026
View reviewed changes

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found one more case: modify the file, delete it, get the focus back, choose Close. See the comment.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/idlelib/editor.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot added awaiting changes and removed awaiting change review labels Sep 17, 2026
@serhiy-storchaka serhiy-storchaka mentioned this pull request Sep 17, 2026
tkinter.simpledialog: KeyError when a dialog is opened while a window not created by tkinter holds the grab #157676
Closed
@python python deleted a comment from bedevere-app Bot Sep 22, 2026
@terryjreedy

terryjreedy commented Sep 22, 2026

Copy link
Copy Markdown
Member

@tonghuaroot Serhiy requested another change 5 days ago. I would like to get this into early October releases.

tonghuaroot reacted with eyes emoji
All reactions
  • 👀 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tonghuaroot
pythongh-153480: Clear mtime before the deleted-file dialog for all c…
9cabce6
…hoices

With a modified buffer, Close asks whether to save and the queued FocusIn
was delivered inside that message box, reopening the dialog. Forget the
mtime before showing the dialog (not only for Save As/Ignore); a
successful Save As restores it via set_saved(True).
@tonghuaroot

tonghuaroot commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

Done: self.mtime = None now runs before the dialog for all choices, so the queued FocusIn no longer reopens it on Close (a successful Save As still restores it).

I have made the requested changes; please review again

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot added awaiting change review and removed awaiting changes labels Sep 23, 2026
@bedevere-app

bedevere-app Bot commented Sep 23, 2026

Copy link
Copy Markdown

Thanks for making the requested changes!

@serhiy-storchaka: please review the changes made to this pull request.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app
bedevere-app Bot requested a review from serhiy-storchaka September 23, 2026 01:42
@python python deleted a comment from bedevere-app Bot Sep 23, 2026
@terryjreedy

terryjreedy commented Sep 23, 2026

Copy link
Copy Markdown
Member

For the future: It looks like you are force-pushing or something, so that each commit shows the cumulative change rather that just the little change made. For the last one, the diff should be a simple merge commit adding the one. We far prefer the latter for reviewing changes.

Serhiy, ready to merge?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

serhiy-storchaka
serhiy-storchaka reviewed Sep 23, 2026
View reviewed changes

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your update.

test_deleted_file_returns_none and test_not_yet_created_filename are the same test.

Optional nits: the new tests could use os_helper.temp_dir() and os_helper.create_empty_file() instead of tempfile and pathlib.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
terryjreedy
terryjreedy reviewed Sep 25, 2026
View reviewed changes
Comment thread Lib/idlelib/idle_test/test_editor.py
Comment on lines +318 to +325
def test_deleted_file_returns_none(self):
with tempfile.TemporaryDirectory() as d:
p = os.path.join(d, 'gone.py')
Path(p).touch()
os.remove(p)
stub = types.SimpleNamespace(io=types.SimpleNamespace(filename=p))
self.assertIsNone(Editor.last_mtime(stub))

@terryjreedy terryjreedy Sep 25, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Serhiy, is simply deleting one of the two specified method what you requested?

Suggested change
def test_deleted_file_returns_none(self):
with tempfile.TemporaryDirectory() as d:
p = os.path.join(d, 'gone.py')
Path(p).touch()
os.remove(p)
stub = types.SimpleNamespace(io=types.SimpleNamespace(filename=p))
self.assertIsNone(Editor.last_mtime(stub))

I am fine with not replacing the working code.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
terryjreedy
terryjreedy reviewed Sep 27, 2026
View reviewed changes

@terryjreedy terryjreedy left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm merging as is. Tests can be edited later.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@terryjreedy
terryjreedy dismissed serhiy-storchaka’s stale review September 27, 2026 01:09

Not clear which changes this refers to. Essential changes have been done.

@terryjreedy
terryjreedy enabled auto-merge (squash) September 27, 2026 01:11
terryjreedy
terryjreedy approved these changes Sep 27, 2026
View reviewed changes
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting change review labels Sep 27, 2026
@terryjreedy
terryjreedy merged commit 6af40a6 into python:main Sep 27, 2026
57 of 60 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the awaiting merge label Sep 27, 2026
@terryjreedy terryjreedy added needs backport to 3.13 only security fixes needs backport to 3.14 bugs and security fixes needs backport to 3.15 bugs and security fixes labels Sep 27, 2026
@miss-islington-app

miss-islington-app Bot commented Sep 27, 2026

Copy link
Copy Markdown

Thanks @tonghuaroot for the PR, and @terryjreedy for merging it 🌮🎉.. I'm working now to backport this PR to: 3.13.
🐍🍒⛏🤖

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@miss-islington-app

miss-islington-app Bot commented Sep 27, 2026

Copy link
Copy Markdown

Thanks @tonghuaroot for the PR, and @terryjreedy for merging it 🌮🎉.. I'm working now to backport this PR to: 3.14.
🐍🍒⛏🤖

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@miss-islington-app

miss-islington-app Bot commented Sep 27, 2026

Copy link
Copy Markdown

Thanks @tonghuaroot for the PR, and @terryjreedy for merging it 🌮🎉.. I'm working now to backport this PR to: 3.15.
🐍🍒⛏🤖

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app

bedevere-app Bot commented Sep 27, 2026

Copy link
Copy Markdown

GH-158262 is a backport of this pull request to the 3.14 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.14 bugs and security fixes label Sep 27, 2026
@bedevere-app

bedevere-app Bot commented Sep 27, 2026

Copy link
Copy Markdown

GH-158263 is a backport of this pull request to the 3.13 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.13 only security fixes label Sep 27, 2026
@bedevere-app

bedevere-app Bot commented Sep 27, 2026

Copy link
Copy Markdown

GH-158264 is a backport of this pull request to the 3.15 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.15 bugs and security fixes label Sep 27, 2026
terryjreedy pushed a commit that referenced this pull request Sep 27, 2026
@miss-islington @tonghuaroot @serhiy-storchaka
[3.13] gh-153480: Stop IDLE crashing when a file open in the editor i…
694e737
…s deleted (GH-153481) (#158263)

gh-153480: Stop IDLE crashing when a file open in the editor is deleted (GH-153481)

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.
See PR discussion for more.

---------
(cherry picked from commit 6af40a6)

Co-authored-by: tonghuaroot (童话) <[email protected]>
Co-authored-by: Serhiy Storchaka <[email protected]>
terryjreedy pushed a commit that referenced this pull request Sep 27, 2026
@miss-islington @tonghuaroot @serhiy-storchaka
[3.14] gh-153480: Stop IDLE crashing when a file open in the editor i…
cbc7753
…s deleted (GH-153481) (#158262)

gh-153480: Stop IDLE crashing when a file open in the editor is deleted (GH-153481)

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.
See PR discussion for more.

---------
(cherry picked from commit 6af40a6)

Co-authored-by: tonghuaroot (童话) <[email protected]>
Co-authored-by: Serhiy Storchaka <[email protected]>
terryjreedy added a commit that referenced this pull request Oct 9, 2026
@miss-islington @tonghuaroot
@serhiy-storchaka @terryjreedy
[3.15] gh-153480: Stop IDLE crashing when a file open in the editor i…
251e132
…s deleted (GH-153481) (#158264)

gh-153480: Stop IDLE crashing when a file open in the editor is deleted (GH-153481)

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.
See PR discussion for more.

---------
(cherry picked from commit 6af40a6)

Co-authored-by: tonghuaroot (童话) <[email protected]>
Co-authored-by: Serhiy Storchaka <[email protected]>
Co-authored-by: Terry Jan Reedy <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@serhiy-storchaka serhiy-storchaka serhiy-storchaka left review comments
@terryjreedy terryjreedy terryjreedy approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@tonghuaroot @terryjreedy @serhiy-storchaka
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.