]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.15] gh-153333: Read tkinter profile scripts with the source file's encoding (GH...
authorSerhiy Storchaka <storchaka@gmail.com>
Sat, 11 Jul 2026 05:22:20 +0000 (08:22 +0300)
committerGitHub <noreply@github.com>
Sat, 11 Jul 2026 05:22:20 +0000 (05:22 +0000)
Tk.readprofile ran the user's ~/.CLASS.py and ~/.BASE.py scripts with
exec(open(path).read()), decoding them with the locale encoding.  Read
them in binary mode so exec() honors each script's own coding cookie.
(cherry picked from commit bac73b0f4ea475cbfb11f41579129c9d07075c34)

Co-authored-by: tonghuaroot (童话) <tonghuaroot@gmail.com>
Lib/test/test_tkinter/test_misc.py
Lib/tkinter/__init__.py
Misc/NEWS.d/next/Library/2026-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst [new file with mode: 0644]

index 698ba818029fe8c8a175fd86232a7f66e53b50a7..285a5d0938d2deb0bd1b4b393e74f037c774af9e 100644 (file)
@@ -1,5 +1,6 @@
 import collections.abc
 import functools
+import os
 import platform
 import sys
 import textwrap
@@ -755,6 +756,26 @@ class MiscTest(AbstractTkTest, unittest.TestCase):
 
 class TkTest(AbstractTkTest, unittest.TestCase):
 
+    def test_readprofile(self):
+        # gh-153333: profile scripts are decoded with their own coding cookie,
+        # not the locale encoding.  Two cookies so no locale can mask the bug.
+        profiles = {
+            '.RpClass.py': ('latin-1', "self._rp_latin1 = 'caf\xe9'"),
+            '.rpbase.py': ('utf-8', "self._rp_utf8 = 'caf\xe9'"),
+        }
+        self.addCleanup(self.root.__dict__.pop, '_rp_latin1', None)
+        self.addCleanup(self.root.__dict__.pop, '_rp_utf8', None)
+        with (os_helper.temp_dir() as home,
+              os_helper.EnvironmentVarGuard() as env):
+            env['HOME'] = home
+            for filename, (encoding, body) in profiles.items():
+                script = '# -*- coding: %s -*-\n%s\n' % (encoding, body)
+                with open(os.path.join(home, filename), 'wb') as f:
+                    f.write(script.encode(encoding))
+            self.root.readprofile('rpbase', 'RpClass')
+        self.assertEqual(self.root._rp_latin1, 'caf\xe9')
+        self.assertEqual(self.root._rp_utf8, 'caf\xe9')
+
     def test_className(self):
         # The className argument sets the class of the root window.  Tk
         # title-cases it: the first letter is upper-cased, the rest lower-cased.
index 7189471ee3fa0e7f88a66f61a2822484d988883f..3b693bc72f57238e04f7d2ff60af7c5a7d310d9b 100644 (file)
@@ -2639,11 +2639,13 @@ class Tk(Misc, Wm):
         if os.path.isfile(class_tcl):
             self.tk.call('source', class_tcl)
         if os.path.isfile(class_py):
-            exec(open(class_py).read(), dir)
+            with open(class_py, 'rb') as f:
+                exec(f.read(), dir)
         if os.path.isfile(base_tcl):
             self.tk.call('source', base_tcl)
         if os.path.isfile(base_py):
-            exec(open(base_py).read(), dir)
+            with open(base_py, 'rb') as f:
+                exec(f.read(), dir)
 
     def report_callback_exception(self, exc, val, tb):
         """Report callback exception on sys.stderr.
diff --git a/Misc/NEWS.d/next/Library/2026-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst b/Misc/NEWS.d/next/Library/2026-07-08-21-15-00.gh-issue-153333.Kp3mZq.rst
new file mode 100644 (file)
index 0000000..6fcbd59
--- /dev/null
@@ -0,0 +1,3 @@
+The ``readprofile`` method of :class:`tkinter.Tk` now reads the user's
+profile scripts using the encoding declared in the file, instead of the
+locale encoding.