Skip to content

Commit 053a00a

Browse files
Finish types for ttk.Style
1 parent 508e578 commit 053a00a

File tree

1 file changed

+87
-12
lines changed

1 file changed

+87
-12
lines changed

stdlib/tkinter/ttk.pyi

Lines changed: 87 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import _tkinter
2+
import sys
23
import tkinter
3-
from _typeshed import MaybeNone
4+
from _typeshed import MaybeNone, Incomplete
45
from collections.abc import Callable
56
from tkinter.font import _FontDescription
67
from typing import Any, Literal, TypedDict, overload, Iterable
7-
from typing_extensions import TypeAlias, Unpack
8+
from typing_extensions import TypeAlias, Unpack, Never
89

910
__all__ = [
1011
"Button",
@@ -47,18 +48,68 @@ _Padding: TypeAlias = (
4748

4849
# from ttk_widget (aka ttk::widget) manual page, differs from tkinter._Compound
4950
_TtkCompound: TypeAlias = Literal["", "text", "image", tkinter._Compound]
51+
5052
# Last item (option value to apply) varies between different options so use Any.
51-
# This doesn't have to be a tuple so also add a less precise Iterable option.
52-
_Statespec: TypeAlias = tuple[Unpack[tuple[str, ...]], Any] | Iterable[str | Any]
53+
# It could also be any iterable with items matching the tuple, but that case
54+
# hasn't been added here for consistency with _Padding above.
55+
_Statespec: TypeAlias = tuple[Unpack[tuple[str, ...]], Any]
56+
_ImageStatespec: TypeAlias = tuple[Unpack[tuple[str, ...]], tkinter._ImageSpec]
57+
_VsapiStatespec: TypeAlias = tuple[Unpack[tuple[str, ...]], int]
58+
class _Layout(TypedDict, total=False):
59+
side: Literal["left", "right", "top", "bottom"]
60+
sticky: str # consists of letters 'n', 's', 'w', 'e', may contain repeats, may be empty
61+
unit: Literal[0, 1] | bool
62+
children: _LayoutSpec
63+
# Note: there seem to be some other undocumented keys sometimes
64+
# This could be any sequence when passed as a parameter but will always be a list when returned.
65+
_LayoutSpec: TypeAlias = list[tuple[str, _Layout | None]]
66+
67+
# Keep these in sync with the appropriate methods in Style
68+
class _ElementCreateImageKwargs(TypedDict, total=False):
69+
border: _Padding
70+
height: tkinter._ScreenUnits
71+
padding: _Padding
72+
sticky: str
73+
width: tkinter._ScreenUnits
74+
_ElementCreateArgsCrossPlatform: TypeAlias = (
75+
# Could be any sequence here but types are not homogenous so just type it as tuple
76+
tuple[Literal['image'], tkinter._ImageSpec, Unpack[tuple[_ImageStatespec, ...]], _ElementCreateImageKwargs]
77+
| tuple[Literal['from'], str, str] | tuple[Literal['from'], str] # (fromelement is optional)
78+
)
79+
if sys.platform == "win32" and sys.version_info >= (3, 13):
80+
class _ElementCreateVsapiKwargsPadding(TypedDict, total=False):
81+
padding: _Padding
82+
class _ElementCreateVsapiKwargsMargin(TypedDict, total=False):
83+
padding: _Padding
84+
class _ElementCreateVsapiKwargsSize(TypedDict):
85+
width: tkinter._ScreenUnits
86+
height: tkinter._ScreenUnits
87+
_ElementCreateVsapiKwargsDict = (
88+
_ElementCreateVsapiKwargsPadding | _ElementCreateVsapiKwargsMargin | _ElementCreateVsapiKwargsSize)
89+
_ElementCreateArgs: TypeAlias = (
90+
_ElementCreateArgsCrossPlatform
91+
| tuple[Literal['vsapi'], str, int, _ElementCreateVsapiKwargsDict]
92+
| tuple[Literal['vsapi'], str, int, _VsapiStatespec, _ElementCreateVsapiKwargsDict])
93+
else:
94+
_ElementCreateArgs: TypeAlias = _ElementCreateArgsCrossPlatform
95+
_ThemeSettingsValue = TypedDict(
96+
'_ThemeSettingsValue', {
97+
'configure': dict[str, Any],
98+
'map': dict[str, Iterable[_Statespec]],
99+
'layout': _LayoutSpec,
100+
'element create': _ElementCreateArgs,
101+
}, total=False
102+
)
103+
_ThemeSettings = dict[str, _ThemeSettingsValue]
53104

54105
class Style:
55106
master: tkinter.Misc
56107
tk: _tkinter.TkappType
57108
def __init__(self, master: tkinter.Misc | None = None) -> None: ...
58-
def lookup(self, style, option, state=None, default=None): ...
59-
def layout(self, style, layoutspec=None): ...
109+
# For these methods, values given vary between options. Returned values
110+
# seem to be str, but this might not always be the case.
60111
@overload
61-
def configure(self, style: str) -> dict[str, Any]: ...
112+
def configure(self, style: str) -> dict[str, Any] | None: ... # Returns None if no configuration.
62113
@overload
63114
def configure(self, style: str, query_opt: str, **kw: Any) -> Any: ...
64115
@overload
@@ -67,11 +118,35 @@ class Style:
67118
def map(self, style: str, query_opt: str) -> _Statespec: ...
68119
@overload
69120
def map(self, style: str, **kw: Iterable[_Statespec]) -> dict[str, _Statespec]: ...
70-
def element_create(self, elementname, etype, *args, **kw) -> None: ...
71-
def element_names(self): ...
72-
def element_options(self, elementname): ...
73-
def theme_create(self, themename, parent=None, settings=None) -> None: ...
74-
def theme_settings(self, themename, settings) -> None: ...
121+
def lookup(self, style: str, option: str, state: Iterable[str] | None = None, default: Any | None = None) -> Any: ...
122+
@overload
123+
def layout(self, style: str, layoutspec: _LayoutSpec) -> list[Never]: ... # Always seems to return an empty list
124+
@overload
125+
def layout(self, style: str, layoutspec: None = None) -> _LayoutSpec: ...
126+
@overload
127+
def element_create(self, elementname: str, etype: Literal['image'], __default_image: tkinter._ImageSpec,
128+
*imagespec: _ImageStatespec, border: _Padding = ..., height: tkinter._ScreenUnits = ...,
129+
padding: _Padding = ..., sticky: str = ..., width: tkinter._ScreenUnits = ...) -> None: ...
130+
@overload
131+
def element_create(self, elementname: str, etype: Literal['from'], __themename: str, __fromelement: str = ...) -> None: ...
132+
if sys.platform == 'win32' and sys.version_info >= (3, 13): # and tk version >= 8.6
133+
# margin, padding, and (width + height) are mutually exclusive. width
134+
# and height must either both be present or not present at all. Note:
135+
# There are other undocumented options if you look at ttk's source code.
136+
@overload
137+
def element_create(self, elementname: str, etype: Literal['vsapi'], __class: str, __part: int,
138+
__vs_statespec: _VsapiStatespec = (((), 1),), *, padding: _Padding = ...) -> None: ...
139+
@overload
140+
def element_create(self, elementname: str, etype: Literal['vsapi'], __class: str, __part: int,
141+
__vs_statespec: _VsapiStatespec = (((), 1),), *, margin: _Padding = ...) -> None: ...
142+
@overload
143+
def element_create(self, elementname: str, etype: Literal['vsapi'], __class: str, __part: int,
144+
__vs_statespec: _VsapiStatespec = (((), 1),), *, width: tkinter._ScreenUnits,
145+
height: tkinter._ScreenUnits) -> None: ...
146+
def element_names(self) -> tuple[str, ...]: ...
147+
def element_options(self, elementname: str) -> tuple[str, ...]: ...
148+
def theme_create(self, themename: str, parent: str = None, settings: _ThemeSettings | None = None) -> None: ...
149+
def theme_settings(self, themename: str, settings: _ThemeSettings) -> None: ...
75150
def theme_names(self) -> tuple[str, ...]: ...
76151
@overload
77152
def theme_use(self, themename: str) -> None: ...

0 commit comments

Comments
 (0)