https://github.com/python/cpython/commit/f9c44ea015dc94d45e0c8b6a39111a0f990aecac
commit: f9c44ea015dc94d45e0c8b6a39111a0f990aecac
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-06-29T11:41:52+03:00
summary:

[3.14] gh-85320: Use UTF-8 for IDLE configuration and breakpoint files 
(GH-152475) (GH-152556)

They were read and written using the locale encoding, which could corrupt
non-ASCII paths and made them non-portable.
(cherry picked from commit f6e904e1a666cb1e5664750b1c3d8f89cba3a769)

Co-authored-by: Serhiy Storchaka <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>

files:
A Misc/NEWS.d/next/IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst
M Lib/idlelib/News3.txt
M Lib/idlelib/config.py
M Lib/idlelib/pyshell.py

diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt
index da3a1458111d7a5..9dd051f945e01a0 100644
--- a/Lib/idlelib/News3.txt
+++ b/Lib/idlelib/News3.txt
@@ -4,6 +4,11 @@ Released after 2025-10-07
 =========================
 
 
+gh-85320: IDLE now reads and writes its configuration files and the
+breakpoints file using UTF-8 instead of the locale encoding.
+Files with non-ASCII characters and non-UTF-8 encoding may need
+to be opened in an editor and resaved with UTF-8 encoding.
+
 gh-143774: Better explain the operation of Format / Format Paragraph.
 Patch by Terry J. Reedy.
 
diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py
index d10c88a43f9231d..21873d252dc9bab 100644
--- a/Lib/idlelib/config.py
+++ b/Lib/idlelib/config.py
@@ -73,8 +73,9 @@ def GetOptionList(self, section):
 
     def Load(self):
         "Load the configuration file from disk."
-        if self.file:
-            self.read(self.file)
+        if self.file and os.path.exists(self.file):
+            with open(self.file, encoding='utf-8', errors='replace') as f:
+                self.read_file(f)
 
 class IdleUserConfParser(IdleConfParser):
     """
@@ -133,10 +134,10 @@ def Save(self):
         if fname and fname[0] != '#':
             if not self.IsEmpty():
                 try:
-                    cfgFile = open(fname, 'w')
+                    cfgFile = open(fname, 'w', encoding='utf-8')
                 except OSError:
                     os.unlink(fname)
-                    cfgFile = open(fname, 'w')
+                    cfgFile = open(fname, 'w', encoding='utf-8')
                 with cfgFile:
                     self.write(cfgFile)
             elif os.path.exists(self.file):
diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py
index 1b7c2af1a923d70..8605b0cbd57f565 100755
--- a/Lib/idlelib/pyshell.py
+++ b/Lib/idlelib/pyshell.py
@@ -242,12 +242,13 @@ def store_file_breaks(self):
         breaks = self.breakpoints
         filename = self.io.filename
         try:
-            with open(self.breakpointPath) as fp:
+            with open(self.breakpointPath,
+                      encoding='utf-8', errors='replace') as fp:
                 lines = fp.readlines()
         except OSError:
             lines = []
         try:
-            with open(self.breakpointPath, "w") as new_file:
+            with open(self.breakpointPath, "w", encoding='utf-8') as new_file:
                 for line in lines:
                     if not line.startswith(filename + '='):
                         new_file.write(line)
@@ -272,7 +273,8 @@ def restore_file_breaks(self):
         if filename is None:
             return
         if os.path.isfile(self.breakpointPath):
-            with open(self.breakpointPath) as fp:
+            with open(self.breakpointPath,
+                      encoding='utf-8', errors='replace') as fp:
                 lines = fp.readlines()
             for line in lines:
                 if line.startswith(filename + '='):
diff --git 
a/Misc/NEWS.d/next/IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst 
b/Misc/NEWS.d/next/IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst
new file mode 100644
index 000000000000000..ec34bf8ead9eb9f
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2026-06-28-06-46-46.gh-issue-85320.Hq2vKn.rst
@@ -0,0 +1,4 @@
+IDLE now reads and writes its configuration files and the breakpoints file
+using UTF-8 instead of the locale encoding.  This keeps non-ASCII data (such
+as non-ASCII paths) from being corrupted and makes the files portable between
+environments.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to