From 6137804b1d9422c39d37fd4db173aacff1444c22 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 27 Jun 2026 15:17:34 +0300 Subject: [PATCH] gh-50409: Make action-only tkinter methods return None Many tkinter and tkinter.ttk methods that merely perform an action returned the empty string or empty tuple produced by the underlying Tcl command instead of None. They now return None, like other action methods. This also affects the setting form of several get/set methods; their querying form is unchanged. Co-Authored-By: Claude Opus 4.8 --- Lib/tkinter/__init__.py | 38 ++++++++++--------- Lib/tkinter/ttk.py | 14 ++++--- ...6-06-27-15-16-05.gh-issue-50409.24d72f.rst | 4 ++ 3 files changed, 33 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-27-15-16-05.gh-issue-50409.24d72f.rst diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 897a1ba093c2720..9185d0cd84b4805 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -2392,7 +2392,7 @@ def wm_command(self, value=None): def wm_deiconify(self): """Deiconify this widget. If it was never mapped it will not be mapped. On Windows it will raise this widget and give it the focus.""" - return self.tk.call('wm', 'deiconify', self._w) + self.tk.call('wm', 'deiconify', self._w) deiconify = wm_deiconify @@ -2459,7 +2459,7 @@ def wm_iconbadge(self, badge): # new in Tk 9.0 (Windows) or app panel (X11). On X11, the variable ::tk::icons::base_icon(WINDOW) must be set to the image used for the window icon for this command to work.""" - return self.tk.call('wm', 'iconbadge', self._w, badge) + self.tk.call('wm', 'iconbadge', self._w, badge) iconbadge = wm_iconbadge @@ -2481,7 +2481,7 @@ def wm_iconbitmap(self, bitmap=None, default=None): def wm_iconify(self): """Display widget as icon.""" - return self.tk.call('wm', 'iconify', self._w) + self.tk.call('wm', 'iconify', self._w) iconify = wm_iconify @@ -2654,7 +2654,7 @@ def wm_transient(self, master=None): def wm_withdraw(self): """Withdraw this widget from the screen such that it is unmapped and forgotten by the window manager. Re-draw it with wm_deiconify.""" - return self.tk.call('wm', 'withdraw', self._w) + self.tk.call('wm', 'withdraw', self._w) withdraw = wm_withdraw @@ -4189,19 +4189,19 @@ def edit_redo(self): then. Generates an error when the redo stack is empty. Does nothing when the undo option is false. """ - return self.edit("redo") + self.edit("redo") def edit_reset(self): """Clears the undo and redo stacks """ - return self.edit("reset") + self.edit("reset") def edit_separator(self): """Inserts a separator (boundary) on the undo stack. Does nothing when the undo option is false """ - return self.edit("separator") + self.edit("separator") def edit_undo(self): """Undoes the last edit action @@ -4212,7 +4212,7 @@ def edit_undo(self): an error when the undo stack is empty. Does nothing when the undo option is false """ - return self.edit("undo") + self.edit("undo") def get(self, index1, index2=None): """Return the text from INDEX1 to INDEX2 (not included).""" @@ -4411,7 +4411,7 @@ def tag_add(self, tagName, index1, *args): def tag_unbind(self, tagName, sequence, funcid=None): """Unbind for all characters with TAGNAME for event SEQUENCE the function identified with FUNCID.""" - return self._unbind((self._w, 'tag', 'bind', tagName, sequence), funcid) + self._unbind((self._w, 'tag', 'bind', tagName, sequence), funcid) def tag_bind(self, tagName, sequence, func, add=None): """Bind to all characters with TAGNAME at event SEQUENCE a call to function FUNC. @@ -5032,7 +5032,7 @@ def delete(self, first, last=None): defaults to first+1, i.e. a single character is deleted. This command returns an empty string. """ - return self.tk.call(self._w, 'delete', first, last) + self.tk.call(self._w, 'delete', first, last) def get(self): """Returns the spinbox's string""" @@ -5044,7 +5044,7 @@ def icursor(self, index): The insertion cursor will be displayed just before the character given by index. Returns an empty string """ - return self.tk.call(self._w, 'icursor', index) + self.tk.call(self._w, 'icursor', index) def identify(self, x, y): """Returns the name of the widget at position x, y @@ -5063,7 +5063,7 @@ def insert(self, index, s): Returns an empty string. """ - return self.tk.call(self._w, 'insert', index, s) + self.tk.call(self._w, 'insert', index, s) def invoke(self, element): """Causes the specified element to be invoked @@ -5071,7 +5071,7 @@ def invoke(self, element): The element could be buttondown or buttonup triggering the action associated with it. """ - return self.tk.call(self._w, 'invoke', element) + self.tk.call(self._w, 'invoke', element) def scan(self, *args): """Internal function.""" @@ -5116,7 +5116,7 @@ def selection_adjust(self, index): the characters between index and the most recent selection anchor point, inclusive. """ - return self.selection("adjust", index) + self.selection("adjust", index) def selection_clear(self): # overrides Misc.selection_clear """Clear the selection @@ -5124,7 +5124,7 @@ def selection_clear(self): # overrides Misc.selection_clear If the selection isn't in this widget then the command has no effect. """ - return self.selection("clear") + self.selection("clear") def selection_element(self, element=None): """Sets or gets the currently selected element. @@ -5132,7 +5132,9 @@ def selection_element(self, element=None): If a spinbutton element is specified, it will be displayed depressed. """ - return self.tk.call(self._w, 'selection', 'element', element) + if element is None: + return self.tk.call(self._w, 'selection', 'element') + self.tk.call(self._w, 'selection', 'element', element) def selection_from(self, index): """Set the fixed end of a selection to INDEX.""" @@ -5250,12 +5252,12 @@ def proxy_coord(self): def proxy_forget(self): """Remove the proxy from the display. """ - return self.proxy("forget") + self.proxy("forget") def proxy_place(self, x, y): """Place the proxy at the given x and y coordinates. """ - return self.proxy("place", x, y) + self.proxy("place", x, y) def sash(self, *args): """Internal function.""" diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py index 0cabc5c3140fd6b..c3c4a0143ce2757 100644 --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -708,7 +708,7 @@ def current(self, newindex=None): if res == '': return -1 return self.tk.getint(res) - return self.tk.call(self._w, "current", newindex) + self.tk.call(self._w, "current", newindex) def set(self, value): @@ -881,7 +881,9 @@ def select(self, tab_id=None): previously-selected window (if different) is unmapped. If tab_id is omitted, returns the widget name of the currently selected pane.""" - return self.tk.call(self._w, "select", tab_id) + if tab_id is None: + return self.tk.call(self._w, "select") + self.tk.call(self._w, "select", tab_id) def tab(self, tab_id, option=None, **kw): @@ -1263,7 +1265,9 @@ def exists(self, item): def focus(self, item=None): # overrides Misc.focus """If item is specified, sets the focus item to item. Otherwise, returns the current focus item, or '' if there is none.""" - return self.tk.call(self._w, "focus", item) + if item is None: + return self.tk.call(self._w, "focus") + self.tk.call(self._w, "focus", item) def heading(self, column, option=None, **kw): @@ -1617,7 +1621,7 @@ def cellfocus(self, cell=None): * Availability: Tk 9.1""" if cell is None: return self.tk.splitlist(self.tk.call(self._w, "cellfocus")) - return self.tk.call(self._w, "cellfocus", cell) + self.tk.call(self._w, "cellfocus", cell) def sort(self, parent, *, column=None, command=None, dictionary=False, @@ -1883,7 +1887,7 @@ def cellselection_anchor(self, cell=None): if cell is None: return self.tk.splitlist( self.tk.call(self._w, "cellselection", "anchor")) - return self.tk.call(self._w, "cellselection", "anchor", cell) + self.tk.call(self._w, "cellselection", "anchor", cell) def cellselection_includes(self, *cells): diff --git a/Misc/NEWS.d/next/Library/2026-06-27-15-16-05.gh-issue-50409.24d72f.rst b/Misc/NEWS.d/next/Library/2026-06-27-15-16-05.gh-issue-50409.24d72f.rst new file mode 100644 index 000000000000000..65309eaa7b2ecbe --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-27-15-16-05.gh-issue-50409.24d72f.rst @@ -0,0 +1,4 @@ +Many :mod:`tkinter` and :mod:`tkinter.ttk` methods that merely perform an +action no longer return the empty string or empty tuple produced by the +underlying Tcl command; they now return ``None``. This also affects the +setting form of several get/set methods (their querying form is unchanged).