From 80fc171a778103bf905deca203707ed616909d55 Mon Sep 17 00:00:00 2001 From: tonghuaroot Date: Fri, 10 Jul 2026 10:45:44 +0800 Subject: [PATCH 1/2] gh-153477: Fix IDLE startup crash on a corrupt user config file IdleConfParser.Load raised the configparser exception on a corrupt or partially written user configuration file, which aborted IDLE startup. Catch it, warn, and fall back to the default configuration, matching the module's documented graceful-degradation behavior. --- Lib/idlelib/config.py | 8 ++++++-- Lib/idlelib/idle_test/test_config.py | 14 ++++++++++++++ .../2026-07-10-19-40-00.gh-issue-153477.Cf9Ld2.rst | 2 ++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-10-19-40-00.gh-issue-153477.Cf9Ld2.rst diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index 82afd6c49269d2..a02c7365484e1b 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -25,7 +25,7 @@ """ # TODOs added Oct 2014, tjr -from configparser import ConfigParser +from configparser import ConfigParser, Error import os import sys @@ -75,7 +75,11 @@ def Load(self): "Load the configuration file from disk." if self.file and os.path.exists(self.file): with open(self.file, encoding='utf-8', errors='replace') as f: - self.read_file(f) + try: + self.read_file(f) + except Error as err: # any configparser parse error + _warn(f'\nInvalid config file, using default config:\n' + f'{self.file!r}\n{err}\n', self.file) class IdleUserConfParser(IdleConfParser): """ diff --git a/Lib/idlelib/idle_test/test_config.py b/Lib/idlelib/idle_test/test_config.py index 6d75cf7aa67dcc..02d028686e8eac 100644 --- a/Lib/idlelib/idle_test/test_config.py +++ b/Lib/idlelib/idle_test/test_config.py @@ -93,6 +93,20 @@ def test_load_file(self): self.assertEqual(parser.Get('Foo Bar', 'foo'), 'newbar') self.assertEqual(parser.GetOptionList('Foo Bar'), ['foo']) + def test_load_invalid_file(self): + # gh-000000: a corrupt config file must warn and fall back to + # defaults, not abort IDLE startup. + self.addCleanup(config._warned.clear) + with tempfile.TemporaryDirectory() as tdir: + path = os.path.join(tdir, 'invalid.cfg') + with open(path, 'w', encoding='utf-8') as f: + f.write('option = value\n') # missing section header + parser = config.IdleConfParser(path) + with captured_stderr() as stderr: + parser.Load() # must not raise + self.assertEqual(parser.sections(), []) + self.assertIn('Invalid config file', stderr.getvalue()) + class IdleUserConfParserTest(unittest.TestCase): """Test that IdleUserConfParser works""" diff --git a/Misc/NEWS.d/next/Library/2026-07-10-19-40-00.gh-issue-153477.Cf9Ld2.rst b/Misc/NEWS.d/next/Library/2026-07-10-19-40-00.gh-issue-153477.Cf9Ld2.rst new file mode 100644 index 00000000000000..1b34fba74a1eb8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-10-19-40-00.gh-issue-153477.Cf9Ld2.rst @@ -0,0 +1,2 @@ +IDLE now warns and falls back to the default configuration when a user +configuration file cannot be parsed, instead of failing to start. From 0a94b48182cc5d63ee1ca241fd4d5645da817125 Mon Sep 17 00:00:00 2001 From: tonghuaroot Date: Fri, 10 Jul 2026 18:27:35 +0800 Subject: [PATCH 2/2] gh-153477: Backfill issue number in a test comment --- Lib/idlelib/idle_test/test_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/idle_test/test_config.py b/Lib/idlelib/idle_test/test_config.py index 02d028686e8eac..7ef2590c3ec84a 100644 --- a/Lib/idlelib/idle_test/test_config.py +++ b/Lib/idlelib/idle_test/test_config.py @@ -94,7 +94,7 @@ def test_load_file(self): self.assertEqual(parser.GetOptionList('Foo Bar'), ['foo']) def test_load_invalid_file(self): - # gh-000000: a corrupt config file must warn and fall back to + # gh-153477: a corrupt config file must warn and fall back to # defaults, not abort IDLE startup. self.addCleanup(config._warned.clear) with tempfile.TemporaryDirectory() as tdir: