Skip to content

Commit e7ab891

Browse files
gh-55646: Do not crash IDLE on an invalid key binding
A typo in a key binding, such as <Alt-Key-up> for <Alt-Key-Up>, crashed IDLE at startup. It is now ignored with a warning.
1 parent 2303eea commit e7ab891

3 files changed

Lines changed: 35 additions & 2 deletions

File tree

Lib/idlelib/idle_test/test_multicall.py

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

33
from idlelib import multicall
4+
import io
45
import unittest
56
from test.support import requires
67
from tkinter import Tk, Text
8+
from unittest import mock
79

810

911
class MultiCallTest(unittest.TestCase):
@@ -43,6 +45,15 @@ def test_yview(self):
4345
mctext = self.mc(self.root)
4446
self.assertIs(mctext.yview.__func__, Text.yview)
4547

48+
def test_invalid_binding(self):
49+
# gh-55646: an invalid key binding must not crash IDLE.
50+
mctext = self.mc(self.root)
51+
# 'up' is not a keysym; it should be 'Up'.
52+
mctext.event_add('<<test-bad>>', '<Alt-Key-up>')
53+
with mock.patch('sys.stderr', new_callable=io.StringIO) as stderr:
54+
mctext.bind('<<test-bad>>', lambda e: None) # Must not raise.
55+
self.assertIn('invalid key binding', stderr.getvalue())
56+
4657

4758
if __name__ == '__main__':
4859
unittest.main(verbosity=2)

Lib/idlelib/multicall.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,14 @@ def _triplet_to_sequence(triplet):
310310
else:
311311
return '<'+_state_names[triplet[0]]+_types[triplet[1]][0]+'>'
312312

313+
314+
def _warn_bad_binding(triplet, err):
315+
# Ignore a key binding invalidated by a typo in the user's config
316+
# instead of crashing IDLE (gh-55646).
317+
print(f'Warning: ignoring invalid key binding '
318+
f'{_triplet_to_sequence(triplet)!r}: {err}', file=sys.stderr)
319+
320+
313321
_multicall_dict = {}
314322
def MultiCallCreator(widget):
315323
"""Return a MultiCall class which inherits its methods from the
@@ -343,8 +351,15 @@ def bind(self, sequence=None, func=None, add=None):
343351
self.__binders[triplet[1]].unbind(triplet, ei[0])
344352
ei[0] = func
345353
if ei[0] is not None:
354+
bad = []
346355
for triplet in ei[1]:
347-
self.__binders[triplet[1]].bind(triplet, func)
356+
try:
357+
self.__binders[triplet[1]].bind(triplet, func)
358+
except tkinter.TclError as err:
359+
_warn_bad_binding(triplet, err)
360+
bad.append(triplet)
361+
for triplet in bad: # Drop the invalid sequences.
362+
ei[1].remove(triplet)
348363
else:
349364
self.__eventinfo[sequence] = [func, []]
350365
return widget.bind(self, sequence, func, add)
@@ -374,7 +389,11 @@ def event_add(self, virtual, *sequences):
374389
widget.event_add(self, virtual, seq)
375390
else:
376391
if func is not None:
377-
self.__binders[triplet[1]].bind(triplet, func)
392+
try:
393+
self.__binders[triplet[1]].bind(triplet, func)
394+
except tkinter.TclError as err:
395+
_warn_bad_binding(triplet, err)
396+
continue # Drop the invalid sequence.
378397
triplets.append(triplet)
379398

380399
def event_delete(self, virtual, *sequences):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix IDLE crash at startup when the user configuration contains an invalid key
2+
binding, such as ``<Alt-Key-up>`` instead of ``<Alt-Key-Up>``. The invalid
3+
binding is now ignored with a warning.

0 commit comments

Comments
 (0)