Open ghost opened 10 months ago
@Barrowcroft Could you please elaborate a bit what mechanism are you using for type hinting and what error are you facing? Code snippets, error screenshot may help.
Thanks for your reply.
I am using type checking by putting " "python.analysis.typeCheckingMode": "strict", " into my settings file.
When I include CustomTkinter I get the message "Stub file not found for "customtkinter"
I also get issues any time I access the 'grid' or 'configure' methods. Messages "Type of "configure" is partially unknown" and "Type of "grid" is partially unknown" respectively.
I get similar problems with '.mainloop',
It may well be simply a matter of my misunderstanding type hinting. I should add that everything functions correctly, but the type checker complains a lot.
thanks
@Barrowcroft, In the customtkinter
library, type hints are currently provided to the CTk-specific widgets and methods. Notably, the hints do not extend to encompass classes or functions that remain identical in both the Tkinter
and customtkinter
frameworks. This facility will be addressed in the forthcoming version of the customtkinter
.
For users desiring comprehensive type hints, a recommended approach involves leveraging Python Interfaces. To implement type hints consistently across all scenarios, one can create a customtkinter.pyi
file within the current working directory of the user. This file should contain all requisite type hints, ensuring uniformity and clarity in various projects.
Guide and demonstration:
customtkinter.pyi
file:
from typing import Union, Tuple, Callable, Optional, Literal
import PIL
class CTk:
def __init__(self, fg_color: str = None) -> None:
...
def geometry(self, width_x_height: str) -> None:
"""Sets geometry of the window in width x height form."""
...
class CTkImage:
def __init__(self, light_image: PIL.Image | None, dark_image: PIL.Image | None, size: Tuple[int, int]) -> None: ...
...
class CTkFont:
def __init__(self, family: str, weight: str, size: int) -> None:
...
class Variable:
...
class CTkButton:
def __init__(self,
master: any,
width: int = 140,
height: int = 28,
corner_radius: Optional[int] = None,
border_width: Optional[int] = None,
border_spacing: int = 2,
bg_color: Union[str, Tuple[str, str]] = "transparent",
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
hover_color: Optional[Union[str, Tuple[str, str]]] = None,
border_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color_disabled: Optional[Union[str, Tuple[str, str]]] = None,
background_corner_colors: Union[Tuple[Union[str, Tuple[str, str]]], None] = None,
round_width_to_even_floats: bool = True,
round_height_to_even_floats: bool = True,
text: str = "CTkButton",
font: Optional[Union[tuple, CTkFont]] = None,
textvariable: Union[Variable, None] = None,
image: Union[CTkImage, CTkImage, None] = None,
state: str = "normal",
hover: bool = True,
command: Union[Callable[[], None], None] = None,
compound: str = "left",
anchor: str = "center",
**kwargs):
...
def destroy(self):
"""Deletes the object completely and frees up space."""
...
def configure(self,
corner_radius: float,
border_width: float,
border_spacing: float,
fg_color: str | tuple[str, str],
hover_color: str | tuple[str, str],
border_color: str | tuple[str, str],
text_color: str | tuple[str, str],
text_color_disabled: str | tuple[str, str],
background_corner_colors: Tuple[str, str, str, str],
text: str,
font: CTkFont | Tuple[str, int, str],
textvariable: Variable,
image: CTkImage | None,
state: str,
hover: bool,
command: Callable,
compound: Literal["left", "right", "top", "bottom"],
anchor: str,
kwargs
):
...
def cget(self,
corner_radius: float,
border_width: float,
border_spacing: float,
fg_color: str | tuple[str, str],
hover_color: str | tuple[str, str],
border_color: str | tuple[str, str],
text_color: str | tuple[str, str],
text_color_disabled: str | tuple[str, str],
background_corner_colors: Tuple[str, str, str, str],
text: str,
font: CTkFont | Tuple[str, int, str],
textvariable: Variable,
image: CTkImage | None,
state: str,
hover: bool,
command: Callable,
compound: Literal["left", "right", "top", "bottom"],
anchor: str,
kwargs
) -> any:
...
def invoke(self):
""" calls command function if button is not disabled """
...
def bind(self, sequence: str = None, command: Callable = None, add: Union[str, bool] = True):
""" called on the tkinter.Canvas """
...
def unbind(self, sequence: str = None, funcid: str = None):
""" called on the tkinter.Label and tkinter.Canvas """
...
def focus(self):
"""Takes the button in focus."""
...
def focus_set(self):
"""Takes the button in focus."""
...
def focus_force(self):
"""Takes the button in focus forced."""
...
def grid(self,
column: float,
columnspan: float,
in_: CTk,
ipadx: float,
ipady: float,
padx: float,
pady: float,
row: float,
rowspan: float,
sticky: Literal["n", "s", "e", "w", "nw", "ne", "sw", "se", "ew", "ns", "nsew"]
):
...
Output Demonstration:
configure
hover box
configure
typing list
grid
typing box
grid
typing list
grid
typing suggestion
You can add more methods, classes in the customtkinter.pyi
file for type hints in your projects as per your requirements.
Hope, it will be helpful for you.
Thank you so much. That is indeed really helpful. I will try and implement it that way, and see how it goes.
Thank you so much. That is indeed really helpful. I will try and implement it that way, and see how it goes.
@Barrowcroft You are most welcome :)
I recently started developing with strict type hinting switched on. This has thrown up lots of issues with calls to CustomTkinter methods. Is this a known issue or have I done something wrong? thanks