From cb28dbdcab992878e8a2710152469b537362e21b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 22 Jun 2026 01:03:06 +0300 Subject: [PATCH] gh-151878: Add tkinter Entry and Spinbox validate methods Wrap the Tk "validate" widget command of the entry and spinbox widgets as the methods Entry.validate() and Spinbox.validate(), forcing an evaluation of the validatecommand independently of the validate option and returning whether the value is valid. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01XWevzas4XVpjzedzR9gKVo --- Doc/library/tkinter.rst | 16 ++++++++++++++++ Doc/whatsnew/3.16.rst | 5 +++++ Lib/test/test_tkinter/test_widgets.py | 19 +++++++++++++++++++ Lib/tkinter/__init__.py | 16 ++++++++++++++++ ...-06-22-01-02-33.gh-issue-151878.IFIA5C.rst | 3 +++ 5 files changed, 59 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-06-22-01-02-33.gh-issue-151878.IFIA5C.rst diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 222a4d0128bd8d..b96ee24803465f 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -4141,6 +4141,14 @@ Widget classes Typically associated with mouse motion events, to produce the effect of dragging the entry at high speed through the window. + .. method:: validate() + + Force an evaluation of the command given by the *validatecommand* option, + independently of the conditions specified by the *validate* option, and + return whether the value is considered valid. + + .. versionadded:: next + .. class:: Frame(master=None, cnf={}, **kw) @@ -5069,6 +5077,14 @@ Widget classes .. versionadded:: 3.8 + .. method:: validate() + + Force an evaluation of the command given by the *validatecommand* option, + independently of the conditions specified by the *validate* option, and + return whether the value is considered valid. + + .. versionadded:: next + .. class:: Text(master=None, cnf={}, **kw) diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index ec8e367d938ddb..fd5f5e5a5788a1 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -157,6 +157,11 @@ tkinter synchronization of the displayed view with the underlying text. (Contributed by Serhiy Storchaka in :gh:`151675`.) +* Added a :meth:`!validate` method to the :class:`!tkinter.Entry` and + :class:`!tkinter.Spinbox` widgets, which forces an evaluation of the + validation command. + (Contributed by Serhiy Storchaka in :gh:`151878`.) + xml --- diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 4b51d219d87e5b..d0305562a0cb05 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -589,6 +589,25 @@ def test_select_aliases(self): self.assertRaisesRegex(TclError, 'bad entry index "xyz"', widget.select_range, 'xyz', 'end') + def test_validate(self): + calls = [] + def validatecommand(value): + calls.append(value) + return value.isdigit() + # validate='none' means validation is never triggered automatically, + # so validate() exercises the forced evaluation. + widget = self.create(validate='none', + validatecommand=(self.root.register(validatecommand), '%P')) + widget.insert(0, '123') + result = widget.validate() + self.assertIs(result, True) + self.assertEqual(calls, ['123']) + widget.delete(0, 'end') + widget.insert(0, 'abc') + calls.clear() + self.assertIs(widget.validate(), False) + self.assertEqual(calls, ['abc']) + @add_configure_tests(StandardOptionsTests) class SpinboxTest(EntryTest, unittest.TestCase): diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 8bdf7cc1e2d96b..4b2291b41fc26e 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -3401,6 +3401,14 @@ def selection_to(self, index): select_to = selection_to + def validate(self): + """Force an evaluation of the validation command. + + This evaluates the command given by the validatecommand option, + independently of the conditions specified by the validate option. + Return whether the value is considered valid.""" + return self.tk.getboolean(self.tk.call(self._w, 'validate')) + class Frame(Widget): """Frame widget which may contain other widgets and can have a 3D border.""" @@ -4913,6 +4921,14 @@ def selection_to(self, index): """Set the variable end of a selection to INDEX.""" self.selection('to', index) + def validate(self): + """Force an evaluation of the validation command. + + This evaluates the command given by the validatecommand option, + independently of the conditions specified by the validate option. + Return whether the value is considered valid.""" + return self.tk.getboolean(self.tk.call(self._w, 'validate')) + ########################################################################### diff --git a/Misc/NEWS.d/next/Library/2026-06-22-01-02-33.gh-issue-151878.IFIA5C.rst b/Misc/NEWS.d/next/Library/2026-06-22-01-02-33.gh-issue-151878.IFIA5C.rst new file mode 100644 index 00000000000000..af0d2c25136c45 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-22-01-02-33.gh-issue-151878.IFIA5C.rst @@ -0,0 +1,3 @@ +Add the :meth:`!validate` method to the :class:`tkinter.Entry` and +:class:`tkinter.Spinbox` widgets, forcing an evaluation of the validation +command.