From e5f42604e7976a34674062047f3caac6c5468891 Mon Sep 17 00:00:00 2001 From: John Zhou Date: Wed, 28 May 2025 22:19:18 -0500 Subject: [PATCH 01/31] fix a dos --- Lib/idlelib/editor.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index c76db20c58792d..70f09518efb3f4 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1203,10 +1203,20 @@ def load_extension(self, name): self.apply_bindings(keydefs) for vevent in keydefs: methodname = vevent.replace("-", "_") - while methodname[:1] == '<': - methodname = methodname[1:] - while methodname[-1:] == '>': - methodname = methodname[:-1] + stripl = 0 + for char in methodname: + if char == '<': + stripl += 1 + else: + break + methodname = methodname[stripl:] + stripr = 0 + for char in methodname[::-1]: + if char == '>': + stripr -= 1 + else: + break + methodname = methodname[:stripr] methodname = methodname + "_event" if hasattr(ins, methodname): self.text.bind(vevent, getattr(ins, methodname)) From aa5b5a813fefe435fbde492c0a30324b3148bcac Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 03:24:19 +0000 Subject: [PATCH 02/31] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst diff --git a/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst b/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst new file mode 100644 index 00000000000000..cac6108a74d62a --- /dev/null +++ b/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst @@ -0,0 +1 @@ +A DOS vulnerability in ``idlelib`` is fixed regarding string slicing. From edfa9042cf13e5d8d951119ffa53c70b423b04c1 Mon Sep 17 00:00:00 2001 From: John Date: Thu, 29 May 2025 21:41:04 -0500 Subject: [PATCH 03/31] Update Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst Co-authored-by: Peter Bierma --- .../Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst b/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst index cac6108a74d62a..389b8af30ef048 100644 --- a/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst +++ b/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst @@ -1 +1 @@ -A DOS vulnerability in ``idlelib`` is fixed regarding string slicing. +Fix a DOS vulnerability in :mod:`idlelib` regarding string slicing. From 2090bafb8f67a927703b025fa34ec347b5eb6b79 Mon Sep 17 00:00:00 2001 From: John Zhou Date: Thu, 29 May 2025 22:29:53 -0500 Subject: [PATCH 04/31] another dos and also simplify --- Lib/idlelib/editor.py | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 70f09518efb3f4..e4024839bea55f 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1203,20 +1203,7 @@ def load_extension(self, name): self.apply_bindings(keydefs) for vevent in keydefs: methodname = vevent.replace("-", "_") - stripl = 0 - for char in methodname: - if char == '<': - stripl += 1 - else: - break - methodname = methodname[stripl:] - stripr = 0 - for char in methodname[::-1]: - if char == '>': - stripr -= 1 - else: - break - methodname = methodname[:stripr] + methodname = methodname.lstrip('<').rstrip('>') methodname = methodname + "_event" if hasattr(ins, methodname): self.text.bind(vevent, getattr(ins, methodname)) @@ -1378,14 +1365,18 @@ def smart_backspace_event(self, event): have = len(chars.expandtabs(tabwidth)) assert have > 0 want = ((have - 1) // self.indentwidth) * self.indentwidth - # Debug prompt is multilined.... + ncharsdeleted = 0 - while True: - chars = chars[:-1] - ncharsdeleted = ncharsdeleted + 1 - have = len(chars.expandtabs(tabwidth)) - if have <= want or chars[-1] not in " \t": + have = len(chars.expandtabs(tabwidth)) + + for i in range(len(chars) - 1, -1, -1): + if have <= want or chars[i] not in " \t": break + ncharsdeleted += 1 + + chars = chars[:len(chars) - ncharsdeleted] + have = len(chars.expandtabs(tabwidth)) + text.undo_block_start() text.delete("insert-%dc" % ncharsdeleted, "insert") if have < want: From d2838a589b9aa90d04bd50e40176e8812215324d Mon Sep 17 00:00:00 2001 From: John Zhou Date: Thu, 29 May 2025 22:34:27 -0500 Subject: [PATCH 05/31] grumble --- Lib/idlelib/editor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index e4024839bea55f..2aebd528ebfbdc 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1365,7 +1365,7 @@ def smart_backspace_event(self, event): have = len(chars.expandtabs(tabwidth)) assert have > 0 want = ((have - 1) // self.indentwidth) * self.indentwidth - + ncharsdeleted = 0 have = len(chars.expandtabs(tabwidth)) @@ -1373,7 +1373,7 @@ def smart_backspace_event(self, event): if have <= want or chars[i] not in " \t": break ncharsdeleted += 1 - + chars = chars[:len(chars) - ncharsdeleted] have = len(chars.expandtabs(tabwidth)) From 83bafff6744aff00d78bf21a8e0ae71b7d30a38e Mon Sep 17 00:00:00 2001 From: John Zhou Date: Fri, 30 May 2025 10:41:02 -0500 Subject: [PATCH 06/31] have condition --- Lib/idlelib/editor.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 2aebd528ebfbdc..1cc0c4468b62f2 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1366,16 +1366,14 @@ def smart_backspace_event(self, event): assert have > 0 want = ((have - 1) // self.indentwidth) * self.indentwidth + # Debug prompt is multilined.... ncharsdeleted = 0 - have = len(chars.expandtabs(tabwidth)) - for i in range(len(chars) - 1, -1, -1): + have = len(chars.expandtabs(tabwidth)) if have <= want or chars[i] not in " \t": break ncharsdeleted += 1 - chars = chars[:len(chars) - ncharsdeleted] - have = len(chars.expandtabs(tabwidth)) text.undo_block_start() text.delete("insert-%dc" % ncharsdeleted, "insert") From 660fbd388c9154ed7f2e56ee9902198f1599c1be Mon Sep 17 00:00:00 2001 From: John Zhou Date: Fri, 30 May 2025 11:04:37 -0500 Subject: [PATCH 07/31] significant refactor --- Lib/idlelib/editor.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 1cc0c4468b62f2..74ad176ed47831 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1368,11 +1368,18 @@ def smart_backspace_event(self, event): # Debug prompt is multilined.... ncharsdeleted = 0 + have = len(chars.expandtabs(tabwidth)) for i in range(len(chars) - 1, -1, -1): - have = len(chars.expandtabs(tabwidth)) - if have <= want or chars[i] not in " \t": - break + # ``Delete'' chars[i], and subtract count + # (since redoing expandtabs is O(n)) ncharsdeleted += 1 + if chars[i] == '\t': + have -= tabwidth + else: + have -= 1 + if have <= want or chars[i-1] not in " \t": + break + # Perform the actual removal chars = chars[:len(chars) - ncharsdeleted] text.undo_block_start() From 15f821a8daaeecf24b548d8468f1de5a8cb6c232 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 1 Jun 2025 11:45:34 -0500 Subject: [PATCH 08/31] Update Lib/idlelib/editor.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/idlelib/editor.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 74ad176ed47831..1d0f0d3d048b12 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1379,9 +1379,7 @@ def smart_backspace_event(self, event): have -= 1 if have <= want or chars[i-1] not in " \t": break - # Perform the actual removal chars = chars[:len(chars) - ncharsdeleted] - text.undo_block_start() text.delete("insert-%dc" % ncharsdeleted, "insert") if have < want: From 6a59e50c7155ad496d6ca9886b58436984f46e2d Mon Sep 17 00:00:00 2001 From: John Zhou Date: Sun, 1 Jun 2025 11:49:47 -0500 Subject: [PATCH 09/31] rem blank line --- Lib/idlelib/editor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 1d0f0d3d048b12..4ba07bcf8b873c 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1365,7 +1365,6 @@ def smart_backspace_event(self, event): have = len(chars.expandtabs(tabwidth)) assert have > 0 want = ((have - 1) // self.indentwidth) * self.indentwidth - # Debug prompt is multilined.... ncharsdeleted = 0 have = len(chars.expandtabs(tabwidth)) From 546f19bdc2091e30f9670dbd2bec761f50d8c56d Mon Sep 17 00:00:00 2001 From: John Zhou Date: Sun, 1 Jun 2025 13:44:40 -0500 Subject: [PATCH 10/31] write some tests --- Lib/idlelib/editor.py | 31 ++++++++++++++++------------ Lib/idlelib/idle_test/test_editor.py | 11 ++++++++++ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 4ba07bcf8b873c..661a2372b2770f 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1338,6 +1338,23 @@ def set_indentation_params(self, is_py_src, guess=True): self.usetabs = False self.set_tk_tabwidth(self.tabwidth) + @staticmethod + def delete_trail_whitespace(want, chars, tabwidth): + ncharsdeleted = 0 + have = len(chars.expandtabs(tabwidth)) + for i in range(len(chars) - 1, -1, -1): + # ``Delete'' chars[i], and subtract count + # (since redoing expandtabs is O(n)) + ncharsdeleted += 1 + if chars[i] == '\t': + have -= tabwidth + else: + have -= 1 + if have <= want or chars[i-1] not in " \t": + break + chars = chars[:len(chars) - ncharsdeleted] + return ncharsdeleted, chars + def smart_backspace_event(self, event): text = self.text first, last = self.get_selection_indices() @@ -1366,19 +1383,7 @@ def smart_backspace_event(self, event): assert have > 0 want = ((have - 1) // self.indentwidth) * self.indentwidth # Debug prompt is multilined.... - ncharsdeleted = 0 - have = len(chars.expandtabs(tabwidth)) - for i in range(len(chars) - 1, -1, -1): - # ``Delete'' chars[i], and subtract count - # (since redoing expandtabs is O(n)) - ncharsdeleted += 1 - if chars[i] == '\t': - have -= tabwidth - else: - have -= 1 - if have <= want or chars[i-1] not in " \t": - break - chars = chars[:len(chars) - ncharsdeleted] + ncharsdeleted, chars = TestWindow.delete_trail_whitespace(want, chars, tabwidth) text.undo_block_start() text.delete("insert-%dc" % ncharsdeleted, "insert") if have < want: diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 0dfe2f3c58befa..fd1b1c9634cad7 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -237,5 +237,16 @@ def test_rclick(self): pass +class DeleteWantTest(unittest.TestCase): + + def test_delete_trail_whitespace(self): + test_str = "abcde" + 10000 * "\t" + 10000 * " " + res_str = Editor.delete_trail_whitespace(30000, test_str, 4)[1] + self.assertEqual(res_str, "abcde" + 7498 * "\t") + res_str = Editor.delete_trail_whitespace(41005, test_str, 4)[1] + self.assertEqual(res_str, "abcde" + 10000 * "\t" + 1000 * " ") + res_str = Editor.delete_trail_whitespace(4, test_str, 4)[1] + self.assertEqual(res_str, "abcd") + if __name__ == '__main__': unittest.main(verbosity=2) From 605373b00b2c0415667a950c594c7404c9c86c1b Mon Sep 17 00:00:00 2001 From: John Zhou Date: Sun, 1 Jun 2025 13:47:22 -0500 Subject: [PATCH 11/31] static --- Lib/idlelib/editor.py | 5 ++--- Lib/idlelib/idle_test/test_editor.py | 16 +++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 661a2372b2770f..7a68a8d2e90d22 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1338,8 +1338,7 @@ def set_indentation_params(self, is_py_src, guess=True): self.usetabs = False self.set_tk_tabwidth(self.tabwidth) - @staticmethod - def delete_trail_whitespace(want, chars, tabwidth): + def delete_trail_whitespace(self, want, chars, tabwidth): ncharsdeleted = 0 have = len(chars.expandtabs(tabwidth)) for i in range(len(chars) - 1, -1, -1): @@ -1383,7 +1382,7 @@ def smart_backspace_event(self, event): assert have > 0 want = ((have - 1) // self.indentwidth) * self.indentwidth # Debug prompt is multilined.... - ncharsdeleted, chars = TestWindow.delete_trail_whitespace(want, chars, tabwidth) + ncharsdeleted, chars = self.delete_trail_whitespace(want, chars, tabwidth) text.undo_block_start() text.delete("insert-%dc" % ncharsdeleted, "insert") if have < want: diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index fd1b1c9634cad7..e50e5b7154f2ec 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -240,13 +240,15 @@ def test_rclick(self): class DeleteWantTest(unittest.TestCase): def test_delete_trail_whitespace(self): - test_str = "abcde" + 10000 * "\t" + 10000 * " " - res_str = Editor.delete_trail_whitespace(30000, test_str, 4)[1] - self.assertEqual(res_str, "abcde" + 7498 * "\t") - res_str = Editor.delete_trail_whitespace(41005, test_str, 4)[1] - self.assertEqual(res_str, "abcde" + 10000 * "\t" + 1000 * " ") - res_str = Editor.delete_trail_whitespace(4, test_str, 4)[1] - self.assertEqual(res_str, "abcd") + with unittest.mock.patch.object(Editor, '__init__', return_value=None) as mock_init: + ew = Editor() + test_str = "abcde" + 10000 * "\t" + 10000 * " " + res_str = ew.delete_trail_whitespace(30000, test_str, 4)[1] + self.assertEqual(res_str, "abcde" + 7498 * "\t") + res_str = ew.delete_trail_whitespace(41005, test_str, 4)[1] + self.assertEqual(res_str, "abcde" + 10000 * "\t" + 1000 * " ") + res_str = ew.delete_trail_whitespace(4, test_str, 4)[1] + self.assertEqual(res_str, "abcd") if __name__ == '__main__': unittest.main(verbosity=2) From 9625fccc9203ff2c4f4eae23cf5f39f0ff2eada2 Mon Sep 17 00:00:00 2001 From: John Zhou Date: Sun, 1 Jun 2025 13:47:55 -0500 Subject: [PATCH 12/31] linter --- Lib/idlelib/idle_test/test_editor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index e50e5b7154f2ec..4ed45a16830b13 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -238,7 +238,7 @@ def test_rclick(self): class DeleteWantTest(unittest.TestCase): - + def test_delete_trail_whitespace(self): with unittest.mock.patch.object(Editor, '__init__', return_value=None) as mock_init: ew = Editor() From d0017b6ede9fadb0904680b96e35f1c1b03b1a91 Mon Sep 17 00:00:00 2001 From: John Zhou Date: Sun, 1 Jun 2025 14:27:28 -0500 Subject: [PATCH 13/31] get this right --- Lib/idlelib/editor.py | 26 ++++++++++++++------------ Lib/idlelib/idle_test/test_editor.py | 8 ++++---- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 7a68a8d2e90d22..270af0172e8f3a 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1339,20 +1339,22 @@ def set_indentation_params(self, is_py_src, guess=True): self.set_tk_tabwidth(self.tabwidth) def delete_trail_whitespace(self, want, chars, tabwidth): - ncharsdeleted = 0 - have = len(chars.expandtabs(tabwidth)) - for i in range(len(chars) - 1, -1, -1): - # ``Delete'' chars[i], and subtract count - # (since redoing expandtabs is O(n)) - ncharsdeleted += 1 - if chars[i] == '\t': - have -= tabwidth + current_pos = 0 + ncharsretained = 0 + for char in chars: + if char == '\t': + current_pos = (current_pos // tabwidth + 1) * tabwidth else: - have -= 1 - if have <= want or chars[i-1] not in " \t": + current_pos += 1 + ncharsretained += 1 + if current_pos > want: + ncharsretained -= 1 break - chars = chars[:len(chars) - ncharsdeleted] - return ncharsdeleted, chars + for i in range(ncharsretained, len(chars)): + if chars[i] not in " \t": + ncharsretained = i + 1 + chars = chars[:ncharsretained] + return len(chars) - ncharsretained, chars def smart_backspace_event(self, event): text = self.text diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 4ed45a16830b13..b3652740444e2e 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -244,11 +244,11 @@ def test_delete_trail_whitespace(self): ew = Editor() test_str = "abcde" + 10000 * "\t" + 10000 * " " res_str = ew.delete_trail_whitespace(30000, test_str, 4)[1] - self.assertEqual(res_str, "abcde" + 7498 * "\t") + self.assertEqual(res_str, "abcde" + 7499 * "\t") res_str = ew.delete_trail_whitespace(41005, test_str, 4)[1] - self.assertEqual(res_str, "abcde" + 10000 * "\t" + 1000 * " ") - res_str = ew.delete_trail_whitespace(4, test_str, 4)[1] - self.assertEqual(res_str, "abcd") + self.assertEqual(res_str, "abcde" + 10000 * "\t" + 1001 * " ") + res_str = ew.delete_trail_whitespace(3, test_str, 4)[1] + self.assertEqual(res_str, "abcde") if __name__ == '__main__': unittest.main(verbosity=2) From 88c318c33dd001e35d00d662669bb8d4ebe7f08d Mon Sep 17 00:00:00 2001 From: John Zhou Date: Sun, 1 Jun 2025 14:43:03 -0500 Subject: [PATCH 14/31] write more tests --- Lib/idlelib/idle_test/test_editor.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index b3652740444e2e..5c3dac0f2aaa06 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -249,6 +249,10 @@ def test_delete_trail_whitespace(self): self.assertEqual(res_str, "abcde" + 10000 * "\t" + 1001 * " ") res_str = ew.delete_trail_whitespace(3, test_str, 4)[1] self.assertEqual(res_str, "abcde") + res_str = ew.delete_trail_whitespace(6, test_str, 4)[1] + self.assertEqual(res_str, "abcde") + res_str = ew.delete_trail_whitespace(30002, test_str, 4)[1] + self.assertEqual(res_str, "abcde" + 7499 * "\t") if __name__ == '__main__': unittest.main(verbosity=2) From 6323ab86d7c6f50ce9e205d30c768e8c6b1dc79a Mon Sep 17 00:00:00 2001 From: John Zhou Date: Sun, 1 Jun 2025 15:12:33 -0500 Subject: [PATCH 15/31] unconditionally remove last character, tests --- Lib/idlelib/editor.py | 10 ++++----- Lib/idlelib/idle_test/test_editor.py | 33 +++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 270af0172e8f3a..87f80f40285f95 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1338,7 +1338,8 @@ def set_indentation_params(self, is_py_src, guess=True): self.usetabs = False self.set_tk_tabwidth(self.tabwidth) - def delete_trail_whitespace(self, want, chars, tabwidth): + def delete_trail_char_and_space(self, want, chars, tabwidth): + chars = chars[:-1] # remove last character unconditionally current_pos = 0 ncharsretained = 0 for char in chars: @@ -1346,15 +1347,14 @@ def delete_trail_whitespace(self, want, chars, tabwidth): current_pos = (current_pos // tabwidth + 1) * tabwidth else: current_pos += 1 - ncharsretained += 1 if current_pos > want: - ncharsretained -= 1 break + ncharsretained += 1 for i in range(ncharsretained, len(chars)): if chars[i] not in " \t": ncharsretained = i + 1 chars = chars[:ncharsretained] - return len(chars) - ncharsretained, chars + return len(chars) - ncharsretained + 1, chars # removal of last def smart_backspace_event(self, event): text = self.text @@ -1384,7 +1384,7 @@ def smart_backspace_event(self, event): assert have > 0 want = ((have - 1) // self.indentwidth) * self.indentwidth # Debug prompt is multilined.... - ncharsdeleted, chars = self.delete_trail_whitespace(want, chars, tabwidth) + ncharsdeleted, chars = self.delete_trail_char_and_space(want, chars, tabwidth) text.undo_block_start() text.delete("insert-%dc" % ncharsdeleted, "insert") if have < want: diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 5c3dac0f2aaa06..8f8d7ddd2e5d2d 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -239,20 +239,41 @@ def test_rclick(self): class DeleteWantTest(unittest.TestCase): - def test_delete_trail_whitespace(self): + def test_delete_trail_char_and_space(self): with unittest.mock.patch.object(Editor, '__init__', return_value=None) as mock_init: ew = Editor() + test_str = "abcde" + 10000 * "\t" + 10000 * " " - res_str = ew.delete_trail_whitespace(30000, test_str, 4)[1] + res_str = ew.delete_trail_char_and_space(30000, test_str, 4)[1] self.assertEqual(res_str, "abcde" + 7499 * "\t") - res_str = ew.delete_trail_whitespace(41005, test_str, 4)[1] + res_str = ew.delete_trail_char_and_space(41005, test_str, 4)[1] self.assertEqual(res_str, "abcde" + 10000 * "\t" + 1001 * " ") - res_str = ew.delete_trail_whitespace(3, test_str, 4)[1] + res_str = ew.delete_trail_char_and_space(3, test_str, 4)[1] self.assertEqual(res_str, "abcde") - res_str = ew.delete_trail_whitespace(6, test_str, 4)[1] + res_str = ew.delete_trail_char_and_space(6, test_str, 4)[1] self.assertEqual(res_str, "abcde") - res_str = ew.delete_trail_whitespace(30002, test_str, 4)[1] + res_str = ew.delete_trail_char_and_space(30002, test_str, 4)[1] self.assertEqual(res_str, "abcde" + 7499 * "\t") + + test_str = "abcde\tabd\t\t" + res_str = ew.delete_trail_char_and_space(7, test_str, 4)[1] + self.assertEqual(res_str, "abcde\tabd") + res_str = ew.delete_trail_char_and_space(12, test_str, 4)[1] + self.assertEqual(res_str, "abcde\tabd\t") + res_str = ew.delete_trail_char_and_space(13, test_str, 4)[1] + self.assertEqual(res_str, "abcde\tabd\t") + res_str = ew.delete_trail_char_and_space(16, test_str, 4)[1] + self.assertEqual(res_str, "abcde\tabd\t") + + test_str = "abcde\tabd\t \ta" + res_str = ew.delete_trail_char_and_space(7, test_str, 4)[1] + self.assertEqual(res_str, "abcde\tabd") + res_str = ew.delete_trail_char_and_space(12, test_str, 4)[1] + self.assertEqual(res_str, "abcde\tabd\t") + res_str = ew.delete_trail_char_and_space(13, test_str, 4)[1] + self.assertEqual(res_str, "abcde\tabd\t ") + res_str = ew.delete_trail_char_and_space(16, test_str, 4)[1] + self.assertEqual(res_str, "abcde\tabd\t \t") if __name__ == '__main__': unittest.main(verbosity=2) From 01921fc070b43af2959f3168c1329783989450f0 Mon Sep 17 00:00:00 2001 From: John Zhou Date: Sun, 1 Jun 2025 15:34:38 -0500 Subject: [PATCH 16/31] more organized testing also speedup test --- Lib/idlelib/idle_test/test_editor.py | 86 +++++++++++++++++----------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 8f8d7ddd2e5d2d..061ba523553ad9 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -5,6 +5,7 @@ from collections import namedtuple from test.support import requires from tkinter import Tk, Text +import time Editor = editor.EditorWindow @@ -239,41 +240,62 @@ def test_rclick(self): class DeleteWantTest(unittest.TestCase): + data = [ + ("abcde" + 10000 * "\t" + 10000 * " ", [ + (30000, 4, "abcde" + 7499 * "\t"), + (41005, 4, "abcde" + 10000 * "\t" + 1001 * " "), + (3, 4, "abcde"), + (6, 4, "abcde"), + (30002, 4, "abcde" + 7499 * "\t"), + ]), + ("abcde\tabd\t\t", [ + (7, 4, "abcde\tabd"), + (12, 4, "abcde\tabd\t"), + (13, 4, "abcde\tabd\t"), + (16, 4, "abcde\tabd\t"), + ]), + ("abcde\tabd\t \ta", [ + (7, 4, "abcde\tabd"), + (12, 4, "abcde\tabd\t"), + (13, 4, "abcde\tabd\t "), + (16, 4, "abcde\tabd\t \t"), + ]), + ] + + def mock_delete_trail_char_and_space(self, want, chars, tabwidth): + ncharsdeleted = 0 + while True: + chars = chars[:-1] + ncharsdeleted = ncharsdeleted + 1 + have = len(chars.expandtabs(tabwidth)) + if have <= want or chars[-1] not in " \t": + break + return ncharsdeleted, chars + def test_delete_trail_char_and_space(self): with unittest.mock.patch.object(Editor, '__init__', return_value=None) as mock_init: + initial_time_new = time.time() ew = Editor() - - test_str = "abcde" + 10000 * "\t" + 10000 * " " - res_str = ew.delete_trail_char_and_space(30000, test_str, 4)[1] - self.assertEqual(res_str, "abcde" + 7499 * "\t") - res_str = ew.delete_trail_char_and_space(41005, test_str, 4)[1] - self.assertEqual(res_str, "abcde" + 10000 * "\t" + 1001 * " ") - res_str = ew.delete_trail_char_and_space(3, test_str, 4)[1] - self.assertEqual(res_str, "abcde") - res_str = ew.delete_trail_char_and_space(6, test_str, 4)[1] - self.assertEqual(res_str, "abcde") - res_str = ew.delete_trail_char_and_space(30002, test_str, 4)[1] - self.assertEqual(res_str, "abcde" + 7499 * "\t") - - test_str = "abcde\tabd\t\t" - res_str = ew.delete_trail_char_and_space(7, test_str, 4)[1] - self.assertEqual(res_str, "abcde\tabd") - res_str = ew.delete_trail_char_and_space(12, test_str, 4)[1] - self.assertEqual(res_str, "abcde\tabd\t") - res_str = ew.delete_trail_char_and_space(13, test_str, 4)[1] - self.assertEqual(res_str, "abcde\tabd\t") - res_str = ew.delete_trail_char_and_space(16, test_str, 4)[1] - self.assertEqual(res_str, "abcde\tabd\t") - - test_str = "abcde\tabd\t \ta" - res_str = ew.delete_trail_char_and_space(7, test_str, 4)[1] - self.assertEqual(res_str, "abcde\tabd") - res_str = ew.delete_trail_char_and_space(12, test_str, 4)[1] - self.assertEqual(res_str, "abcde\tabd\t") - res_str = ew.delete_trail_char_and_space(13, test_str, 4)[1] - self.assertEqual(res_str, "abcde\tabd\t ") - res_str = ew.delete_trail_char_and_space(16, test_str, 4)[1] - self.assertEqual(res_str, "abcde\tabd\t \t") + for dat in self.data: + test_str = dat[0] + for da in dat[1]: + with self.subTest(want=da[0], tabwidth=da[1], input=repr(test_str)): + res_str = ew.delete_trail_char_and_space(da[0], test_str, da[1])[1] + self.assertEqual(res_str, da[2]) + time_new = time.time() - initial_time_new + + initial_time_old = time.time() + with unittest.mock.patch.object(Editor, 'delete_trail_char_and_space', self.mock_delete_trail_char_and_space): + ew = Editor() + for dat in self.data: + test_str = dat[0] + for da in dat[1]: + with self.subTest(want=da[0], tabwidth=da[1], input=repr(test_str)): + res_str = ew.delete_trail_char_and_space(da[0], test_str, da[1])[1] + self.assertEqual(res_str, da[2]) + time_old = time.time() - initial_time_old + + self.assertGreaterEqual(time_old / time_new, 10) if __name__ == '__main__': unittest.main(verbosity=2) From 5f9bb55e3d820176bc6bbd4474fdee726d971cc3 Mon Sep 17 00:00:00 2001 From: John Zhou Date: Sun, 1 Jun 2025 16:43:48 -0500 Subject: [PATCH 17/31] grumble --- Lib/idlelib/editor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 87f80f40285f95..0e104091305511 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1385,6 +1385,7 @@ def smart_backspace_event(self, event): want = ((have - 1) // self.indentwidth) * self.indentwidth # Debug prompt is multilined.... ncharsdeleted, chars = self.delete_trail_char_and_space(want, chars, tabwidth) + have = len(chars.expandtabs(tabwidth)) text.undo_block_start() text.delete("insert-%dc" % ncharsdeleted, "insert") if have < want: From a087395343b8938c00b6a459ac84a5f32d9d7d85 Mon Sep 17 00:00:00 2001 From: John Zhou Date: Sun, 1 Jun 2025 17:47:07 -0500 Subject: [PATCH 18/31] fix some tests and add some new ones --- Lib/idlelib/idle_test/test_editor.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 061ba523553ad9..595b1e9ba91d3a 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -1,4 +1,4 @@ -"Test editor, coverage 53%." +"Test editor, coverage approximately 53%." from idlelib import editor import unittest @@ -260,6 +260,10 @@ class DeleteWantTest(unittest.TestCase): (13, 4, "abcde\tabd\t "), (16, 4, "abcde\tabd\t \t"), ]), + ("\tabcd", [ + (2, 4, ""), + (5, 4, "\ta"), + ]), ] def mock_delete_trail_char_and_space(self, want, chars, tabwidth): @@ -279,7 +283,7 @@ def test_delete_trail_char_and_space(self): for dat in self.data: test_str = dat[0] for da in dat[1]: - with self.subTest(want=da[0], tabwidth=da[1], input=repr(test_str)): + with self.subTest(want=da[0], tabwidth=da[1], input=test_str): res_str = ew.delete_trail_char_and_space(da[0], test_str, da[1])[1] self.assertEqual(res_str, da[2]) time_new = time.time() - initial_time_new @@ -290,7 +294,7 @@ def test_delete_trail_char_and_space(self): for dat in self.data: test_str = dat[0] for da in dat[1]: - with self.subTest(want=da[0], tabwidth=da[1], input=repr(test_str)): + with self.subTest(want=da[0], tabwidth=da[1], input=test_str): res_str = ew.delete_trail_char_and_space(da[0], test_str, da[1])[1] self.assertEqual(res_str, da[2]) time_old = time.time() - initial_time_old From 6604a73df52e113df95531757ca946dc08504649 Mon Sep 17 00:00:00 2001 From: John Zhou Date: Sun, 1 Jun 2025 18:19:31 -0500 Subject: [PATCH 19/31] fix everythign --- Lib/idlelib/editor.py | 6 +++-- Lib/idlelib/idle_test/test_editor.py | 40 +++++++++++++--------------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 0e104091305511..2327cfbf9b8b77 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1354,7 +1354,7 @@ def delete_trail_char_and_space(self, want, chars, tabwidth): if chars[i] not in " \t": ncharsretained = i + 1 chars = chars[:ncharsretained] - return len(chars) - ncharsretained + 1, chars # removal of last + return chars def smart_backspace_event(self, event): text = self.text @@ -1384,7 +1384,9 @@ def smart_backspace_event(self, event): assert have > 0 want = ((have - 1) // self.indentwidth) * self.indentwidth # Debug prompt is multilined.... - ncharsdeleted, chars = self.delete_trail_char_and_space(want, chars, tabwidth) + oldchars = chars + chars = self.delete_trail_char_and_space(want, chars, tabwidth) + ncharsdeleted = len(oldchars) - len(chars) have = len(chars.expandtabs(tabwidth)) text.undo_block_start() text.delete("insert-%dc" % ncharsdeleted, "insert") diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 595b1e9ba91d3a..1b4575312635db 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -260,9 +260,8 @@ class DeleteWantTest(unittest.TestCase): (13, 4, "abcde\tabd\t "), (16, 4, "abcde\tabd\t \t"), ]), - ("\tabcd", [ - (2, 4, ""), - (5, 4, "\ta"), + (" ", [ + (2, 2, " "), ]), ] @@ -274,30 +273,27 @@ def mock_delete_trail_char_and_space(self, want, chars, tabwidth): have = len(chars.expandtabs(tabwidth)) if have <= want or chars[-1] not in " \t": break - return ncharsdeleted, chars + return chars + + def do_tests(self): + ew = Editor() + for dat in self.data: + test_str = dat[0] + for da in dat[1]: + with self.subTest(want=da[0], tabwidth=da[1], input=test_str): + res = ew.delete_trail_char_and_space(da[0], test_str, da[1]) + self.assertEqual(res, da[2]) def test_delete_trail_char_and_space(self): - with unittest.mock.patch.object(Editor, '__init__', return_value=None) as mock_init: + with unittest.mock.patch.object(Editor, '__init__', return_value=None): initial_time_new = time.time() - ew = Editor() - for dat in self.data: - test_str = dat[0] - for da in dat[1]: - with self.subTest(want=da[0], tabwidth=da[1], input=test_str): - res_str = ew.delete_trail_char_and_space(da[0], test_str, da[1])[1] - self.assertEqual(res_str, da[2]) + self.do_tests() time_new = time.time() - initial_time_new - - initial_time_old = time.time() + with unittest.mock.patch.object(Editor, 'delete_trail_char_and_space', self.mock_delete_trail_char_and_space): - ew = Editor() - for dat in self.data: - test_str = dat[0] - for da in dat[1]: - with self.subTest(want=da[0], tabwidth=da[1], input=test_str): - res_str = ew.delete_trail_char_and_space(da[0], test_str, da[1])[1] - self.assertEqual(res_str, da[2]) - time_old = time.time() - initial_time_old + initial_time_old = time.time() + self.do_tests() + time_old = time.time() - initial_time_old self.assertGreaterEqual(time_old / time_new, 10) From 3f0abfb74605ad6fef8e4542f9c199d5ac6ca1c1 Mon Sep 17 00:00:00 2001 From: John Zhou Date: Sun, 1 Jun 2025 18:32:31 -0500 Subject: [PATCH 20/31] precommit --- Lib/idlelib/idle_test/test_editor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 1b4575312635db..b5ecf36d2eb345 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -274,7 +274,7 @@ def mock_delete_trail_char_and_space(self, want, chars, tabwidth): if have <= want or chars[-1] not in " \t": break return chars - + def do_tests(self): ew = Editor() for dat in self.data: @@ -289,7 +289,7 @@ def test_delete_trail_char_and_space(self): initial_time_new = time.time() self.do_tests() time_new = time.time() - initial_time_new - + with unittest.mock.patch.object(Editor, 'delete_trail_char_and_space', self.mock_delete_trail_char_and_space): initial_time_old = time.time() self.do_tests() From 7c92d9a3e69b9b0a2c43d504e5e6832c02ff9612 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sat, 28 Jun 2025 01:25:09 -0400 Subject: [PATCH 21/31] Apply suggestions from code review --- Lib/idlelib/editor.py | 29 ++++---------- Lib/idlelib/idle_test/test_editor.py | 59 ---------------------------- 2 files changed, 7 insertions(+), 81 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 2327cfbf9b8b77..e0d2df5414dada 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1338,24 +1338,6 @@ def set_indentation_params(self, is_py_src, guess=True): self.usetabs = False self.set_tk_tabwidth(self.tabwidth) - def delete_trail_char_and_space(self, want, chars, tabwidth): - chars = chars[:-1] # remove last character unconditionally - current_pos = 0 - ncharsretained = 0 - for char in chars: - if char == '\t': - current_pos = (current_pos // tabwidth + 1) * tabwidth - else: - current_pos += 1 - if current_pos > want: - break - ncharsretained += 1 - for i in range(ncharsretained, len(chars)): - if chars[i] not in " \t": - ncharsretained = i + 1 - chars = chars[:ncharsretained] - return chars - def smart_backspace_event(self, event): text = self.text first, last = self.get_selection_indices() @@ -1384,10 +1366,13 @@ def smart_backspace_event(self, event): assert have > 0 want = ((have - 1) // self.indentwidth) * self.indentwidth # Debug prompt is multilined.... - oldchars = chars - chars = self.delete_trail_char_and_space(want, chars, tabwidth) - ncharsdeleted = len(oldchars) - len(chars) - have = len(chars.expandtabs(tabwidth)) + ncharsdeleted = 0 + while True: + chars = chars[:-1] + ncharsdeleted = ncharsdeleted + 1 + have = len(chars.expandtabs(tabwidth)) + if have <= want or chars[-1] not in " \t": + break text.undo_block_start() text.delete("insert-%dc" % ncharsdeleted, "insert") if have < want: diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index b5ecf36d2eb345..04cd27ade4ee10 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -238,64 +238,5 @@ def test_rclick(self): pass -class DeleteWantTest(unittest.TestCase): - - data = [ - ("abcde" + 10000 * "\t" + 10000 * " ", [ - (30000, 4, "abcde" + 7499 * "\t"), - (41005, 4, "abcde" + 10000 * "\t" + 1001 * " "), - (3, 4, "abcde"), - (6, 4, "abcde"), - (30002, 4, "abcde" + 7499 * "\t"), - ]), - ("abcde\tabd\t\t", [ - (7, 4, "abcde\tabd"), - (12, 4, "abcde\tabd\t"), - (13, 4, "abcde\tabd\t"), - (16, 4, "abcde\tabd\t"), - ]), - ("abcde\tabd\t \ta", [ - (7, 4, "abcde\tabd"), - (12, 4, "abcde\tabd\t"), - (13, 4, "abcde\tabd\t "), - (16, 4, "abcde\tabd\t \t"), - ]), - (" ", [ - (2, 2, " "), - ]), - ] - - def mock_delete_trail_char_and_space(self, want, chars, tabwidth): - ncharsdeleted = 0 - while True: - chars = chars[:-1] - ncharsdeleted = ncharsdeleted + 1 - have = len(chars.expandtabs(tabwidth)) - if have <= want or chars[-1] not in " \t": - break - return chars - - def do_tests(self): - ew = Editor() - for dat in self.data: - test_str = dat[0] - for da in dat[1]: - with self.subTest(want=da[0], tabwidth=da[1], input=test_str): - res = ew.delete_trail_char_and_space(da[0], test_str, da[1]) - self.assertEqual(res, da[2]) - - def test_delete_trail_char_and_space(self): - with unittest.mock.patch.object(Editor, '__init__', return_value=None): - initial_time_new = time.time() - self.do_tests() - time_new = time.time() - initial_time_new - - with unittest.mock.patch.object(Editor, 'delete_trail_char_and_space', self.mock_delete_trail_char_and_space): - initial_time_old = time.time() - self.do_tests() - time_old = time.time() - initial_time_old - - self.assertGreaterEqual(time_old / time_new, 10) - if __name__ == '__main__': unittest.main(verbosity=2) From e1fb6b990f0fb216032c0691ba7c6e64c72dff6c Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sat, 28 Jun 2025 01:26:57 -0400 Subject: [PATCH 22/31] Apply suggestions from code review --- Lib/idlelib/idle_test/test_editor.py | 1 - .../next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst | 1 - 2 files changed, 2 deletions(-) diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 04cd27ade4ee10..42aacb6e0d807e 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -5,7 +5,6 @@ from collections import namedtuple from test.support import requires from tkinter import Tk, Text -import time Editor = editor.EditorWindow diff --git a/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst b/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst index 389b8af30ef048..e69de29bb2d1d6 100644 --- a/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst +++ b/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst @@ -1 +0,0 @@ -Fix a DOS vulnerability in :mod:`idlelib` regarding string slicing. From 7b67419ccc627bec87691067e87e971b94fbdfb0 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sat, 28 Jun 2025 01:27:28 -0400 Subject: [PATCH 23/31] Update Lib/idlelib/idle_test/test_editor.py --- Lib/idlelib/idle_test/test_editor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 42aacb6e0d807e..0dfe2f3c58befa 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -1,4 +1,4 @@ -"Test editor, coverage approximately 53%." +"Test editor, coverage 53%." from idlelib import editor import unittest From 1037bea492c7b08de0f428efd5acbb0ac7926f33 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sat, 28 Jun 2025 02:10:22 -0400 Subject: [PATCH 24/31] Delete Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst --- .../next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst diff --git a/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst b/Misc/NEWS.d/next/Security/2025-05-29-03-24-18.gh-issue-134873.dziqkQ.rst deleted file mode 100644 index e69de29bb2d1d6..00000000000000 From e505938488d07b8c99391b636b25656f6c5b5508 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 28 Jun 2025 13:29:53 +0000 Subject: [PATCH 25/31] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst diff --git a/Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst b/Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst new file mode 100644 index 00000000000000..9aac99f5224f7c --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst @@ -0,0 +1 @@ +Code for replacing left and right angled brackets in extension names when loading extensions in IDLE has been simplified. From 283a27a6bd96d623ebb761d549b78fcb8c69953e Mon Sep 17 00:00:00 2001 From: John Date: Sun, 29 Jun 2025 08:03:00 -0500 Subject: [PATCH 26/31] Apply suggestions from code review --- Lib/idlelib/editor.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index e0d2df5414dada..c42f6bb18579ce 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1202,9 +1202,7 @@ def load_extension(self, name): if keydefs: self.apply_bindings(keydefs) for vevent in keydefs: - methodname = vevent.replace("-", "_") - methodname = methodname.lstrip('<').rstrip('>') - methodname = methodname + "_event" + methodname = vevent.lstrip("<").replace("-", "_").rstrip(">") + "_event" if hasattr(ins, methodname): self.text.bind(vevent, getattr(ins, methodname)) From d58bd187a4bca0a1f25a9b0eaf094925a75ab2dc Mon Sep 17 00:00:00 2001 From: John Date: Sun, 29 Jun 2025 08:05:41 -0500 Subject: [PATCH 27/31] update news --- .../next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst b/Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst index 9aac99f5224f7c..34a5639277ba8c 100644 --- a/Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst +++ b/Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst @@ -1 +1 @@ -Code for replacing left and right angled brackets in extension names when loading extensions in IDLE has been simplified. +Update code in editor.Editor.load_extension. Patch by johnzhou721, Zachary Ware, and Terry J. Reedy. From 560e06b50468616ed98dc2287c581ae2b13892a0 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 29 Jun 2025 08:07:07 -0500 Subject: [PATCH 28/31] Update News3.txt --- Lib/idlelib/News3.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt index 30784578cc637f..fb05cb179831e6 100644 --- a/Lib/idlelib/News3.txt +++ b/Lib/idlelib/News3.txt @@ -4,6 +4,9 @@ Released on 2025-10-07 ========================= +gh-134873: Update code in editor.Editor.load_extension. +Patch by johnzhou721, Zachary Ware, and Terry J. Reedy. + gh-112936: IDLE - Include Shell menu in single-process mode, though with Restart Shell and View Last Restart disabled. Patch by Zhikang Yan. From a09c45801325d4d1a47566d8306700ac549a99ed Mon Sep 17 00:00:00 2001 From: John Date: Mon, 30 Jun 2025 11:55:13 -0500 Subject: [PATCH 29/31] Delete Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst --- .../next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst diff --git a/Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst b/Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst deleted file mode 100644 index 34a5639277ba8c..00000000000000 --- a/Misc/NEWS.d/next/IDLE/2025-06-28-13-29-52.gh-issue-136061.EQYuVW.rst +++ /dev/null @@ -1 +0,0 @@ -Update code in editor.Editor.load_extension. Patch by johnzhou721, Zachary Ware, and Terry J. Reedy. From a082fbf920645e148a091103a89ef988de9f80f8 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 30 Jun 2025 11:55:46 -0500 Subject: [PATCH 30/31] Update Lib/idlelib/News3.txt Co-authored-by: Zachary Ware --- Lib/idlelib/News3.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt index fb05cb179831e6..6cb66605e78726 100644 --- a/Lib/idlelib/News3.txt +++ b/Lib/idlelib/News3.txt @@ -4,7 +4,7 @@ Released on 2025-10-07 ========================= -gh-134873: Update code in editor.Editor.load_extension. +gh-134873: Minor code modernization in extension loader. Patch by johnzhou721, Zachary Ware, and Terry J. Reedy. gh-112936: IDLE - Include Shell menu in single-process mode, From 4c1268f0cb886e2c4ab6c756d5fa4a4707445792 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 30 Jun 2025 13:09:28 -0500 Subject: [PATCH 31/31] Update Lib/idlelib/editor.py Co-authored-by: Zachary Ware --- Lib/idlelib/editor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index c42f6bb18579ce..9d4fc62da339ab 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1202,7 +1202,7 @@ def load_extension(self, name): if keydefs: self.apply_bindings(keydefs) for vevent in keydefs: - methodname = vevent.lstrip("<").replace("-", "_").rstrip(">") + "_event" + methodname = vevent.strip("<>").replace("-", "_") + "_event" if hasattr(ins, methodname): self.text.bind(vevent, getattr(ins, methodname)) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy