From b353e8c29b79a7d1738262a3eadbbe98b05bfc1a Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 8 May 2026 06:36:56 -0700 Subject: [PATCH] tkinter: add **kwargs support to tkinter.Misc.after for 3.14 In Python 3.14, https://github.com/python/cpython/pull/126900 added kwargs support to `tkinter.Misc.after`. stubtest missed this because we allowlist the function for a different reason. Found by Codex along with #15717 (I didn't include it in that PR because I incorrectly convinced myself this one was more complicated). It also found missing **kwargs support for some asyncio create_task functions, but we already have issues/PRs about that (e.g. #13687). --- stdlib/tkinter/__init__.pyi | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/stdlib/tkinter/__init__.pyi b/stdlib/tkinter/__init__.pyi index 29073dd23cae..c6fe017c79ca 100644 --- a/stdlib/tkinter/__init__.pyi +++ b/stdlib/tkinter/__init__.pyi @@ -12,6 +12,7 @@ from typing import ( Generic, Literal, NamedTuple, + ParamSpec, Protocol, TypeAlias, TypedDict, @@ -376,6 +377,7 @@ getdouble = float def getboolean(s) -> bool: ... _Ts = TypeVarTuple("_Ts") +_P = ParamSpec("_P") @type_check_only class _GridIndexInfo(TypedDict, total=False): @@ -415,11 +417,19 @@ class Misc: def tk_focusFollowsMouse(self) -> None: ... def tk_focusNext(self) -> Misc | None: ... def tk_focusPrev(self) -> Misc | None: ... - # .after() can be called without the "func" argument, but it is basically never what you want. - # It behaves like time.sleep() and freezes the GUI app. - def after(self, ms: int | Literal["idle"], func: Callable[[Unpack[_Ts]], object], *args: Unpack[_Ts]) -> str: ... - # after_idle is essentially partialmethod(after, "idle") - def after_idle(self, func: Callable[[Unpack[_Ts]], object], *args: Unpack[_Ts]) -> str: ... + if sys.version_info >= (3, 14): + # .after() can be called without the "func" argument, but it is basically never what you want. + # It behaves like time.sleep() and freezes the GUI app. + def after(self, ms: int | Literal["idle"], func: Callable[_P, object], *args: _P.args, **kwargs: _P.kwargs) -> str: ... + # after_idle is essentially partialmethod(after, "idle") + def after_idle(self, func: Callable[_P, object], *args: _P.args, **kwargs: _P.kwargs) -> str: ... + else: + # .after() can be called without the "func" argument, but it is basically never what you want. + # It behaves like time.sleep() and freezes the GUI app. + def after(self, ms: int | Literal["idle"], func: Callable[[Unpack[_Ts]], object], *args: Unpack[_Ts]) -> str: ... + # after_idle is essentially partialmethod(after, "idle") + def after_idle(self, func: Callable[[Unpack[_Ts]], object], *args: Unpack[_Ts]) -> str: ... + def after_cancel(self, id: str) -> None: ... if sys.version_info >= (3, 13): def after_info(self, id: str | None = None) -> tuple[str, ...]: ...