[Python-checkins] gh-91827: Add method info_pathlevel() in tkinter (GH-91829)

serhiy-storchaka webhook-mailer at python.org
Fri May 6 06:51:00 EDT 2022


https://github.com/python/cpython/commit/15dbe8570f215bfb4910cdd79b43dafb2ab6b38f
commit: 15dbe8570f215bfb4910cdd79b43dafb2ab6b38f
branch: main
author: Serhiy Storchaka <storchaka at gmail.com>
committer: serhiy-storchaka <storchaka at gmail.com>
date: 2022-05-06T13:50:38+03:00
summary:

gh-91827: Add method info_pathlevel() in tkinter (GH-91829)

files:
A Misc/NEWS.d/next/Library/2022-04-22-19-11-31.gh-issue-91827.6P3gOI.rst
M Doc/whatsnew/3.11.rst
M Lib/idlelib/help_about.py
M Lib/test/test_tcl.py
M Lib/tkinter/__init__.py
M Lib/tkinter/test/support.py
M Lib/tkinter/test/test_tkinter/test_misc.py
M Lib/tkinter/test/widget_tests.py

diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index f679100863a03..07e8332d51b61 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -744,6 +744,14 @@ For major changes, see :ref:`new-feat-related-type-hints-311`.
   (Contributed by Serhiy Storchaka in :issue:`43923`.)
 
 
+tkinter
+-------
+
+* Added method ``info_patchlevel()`` which returns the exact version of
+  the Tcl library as a named tuple similar to :data:`sys.version_info`.
+  (Contributed by Serhiy Storchaka in :issue:`91827`.)
+
+
 unicodedata
 -----------
 
diff --git a/Lib/idlelib/help_about.py b/Lib/idlelib/help_about.py
index c59f494599806..9cb3ba78c50eb 100644
--- a/Lib/idlelib/help_about.py
+++ b/Lib/idlelib/help_about.py
@@ -76,8 +76,8 @@ def create_widgets(self):
                        bg=self.bg, font=('courier', 24, 'bold'))
         header.grid(row=0, column=0, sticky=E, padx=10, pady=10)
 
-        tk_patchlevel = self.tk.call('info', 'patchlevel')
-        ext = '.png' if tk_patchlevel >= '8.6' else '.gif'
+        tk_patchlevel = self.info_patchlevel()
+        ext = '.png' if tk_patchlevel >= (8, 6) else '.gif'
         icon = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                             'Icons', f'idle_48{ext}')
         self.icon_image = PhotoImage(master=self._root(), file=icon)
@@ -105,7 +105,7 @@ def create_widgets(self):
                       text='Python version:  ' + version,
                       fg=self.fg, bg=self.bg)
         pyver.grid(row=9, column=0, sticky=W, padx=10, pady=0)
