From 79ec7883fcbde3592c934aa97015276221bf2e44 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 10 May 2026 15:46:01 -0700 Subject: [PATCH 1/4] Add Python 3.15 tkinter updates --- stdlib/@tests/stubtest_allowlists/py315.txt | 8 --- stdlib/tkinter/__init__.pyi | 75 +++++++++++++++++---- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/stdlib/@tests/stubtest_allowlists/py315.txt b/stdlib/@tests/stubtest_allowlists/py315.txt index 910f72b6ae56..7e271ce59952 100644 --- a/stdlib/@tests/stubtest_allowlists/py315.txt +++ b/stdlib/@tests/stubtest_allowlists/py315.txt @@ -181,19 +181,11 @@ sys._monitoring sys.last_exc threading.Condition.locked tkinter.Grid.content -tkinter.Grid.grid_content tkinter.Image.__iter__ tkinter.Misc.__iter__ tkinter.Misc.content -tkinter.Misc.grid_content -tkinter.Misc.pack_content -tkinter.Misc.place_content tkinter.Pack.content -tkinter.Pack.pack_content tkinter.Place.content -tkinter.Place.place_content -tkinter.Text.search -tkinter.Text.search_all tkinter.font.Font.__iter__ tkinter.simpledialog.__all__ types.MappingProxyType.get diff --git a/stdlib/tkinter/__init__.pyi b/stdlib/tkinter/__init__.pyi index 0520a55c92e2..060c7d06aa8c 100644 --- a/stdlib/tkinter/__init__.pyi +++ b/stdlib/tkinter/__init__.pyi @@ -313,6 +313,9 @@ class Event(Generic[_W_co]): type: EventType widget: _W_co delta: int + if sys.version_info >= (3, 15): + detail: str + user_data: str if sys.version_info >= (3, 14): def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... @@ -627,6 +630,10 @@ class Misc: def pack_slaves(self) -> list[Widget]: ... def grid_slaves(self, row: int | None = None, column: int | None = None) -> list[Widget]: ... def place_slaves(self) -> list[Widget]: ... + if sys.version_info >= (3, 15): + def pack_content(self) -> list[Widget]: ... + def grid_content(self, row: int | None = None, column: int | None = None) -> list[Widget]: ... + def place_content(self) -> list[Widget]: ... slaves = pack_slaves def event_add(self, virtual: str, *sequences: str) -> None: ... def event_delete(self, virtual: str, *sequences: str) -> None: ... @@ -1103,6 +1110,8 @@ class Pack: ) -> None: ... def pack_forget(self) -> None: ... def pack_info(self) -> _PackInfo: ... # errors if widget hasn't been packed + if sys.version_info >= (3, 15): + def pack_content(self) -> list[Widget]: ... pack = pack_configure forget = pack_forget propagate = Misc.pack_propagate @@ -1141,6 +1150,8 @@ class Place: ) -> None: ... def place_forget(self) -> None: ... def place_info(self) -> _PlaceInfo: ... + if sys.version_info >= (3, 15): + def place_content(self) -> list[Widget]: ... place = place_configure info = place_info @@ -1178,6 +1189,8 @@ class Grid: def grid_forget(self) -> None: ... def grid_remove(self) -> None: ... def grid_info(self) -> _GridInfo: ... + if sys.version_info >= (3, 15): + def grid_content(self, row: int | None = None, column: int | None = None) -> list[Widget]: ... grid = grid_configure location = Misc.grid_location size = Misc.grid_size @@ -3598,19 +3611,55 @@ class Text(Widget, XView, YView): ) -> None: ... def scan_mark(self, x: int, y: int) -> None: ... def scan_dragto(self, x: int, y: int) -> None: ... - def search( - self, - pattern: str, - index: str | float | _tkinter.Tcl_Obj | Widget, - stopindex: str | float | _tkinter.Tcl_Obj | Widget | None = None, - forwards: bool | None = None, - backwards: bool | None = None, - exact: bool | None = None, - regexp: bool | None = None, - nocase: bool | None = None, - count: Variable | None = None, - elide: bool | None = None, - ) -> str: ... # returns empty string for not found + if sys.version_info >= (3, 15): + def search( + self, + pattern: str, + index: str | float | _tkinter.Tcl_Obj | Widget, + stopindex: str | float | _tkinter.Tcl_Obj | Widget | None = None, + forwards: bool | None = None, + backwards: bool | None = None, + exact: bool | None = None, + regexp: bool | None = None, + nocase: bool | None = None, + count: Variable | None = None, + elide: bool | None = None, + *, + nolinestop: bool | None = None, + strictlimits: bool | None = None, + ) -> str: ... # returns empty string for not found + def search_all( + self, + pattern: str, + index: str | float | _tkinter.Tcl_Obj | Widget, + stopindex: str | float | _tkinter.Tcl_Obj | Widget | None = None, + *, + forwards: bool | None = None, + backwards: bool | None = None, + exact: bool | None = None, + regexp: bool | None = None, + nocase: bool | None = None, + count: Variable | None = None, + elide: bool | None = None, + nolinestop: bool | None = None, + overlap: bool | None = None, + strictlimits: bool | None = None, + ) -> tuple[str, ...]: ... + else: + def search( + self, + pattern: str, + index: str | float | _tkinter.Tcl_Obj | Widget, + stopindex: str | float | _tkinter.Tcl_Obj | Widget | None = None, + forwards: bool | None = None, + backwards: bool | None = None, + exact: bool | None = None, + regexp: bool | None = None, + nocase: bool | None = None, + count: Variable | None = None, + elide: bool | None = None, + ) -> str: ... # returns empty string for not found + def see(self, index: str | float | _tkinter.Tcl_Obj | Widget) -> None: ... def tag_add( self, tagName: str, index1: str | float | _tkinter.Tcl_Obj | Widget, *args: str | float | _tkinter.Tcl_Obj | Widget From ec6e688769550a7b23603e64ab20271201d083b3 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 10 May 2026 16:03:19 -0700 Subject: [PATCH 2/4] Add tkinter content aliases --- stdlib/@tests/stubtest_allowlists/py315.txt | 4 ---- stdlib/tkinter/__init__.pyi | 8 ++++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/stdlib/@tests/stubtest_allowlists/py315.txt b/stdlib/@tests/stubtest_allowlists/py315.txt index 7e271ce59952..ebc865c355ce 100644 --- a/stdlib/@tests/stubtest_allowlists/py315.txt +++ b/stdlib/@tests/stubtest_allowlists/py315.txt @@ -180,12 +180,8 @@ sys.__jit sys._monitoring sys.last_exc threading.Condition.locked -tkinter.Grid.content tkinter.Image.__iter__ tkinter.Misc.__iter__ -tkinter.Misc.content -tkinter.Pack.content -tkinter.Place.content tkinter.font.Font.__iter__ tkinter.simpledialog.__all__ types.MappingProxyType.get diff --git a/stdlib/tkinter/__init__.pyi b/stdlib/tkinter/__init__.pyi index 060c7d06aa8c..c96655f59a72 100644 --- a/stdlib/tkinter/__init__.pyi +++ b/stdlib/tkinter/__init__.pyi @@ -634,6 +634,8 @@ class Misc: def pack_content(self) -> list[Widget]: ... def grid_content(self, row: int | None = None, column: int | None = None) -> list[Widget]: ... def place_content(self) -> list[Widget]: ... + # Runtime aliases this to pack_content/grid_content/place_content depending on the mixin class. + def content(self, *args: Any, **kwargs: Any) -> list[Widget]: ... slaves = pack_slaves def event_add(self, virtual: str, *sequences: str) -> None: ... def event_delete(self, virtual: str, *sequences: str) -> None: ... @@ -1112,6 +1114,8 @@ class Pack: def pack_info(self) -> _PackInfo: ... # errors if widget hasn't been packed if sys.version_info >= (3, 15): def pack_content(self) -> list[Widget]: ... + # Runtime aliases this to pack_content/grid_content/place_content depending on the mixin class. + def content(self, *args: Any, **kwargs: Any) -> list[Widget]: ... pack = pack_configure forget = pack_forget propagate = Misc.pack_propagate @@ -1152,6 +1156,8 @@ class Place: def place_info(self) -> _PlaceInfo: ... if sys.version_info >= (3, 15): def place_content(self) -> list[Widget]: ... + # Runtime aliases this to pack_content/grid_content/place_content depending on the mixin class. + def content(self, *args: Any, **kwargs: Any) -> list[Widget]: ... place = place_configure info = place_info @@ -1191,6 +1197,8 @@ class Grid: def grid_info(self) -> _GridInfo: ... if sys.version_info >= (3, 15): def grid_content(self, row: int | None = None, column: int | None = None) -> list[Widget]: ... + # Runtime aliases this to pack_content/grid_content/place_content depending on the mixin class. + def content(self, *args: Any, **kwargs: Any) -> list[Widget]: ... grid = grid_configure location = Misc.grid_location size = Misc.grid_size From fd377125e71e9812c72a08804e9a5c0878a8905a Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 10 May 2026 16:08:09 -0700 Subject: [PATCH 3/4] Use exact tkinter content signatures --- stdlib/tkinter/__init__.pyi | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/stdlib/tkinter/__init__.pyi b/stdlib/tkinter/__init__.pyi index c96655f59a72..e1f3016b70b7 100644 --- a/stdlib/tkinter/__init__.pyi +++ b/stdlib/tkinter/__init__.pyi @@ -634,8 +634,7 @@ class Misc: def pack_content(self) -> list[Widget]: ... def grid_content(self, row: int | None = None, column: int | None = None) -> list[Widget]: ... def place_content(self) -> list[Widget]: ... - # Runtime aliases this to pack_content/grid_content/place_content depending on the mixin class. - def content(self, *args: Any, **kwargs: Any) -> list[Widget]: ... + content = pack_content slaves = pack_slaves def event_add(self, virtual: str, *sequences: str) -> None: ... def event_delete(self, virtual: str, *sequences: str) -> None: ... @@ -1114,8 +1113,7 @@ class Pack: def pack_info(self) -> _PackInfo: ... # errors if widget hasn't been packed if sys.version_info >= (3, 15): def pack_content(self) -> list[Widget]: ... - # Runtime aliases this to pack_content/grid_content/place_content depending on the mixin class. - def content(self, *args: Any, **kwargs: Any) -> list[Widget]: ... + content = pack_content pack = pack_configure forget = pack_forget propagate = Misc.pack_propagate @@ -1156,8 +1154,7 @@ class Place: def place_info(self) -> _PlaceInfo: ... if sys.version_info >= (3, 15): def place_content(self) -> list[Widget]: ... - # Runtime aliases this to pack_content/grid_content/place_content depending on the mixin class. - def content(self, *args: Any, **kwargs: Any) -> list[Widget]: ... + content = place_content place = place_configure info = place_info @@ -1197,8 +1194,7 @@ class Grid: def grid_info(self) -> _GridInfo: ... if sys.version_info >= (3, 15): def grid_content(self, row: int | None = None, column: int | None = None) -> list[Widget]: ... - # Runtime aliases this to pack_content/grid_content/place_content depending on the mixin class. - def content(self, *args: Any, **kwargs: Any) -> list[Widget]: ... + content = grid_content grid = grid_configure location = Misc.grid_location size = Misc.grid_size @@ -1210,7 +1206,7 @@ class BaseWidget(Misc): def destroy(self) -> None: ... # This class represents any widget except Toplevel or Tk. -class Widget(BaseWidget, Pack, Place, Grid): +class Widget(BaseWidget, Pack, Place, Grid): # type: ignore[misc] # content aliases differ across geometry mixins. # Allow bind callbacks to take e.g. Event[Label] instead of Event[Misc]. # Tk and Toplevel get notified for their child widgets' events, but other # widgets don't. @@ -1382,7 +1378,7 @@ class Button(Widget): def flash(self) -> None: ... def invoke(self) -> Any: ... -class Canvas(Widget, XView, YView): +class Canvas(Widget, XView, YView): # type: ignore[misc] # content aliases differ across geometry mixins. def __init__( self, master: Misc | None = None, @@ -2152,7 +2148,7 @@ class Checkbutton(Widget): def select(self) -> None: ... def toggle(self) -> None: ... -class Entry(Widget, XView): +class Entry(Widget, XView): # type: ignore[misc] # content aliases differ across geometry mixins. def __init__( self, master: Misc | None = None, @@ -2395,7 +2391,7 @@ class Label(Widget): def configure(self, cnf: str) -> tuple[str, str, str, Any, Any]: ... config = configure -class Listbox(Widget, XView, YView): +class Listbox(Widget, XView, YView): # type: ignore[misc] # content aliases differ across geometry mixins. def __init__( self, master: Misc | None = None, @@ -3197,7 +3193,7 @@ _WhatToCount: TypeAlias = Literal[ "chars", "displaychars", "displayindices", "displaylines", "indices", "lines", "xpixels", "ypixels" ] -class Text(Widget, XView, YView): +class Text(Widget, XView, YView): # type: ignore[misc] # content aliases differ across geometry mixins. def __init__( self, master: Misc | None = None, @@ -3985,7 +3981,7 @@ class BitmapImage(Image, _BitmapImageLike): def image_names() -> tuple[str, ...]: ... def image_types() -> tuple[str, ...]: ... -class Spinbox(Widget, XView): +class Spinbox(Widget, XView): # type: ignore[misc] # content aliases differ across geometry mixins. def __init__( self, master: Misc | None = None, From 6f08f4dbe4fec411ae1c4d560dc94220d48ec3e7 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 10 May 2026 16:13:32 -0700 Subject: [PATCH 4/4] Handle tkinter content aliases in ttk --- stdlib/tkinter/ttk.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/tkinter/ttk.pyi b/stdlib/tkinter/ttk.pyi index f546c2851860..c3285549b405 100644 --- a/stdlib/tkinter/ttk.pyi +++ b/stdlib/tkinter/ttk.pyi @@ -316,7 +316,7 @@ class Checkbutton(Widget): config = configure def invoke(self) -> Any: ... -class Entry(Widget, tkinter.Entry): +class Entry(Widget, tkinter.Entry): # type: ignore[misc] # content aliases differ across geometry mixins. def __init__( self, master: tkinter.Misc | None = None, @@ -718,7 +718,7 @@ class Notebook(Widget): def tabs(self): ... def enable_traversal(self) -> None: ... -class Panedwindow(Widget, tkinter.PanedWindow): +class Panedwindow(Widget, tkinter.PanedWindow): # type: ignore[misc] # content aliases differ across geometry mixins. def __init__( self, master: tkinter.Misc | None = None, @@ -1106,7 +1106,7 @@ class _TreeviewColumnDict(TypedDict): anchor: Literal["nw", "n", "ne", "w", "center", "e", "sw", "s", "se"] id: str -class Treeview(Widget, tkinter.XView, tkinter.YView): +class Treeview(Widget, tkinter.XView, tkinter.YView): # type: ignore[misc] # content aliases differ across geometry mixins. def __init__( self, master: tkinter.Misc | None = None,