Skip to content

Commit 15dbe85

Browse files
gh-91827: Add method info_pathlevel() in tkinter (GH-91829)
1 parent d707d07 commit 15dbe85

File tree

8 files changed

+75
-23
lines changed

8 files changed

+75
-23
lines changed

Doc/whatsnew/3.11.rst

+8
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,14 @@ For major changes, see :ref:`new-feat-related-type-hints-311`.
744744
(Contributed by Serhiy Storchaka in :issue:`43923`.)
745745

746746

747+
tkinter
748+
-------
749+
750+
* Added method ``info_patchlevel()`` which returns the exact version of
751+
the Tcl library as a named tuple similar to :data:`sys.version_info`.
752+
(Contributed by Serhiy Storchaka in :issue:`91827`.)
753+
754+
747755
unicodedata
748756
-----------
749757

Lib/idlelib/help_about.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ def create_widgets(self):
7676
bg=self.bg, font=('courier', 24, 'bold'))
7777
header.grid(row=0, column=0, sticky=E, padx=10, pady=10)
7878

79-
tk_patchlevel = self.tk.call('info', 'patchlevel')
80-
ext = '.png' if tk_patchlevel >= '8.6' else '.gif'
79+
tk_patchlevel = self.info_patchlevel()
80+
ext = '.png' if tk_patchlevel >= (8, 6) else '.gif'
8181
icon = os.path.join(os.path.abspath(os.path.dirname(__file__)),
8282
'Icons', f'idle_48{ext}')
8383
self.icon_image = PhotoImage(master=self._root(), file=icon)
@@ -105,7 +105,7 @@ def create_widgets(self):
105105
text='Python version: ' + version,
106106
fg=self.fg, bg=self.bg)
107107
pyver.grid(row=9, column=0, sticky=W, padx=10, pady=0)
108-
tkver = Label(frame_background, text='Tk version: ' + tk_patchlevel,
108+
tkver = Label(frame_background, text=f'Tk version: {tk_patchlevel}',
109109
fg=self.fg, bg=self.bg)
110110
tkver.grid(row=9, column=1, sticky=W, padx=2, pady=0)
111111
py_buttons = Frame(frame_background, bg=self.bg)

Lib/test/test_tcl.py

+2-10
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,7 @@ def get_tk_patchlevel():
2828
global _tk_patchlevel
2929
if _tk_patchlevel is None:
3030
tcl = Tcl()
31-
patchlevel = tcl.call('info', 'patchlevel')
32-
m = re.fullmatch(r'(\d+)\.(\d+)([ab.])(\d+)', patchlevel)
33-
major, minor, releaselevel, serial = m.groups()
34-
major, minor, serial = int(major), int(minor), int(serial)
35-
releaselevel = {'a': 'alpha', 'b': 'beta', '.': 'final'}[releaselevel]
36-
if releaselevel == 'final':
37-
_tk_patchlevel = major, minor, serial, releaselevel, 0
38-
else:
39-
_tk_patchlevel = major, minor, 0, releaselevel, serial
31+
_tk_patchlevel = tcl.info_patchlevel()
4032
return _tk_patchlevel
4133

4234

@@ -723,7 +715,7 @@ def test_huge_string_builtins2(self, size):
723715
def setUpModule():
724716
if support.verbose:
725717
tcl = Tcl()
726-
print('patchlevel =', tcl.call('info', 'patchlevel'))
718+
print('patchlevel =', tcl.call('info', 'patchlevel'), flush=True)
727719

728720

729721
if __name__ == "__main__":

Lib/tkinter/__init__.py

+28
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
tk.mainloop()
3131
"""
3232

33+
import collections
3334
import enum
3435
import sys
3536
import types
@@ -143,6 +144,28 @@ def _splitdict(tk, v, cut_minus=True, conv=None):
143144
dict[key] = value
144145
return dict
145146

147+
class _VersionInfoType(collections.namedtuple('_VersionInfoType',
148+
('major', 'minor', 'micro', 'releaselevel', 'serial'))):
149+
def __str__(self):
150+
if self.releaselevel == 'final':
151+
return f'{self.major}.{self.minor}.{self.micro}'
152+
else:
153+
return f'{self.major}.{self.minor}{self.releaselevel[0]}{self.serial}'
154+
155+
def _parse_version(version):
156+
import re
157+
m = re.fullmatch(r'(\d+)\.(\d+)([ab.])(\d+)', version)
158+
major, minor, releaselevel, serial = m.groups()
159+
major, minor, serial = int(major), int(minor), int(serial)
160+
if releaselevel == '.':
161+
micro = serial
162+
serial = 0
163+
releaselevel = 'final'
164+
else:
165+
micro = 0
166+
releaselevel = {'a': 'alpha', 'b': 'beta'}[releaselevel]
167+
return _VersionInfoType(major, minor, micro, releaselevel, serial)
168+
146169

147170
@enum._simple_enum(enum.StrEnum)
148171
class EventType:
@@ -1055,6 +1078,11 @@ def tkraise(self, aboveThis=None):
10551078

10561079
lift = tkraise
10571080

1081+
def info_patchlevel(self):
1082+
"""Returns the exact version of the Tcl library."""
1083+
patchlevel = self.tk.call('info', 'patchlevel')
1084+
return _parse_version(patchlevel)
1085+
10581086
def winfo_atom(self, name, displayof=0):
10591087
"""Return integer which represents atom NAME."""
10601088
args = ('winfo', 'atom') + self._displayof(displayof) + (name,)

Lib/tkinter/test/support.py

+1-9
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,7 @@ def get_tk_patchlevel():
101101
global _tk_patchlevel
102102
if _tk_patchlevel is None:
103103
tcl = tkinter.Tcl()
104-
patchlevel = tcl.call('info', 'patchlevel')
105-
m = re.fullmatch(r'(\d+)\.(\d+)([ab.])(\d+)', patchlevel)
106-
major, minor, releaselevel, serial = m.groups()
107-
major, minor, serial = int(major), int(minor), int(serial)
108-
releaselevel = {'a': 'alpha', 'b': 'beta', '.': 'final'}[releaselevel]
109-
if releaselevel == 'final':
110-
_tk_patchlevel = major, minor, serial, releaselevel, 0
111-
else:
112-
_tk_patchlevel = major, minor, 0, releaselevel, serial
104+
_tk_patchlevel = tcl.info_patchlevel()
113105
return _tk_patchlevel
114106

115107
units = {

Lib/tkinter/test/test_tkinter/test_misc.py

+29
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,35 @@ def callback():
341341
self.assertEqual(log, [1])
342342
self.assertTrue(self.root.winfo_exists())
343343

344+
def test_info_patchlevel(self):
345+
vi = self.root.info_patchlevel()
346+
f = tkinter.Frame(self.root)
347+
self.assertEqual(f.info_patchlevel(), vi)
348+
# The following is almost a copy of tests for sys.version_info.
349+
self.assertIsInstance(vi[:], tuple)
350+
self.assertEqual(len(vi), 5)
351+
self.assertIsInstance(vi[0], int)
352+
self.assertIsInstance(vi[1], int)
353+
self.assertIsInstance(vi[2], int)
354+
self.assertIn(vi[3], ("alpha", "beta", "candidate", "final"))
355+
self.assertIsInstance(vi[4], int)
356+
self.assertIsInstance(vi.major, int)
357+
self.assertIsInstance(vi.minor, int)
358+
self.assertIsInstance(vi.micro, int)
359+
self.assertIn(vi.releaselevel, ("alpha", "beta", "final"))
360+
self.assertIsInstance(vi.serial, int)
361+
self.assertEqual(vi[0], vi.major)
362+
self.assertEqual(vi[1], vi.minor)
363+
self.assertEqual(vi[2], vi.micro)
364+
self.assertEqual(vi[3], vi.releaselevel)
365+
self.assertEqual(vi[4], vi.serial)
366+
self.assertTrue(vi > (1,0,0))
367+
if vi.releaselevel == 'final':
368+
self.assertEqual(vi.serial, 0)
369+
else:
370+
self.assertEqual(vi.micro, 0)
371+
self.assertTrue(str(vi).startswith(f'{vi.major}.{vi.minor}'))
372+
344373

345374
class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
346375

Lib/tkinter/test/widget_tests.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -517,4 +517,4 @@ def test(self, option=option):
517517
def setUpModule():
518518
if test.support.verbose:
519519
tcl = tkinter.Tcl()
520-
print('patchlevel =', tcl.call('info', 'patchlevel'))
520+
print('patchlevel =', tcl.call('info', 'patchlevel'), flush=True)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
In the :mod:`tkinter` module add method ``info_patchlevel()`` which returns
2+
the exact version of the Tcl library as a named tuple similar to
3+
:data:`sys.version_info`.

0 commit comments

Comments
 (0)