-        tkver = Label(frame_background, text='Tk version:  ' + tk_patchlevel,
+        tkver = Label(frame_background, text=f'Tk version:  {tk_patchlevel}',
                       fg=self.fg, bg=self.bg)
         tkver.grid(row=9, column=1, sticky=W, padx=2, pady=0)
         py_buttons = Frame(frame_background, bg=self.bg)
diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py
index e73ad596fe678..548914796ed76 100644
--- a/Lib/test/test_tcl.py
+++ b/Lib/test/test_tcl.py
@@ -28,15 +28,7 @@ def get_tk_patchlevel():
     global _tk_patchlevel
     if _tk_patchlevel is None:
         tcl = Tcl()
-        patchlevel = tcl.call('info', 'patchlevel')
-        m = re.fullmatch(r'(\d+)\.(\d+)([ab.])(\d+)', patchlevel)
-        major, minor, releaselevel, serial = m.groups()
-        major, minor, serial = int(major), int(minor), int(serial)
-        releaselevel = {'a': 'alpha', 'b': 'beta', '.': 'final'}[releaselevel]
-        if releaselevel == 'final':
-            _tk_patchlevel = major, minor, serial, releaselevel, 0
-        else:
-            _tk_patchlevel = major, minor, 0, releaselevel, serial
+        _tk_patchlevel = tcl.info_patchlevel()
     return _tk_patchlevel
 
 
@@ -723,7 +715,7 @@ def test_huge_string_builtins2(self, size):
 def setUpModule():
     if support.verbose:
         tcl = Tcl()
-        print('patchlevel =', tcl.call('info', 'patchlevel'))
+        print('patchlevel =', tcl.call('info', 'patchlevel'), flush=True)
 
 
 if __name__ == "__main__":
diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py
index 2e7e21c6648ea..3d23889c74f24 100644
--- a/Lib/tkinter/__init__.py
+++ b/Lib/tkinter/__init__.py
@@ -30,6 +30,7 @@
 tk.mainloop()
 """
 
+import collections
 import enum
 import sys
 import types
@@ -143,6 +144,28 @@ def _splitdict(tk, v, cut_minus=True, conv=None):
         dict[key] = value
     return dict
 
+class _VersionInfoType(collections.namedtuple('_VersionInfoType',
+        ('major', 'minor', 'micro', 'releaselevel', 'serial'))):
+    def __str__(self):
+        if self.releaselevel == 'final':
+            return f'{self.major}.{self.minor}.{self.micro}'
+        else:
+            return f'{self.major}.{self.minor}{self.releaselevel[0]}{self.serial}'
+
+def _parse_version(version):
+    import re
+    m = re.fullmatch(r'(\d+)\.(\d+)([ab.])(\d+)', version)
+    major, minor, releaselevel, serial = m.groups()
+    major, minor, serial = int(major), int(minor), int(serial)
+    if releaselevel == '.':
+        micro = serial
+        serial = 0
+        releaselevel = 'final'
+    else:
+        micro = 0
+        releaselevel = {'a': 'alpha', 'b': 'beta'}[releaselevel]
+    return _VersionInfoType(major, minor, micro, releaselevel, serial)
+
 
 @enum._simple_enum(enum.StrEnum)
 class EventType:
@@ -1055,6 +1078,11 @@ def tkraise(self, aboveThis=None):
 
     lift = tkraise
 
+    def info_patchlevel(self):
+        """Returns the exact version of the Tcl library."""
+        patchlevel = self.tk.call('info', 'patchlevel')
+        return _parse_version(patchlevel)
+
     def winfo_atom(self, name, displayof=0):
         """Return integer which represents atom NAME."""
         args = ('winfo', 'atom') + self._displayof(displayof) + (name,)
diff --git a/Lib/tkinter/test/support.py b/Lib/tkinter/test/support.py
index dbc47a81e6515..9e26d04536f22 100644
--- a/Lib/tkinter/test/support.py
+++ b/Lib/tkinter/test/support.py
@@ -101,15 +101,7 @@ def get_tk_patchlevel():
     global _tk_patchlevel
     if _tk_patchlevel is None:
         tcl = tkinter.Tcl()
-        patchlevel = tcl.call('info', 'patchlevel')
-        m = re.fullmatch(r'(\d+)\.(\d+)([ab.])(\d+)', patchlevel)
-        major, minor, releaselevel, serial = m.groups()
-        major, minor, serial = int(major), int(minor), int(serial)
-        releaselevel = {'a': 'alpha', 'b': 'beta', '.': 'final'}[releaselevel]
-        if releaselevel == 'final':
-            _tk_patchlevel = major, minor, serial, releaselevel, 0
-        else:
-            _tk_patchlevel = major, minor, 0, releaselevel, serial
+        _tk_patchlevel = tcl.info_patchlevel()
     return _tk_patchlevel
 
 units = {
diff --git a/Lib/tkinter/test/test_tkinter/test_misc.py b/Lib/tkinter/test/test_tkinter/test_misc.py
index 044eb10d68835..620b6ed638c25 100644
--- a/Lib/tkinter/test/test_tkinter/test_misc.py
+++ b/Lib/tkinter/test/test_tkinter/test_misc.py
@@ -341,6 +341,35 @@ def callback():
         self.assertEqual(log, [1])
         self.assertTrue(self.root.winfo_exists())
 
+    def test_info_patchlevel(self):
+        vi = self.root.info_patchlevel()
+        f = tkinter.Frame(self.root)
+        self.assertEqual(f.info_patchlevel(), vi)
+        # The following is almost a copy of tests for sys.version_info.
+        self.assertIsInstance(vi[:], tuple)
+        self.assertEqual(len(vi), 5)
+        self.assertIsInstance(vi[0], int)
+        self.assertIsInstance(vi[1], int)
+        self.assertIsInstance(vi[2], int)
+        self.assertIn(vi[3], ("alpha", "beta", "candidate", "final"))
+        self.assertIsInstance(vi[4], int)
+        self.assertIsInstance(vi.major, int)
+        self.assertIsInstance(vi.minor, int)
+        self.assertIsInstance(vi.micro, int)
+        self.assertIn(vi.releaselevel, ("alpha", "beta", "final"))
+        self.assertIsInstance(vi.serial, int)
+        self.assertEqual(vi[0], vi.major)
+        self.assertEqual(vi[1], vi.minor)
+        self.assertEqual(vi[2], vi.micro)
+        self.assertEqual(vi[3], vi.releaselevel)
+        self.assertEqual(vi[4], vi.serial)
+        self.assertTrue(vi > (1,0,0))
+        if vi.releaselevel == 'final':
+            self.assertEqual(vi.serial, 0)
+        else:
+            self.assertEqual(vi.micro, 0)
+        self.assertTrue(str(vi).startswith(f'{vi.major}.{vi.minor}'))
+
 
 class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
 
diff --git a/Lib/tkinter/test/widget_tests.py b/Lib/tkinter/test/widget_tests.py
index 37d1979c23f1d..a450544c3ee6b 100644
--- a/Lib/tkinter/test/widget_tests.py
+++ b/Lib/tkinter/test/widget_tests.py
@@ -517,4 +517,4 @@ def test(self, option=option):
 def setUpModule():
     if test.support.verbose:
         tcl = tkinter.Tcl()
-        print('patchlevel =', tcl.call('info', 'patchlevel'))
+        print('patchlevel =', tcl.call('info', 'patchlevel'), flush=True)
diff --git a/Misc/NEWS.d/next/Library/2022-04-22-19-11-31.gh-issue-91827.6P3gOI.rst b/Misc/NEWS.d/next/Library/2022-04-22-19-11-31.gh-issue-91827.6P3gOI.rst
new file mode 100644
index 0000000000000..83b752277785b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-04-22-19-11-31.gh-issue-91827.6P3gOI.rst
@@ -0,0 +1,3 @@
+In the :mod:`tkinter` module add method ``info_patchlevel()`` which returns
+the exact version of the Tcl library as a named tuple similar to
+:data:`sys.version_info`.



More information about the Python-checkins mailing list