diff --git a/stdlib/3/tkinter/__init__.pyi b/stdlib/3/tkinter/__init__.pyi index 9b1e3d1296ec..8f03107c984a 100644 --- a/stdlib/3/tkinter/__init__.pyi +++ b/stdlib/3/tkinter/__init__.pyi @@ -2,7 +2,8 @@ import sys from enum import Enum from tkinter.constants import * # noqa: F403 from types import TracebackType -from typing import Any, Callable, Dict, Optional, Tuple, Type, Union +from typing import Any, Callable, Dict, Generic, Optional, Tuple, Type, TypeVar, Union, overload +from typing_extensions import Literal TclError: Any wantobjects: Any @@ -52,7 +53,10 @@ if sys.version_info >= (3, 6): VirtualEvent: str = ... Visibility: str = ... -class Event: +# Events considered covariant because you should never assign to event.widget. +_W = TypeVar("_W", covariant=True, bound="Misc") + +class Event(Generic[_W]): serial: int num: int focus: bool @@ -73,7 +77,7 @@ class Event: type: EventType else: type: str - widget: Misc + widget: _W delta: int def NoDefaultRoot(): ... @@ -119,6 +123,8 @@ getdouble: Any def getboolean(s): ... +# This class is the base class of all widgets. Don't use BaseWidget or Widget +# for that because Tk doesn't inherit from Widget or BaseWidget. class Misc: def destroy(self): ... def deletecommand(self, name): ... @@ -222,12 +228,47 @@ class Misc: def update(self): ... def update_idletasks(self): ... def bindtags(self, tagList: Optional[Any] = ...): ... - def bind(self, sequence: Optional[Any] = ..., func: Optional[Any] = ..., add: Optional[Any] = ...): ... - def unbind(self, sequence, funcid: Optional[Any] = ...): ... - def bind_all(self, sequence: Optional[Any] = ..., func: Optional[Any] = ..., add: Optional[Any] = ...): ... - def unbind_all(self, sequence): ... - def bind_class(self, className, sequence: Optional[Any] = ..., func: Optional[Any] = ..., add: Optional[Any] = ...): ... - def unbind_class(self, className, sequence): ... + # bind with isinstance(func, str) doesn't return anything, but all other + # binds do. The default value of func is not str. + @overload + def bind( + self, + sequence: Optional[str] = ..., + func: Optional[Callable[[Event[Misc]], Optional[Literal["break"]]]] = ..., + add: Optional[bool] = ..., + ) -> str: ... + @overload + def bind(self, sequence: Optional[str], func: str, add: Optional[bool] = ...) -> None: ... + @overload + def bind(self, *, func: str, add: Optional[bool] = ...) -> None: ... + # There's no way to know what type of widget bind_all and bind_class + # callbacks will get, so those are Misc. + @overload + def bind_all( + self, + sequence: Optional[str] = ..., + func: Optional[Callable[[Event[Misc]], Optional[Literal["break"]]]] = ..., + add: Optional[bool] = ..., + ) -> str: ... + @overload + def bind_all(self, sequence: Optional[str], func: str, add: Optional[bool] = ...) -> None: ... + @overload + def bind_all(self, *, func: str, add: Optional[bool] = ...) -> None: ... + @overload + def bind_class( + self, + className: str, + sequence: Optional[str] = ..., + func: Optional[Callable[[Event[Misc]], Optional[Literal["break"]]]] = ..., + add: Optional[bool] = ..., + ) -> str: ... + @overload + def bind_class(self, className: str, sequence: Optional[str], func: str, add: Optional[bool] = ...) -> None: ... + @overload + def bind_class(self, className: str, *, func: str, add: Optional[bool] = ...) -> None: ... + def unbind(self, sequence: str, funcid: Optional[str] = ...) -> None: ... + def unbind_all(self, sequence: str) -> None: ... + def unbind_class(self, className: str, sequence: str) -> None: ... def mainloop(self, n: int = ...): ... def quit(self): ... def nametowidget(self, name): ... @@ -419,7 +460,22 @@ class BaseWidget(Misc): def __init__(self, master, widgetName, cnf=..., kw=..., extra=...): ... def destroy(self): ... -class Widget(BaseWidget, Pack, Place, Grid): ... +# This class represents any widget except Toplevel or Tk. +class Widget(BaseWidget, Pack, Place, Grid): + # 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. + @overload + def bind( + self: _W, + sequence: Optional[str] = ..., + func: Optional[Callable[[Event[_W]], Optional[Literal["break"]]]] = ..., + add: Optional[bool] = ..., + ) -> str: ... + @overload + def bind(self, sequence: Optional[str], func: str, add: Optional[bool] = ...) -> None: ... + @overload + def bind(self, *, func: str, add: Optional[bool] = ...) -> None: ... class Toplevel(BaseWidget, Wm): def __init__(self, master: Optional[Any] = ..., cnf=..., **kw): ... @@ -440,8 +496,19 @@ class Canvas(Widget, XView, YView): def addtag_overlapping(self, newtag, x1, y1, x2, y2): ... def addtag_withtag(self, newtag, tagOrId): ... def bbox(self, *args): ... - def tag_unbind(self, tagOrId, sequence, funcid: Optional[Any] = ...): ... - def tag_bind(self, tagOrId, sequence: Optional[Any] = ..., func: Optional[Any] = ..., add: Optional[Any] = ...): ... + @overload + def tag_bind( + self, + tagOrId: Union[str, int], + sequence: Optional[str] = ..., + func: Optional[Callable[[Event[Canvas]], Optional[Literal["break"]]]] = ..., + add: Optional[bool] = ..., + ) -> str: ... + @overload + def tag_bind(self, tagOrId: Union[str, int], sequence: Optional[str], func: str, add: Optional[bool] = ...) -> None: ... + @overload + def tag_bind(self, tagOrId: Union[str, int], *, func: str, add: Optional[bool] = ...) -> None: ... + def tag_unbind(self, tagOrId: Union[str, int], sequence: str, funcid: Optional[str] = ...) -> None: ... def canvasx(self, screenx, gridspacing: Optional[Any] = ...): ... def canvasy(self, screeny, gridspacing: Optional[Any] = ...): ... def coords(self, *args): ... @@ -660,8 +727,18 @@ class Text(Widget, XView, YView): ): ... def see(self, index): ... def tag_add(self, tagName, index1, *args): ... - def tag_unbind(self, tagName, sequence, funcid: Optional[Any] = ...): ... - def tag_bind(self, tagName, sequence, func, add: Optional[Any] = ...): ... + # tag_bind stuff is very similar to Canvas + @overload + def tag_bind( + self, + tagName: str, + sequence: Optional[str], + func: Optional[Callable[[Event[Text]], Optional[Literal["break"]]]], + add: Optional[bool] = ..., + ) -> str: ... + @overload + def tag_bind(self, tagName: str, sequence: Optional[str], func: str, add: Optional[bool] = ...) -> None: ... + def tag_unbind(self, tagName: str, sequence: str, funcid: Optional[str] = ...) -> None: ... def tag_cget(self, tagName, option): ... def tag_configure(self, tagName, cnf: Optional[Any] = ..., **kw): ... tag_config: Any diff --git a/stdlib/3/tkinter/ttk.pyi b/stdlib/3/tkinter/ttk.pyi index 4d7afe1da86c..4cd08dfa052e 100644 --- a/stdlib/3/tkinter/ttk.pyi +++ b/stdlib/3/tkinter/ttk.pyi @@ -1,6 +1,8 @@ import sys import tkinter -from typing import Any, List, Optional +from tkinter import Event +from typing import Any, Callable, Dict, List, Optional, Tuple, Type, TypeVar, Union, overload +from typing_extensions import Literal def tclobjs_to_py(adict): ... def setup_master(master: Optional[Any] = ...): ... @@ -145,7 +147,19 @@ class Treeview(Widget, tkinter.XView, tkinter.YView): def selection_remove(self, items): ... def selection_toggle(self, items): ... def set(self, item, column: Optional[Any] = ..., value: Optional[Any] = ...): ... - def tag_bind(self, tagname, sequence: Optional[Any] = ..., callback: Optional[Any] = ...): ... + # There's no tag_unbind() or 'add' argument for whatever reason. + # Also, it's 'callback' instead of 'func' here. + @overload + def tag_bind( + self, + tagname: str, + sequence: Optional[str] = ..., + callback: Optional[Callable[[Event[Treeview]], Optional[Literal["break"]]]] = ..., + ) -> str: ... + @overload + def tag_bind(self, tagname: str, sequence: Optional[str], callback: str) -> None: ... + @overload + def tag_bind(self, tagname: str, *, callback: str) -> None: ... def tag_configure(self, tagname, option: Optional[Any] = ..., **kw): ... def tag_has(self, tagname, item: Optional[Any] = ...): ...