From c04a752e244177864b911b361e88f954ca165dcd Mon Sep 17 00:00:00 2001 From: Akuli Date: Sun, 11 Aug 2024 00:08:24 +0300 Subject: [PATCH] Create overloads for `tkinter.Text.count` (#12395) --- stdlib/@tests/stubtest_allowlists/common.txt | 1 + stdlib/@tests/test_cases/check_tkinter.py | 24 +++++++++++++++++++ stdlib/tkinter/__init__.pyi | 25 +++++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/stdlib/@tests/stubtest_allowlists/common.txt b/stdlib/@tests/stubtest_allowlists/common.txt index 8d28fbda3..bdecdac11 100644 --- a/stdlib/@tests/stubtest_allowlists/common.txt +++ b/stdlib/@tests/stubtest_allowlists/common.txt @@ -110,6 +110,7 @@ tkinter.simpledialog.[A-Z_]+ tkinter.simpledialog.TclVersion tkinter.simpledialog.TkVersion tkinter.Misc.after # we intentionally don't allow everything that "works" at runtime +tkinter.Text.count # stubtest somehow thinks that index1 parameter has a default value, but it doesn't in any of the overloads traceback.TracebackException.from_exception # explicitly expanding arguments going into TracebackException __init__ typing(_extensions)?\.IO\.__next__ # Added because IO streams are iterable. See https://github.com/python/typeshed/commit/97bc450acd60c1bcdafef3ce8fbe3b95a9c0cac3 typing.type_check_only # typing decorator that is not available at runtime diff --git a/stdlib/@tests/test_cases/check_tkinter.py b/stdlib/@tests/test_cases/check_tkinter.py index befac6697..ffee64dcb 100644 --- a/stdlib/@tests/test_cases/check_tkinter.py +++ b/stdlib/@tests/test_cases/check_tkinter.py @@ -3,6 +3,8 @@ from __future__ import annotations import tkinter import traceback import types +from typing import Optional, Tuple +from typing_extensions import assert_type def custom_handler(exc: type[BaseException], val: BaseException, tb: types.TracebackType | None) -> None: @@ -28,3 +30,25 @@ label.config(font=("", 12)) label.config(font=("", 12.34)) # type: ignore label.config(font=("", 12, "bold")) label.config(font=("", 12.34, "bold")) # type: ignore + + +# Test the `.count()` method. Comments show values that are returned at runtime. +t = tkinter.Text() +t.insert("end", "asd asd asd\nasd asd") + +assert_type(t.count("1.0", "2.3"), Optional[Tuple[int]]) # (15,) +assert_type(t.count("2.3", "2.3"), Optional[Tuple[int]]) # None +assert_type(t.count("1.0", "2.3", "indices"), Optional[Tuple[int]]) # (15,) +assert_type(t.count("2.3", "2.3", "indices"), Optional[Tuple[int]]) # None +assert_type(t.count("1.0", "2.3", "indices", "update"), Optional[int]) # 15 +assert_type(t.count("2.3", "2.3", "indices", "update"), Optional[int]) # None +assert_type(t.count("1.0", "2.3", "indices", "lines"), Tuple[int, int]) # (15, 1) +assert_type(t.count("2.3", "2.3", "indices", "lines"), Tuple[int, int]) # (0, 0) +assert_type(t.count("1.0", "2.3", "indices", "lines", "update"), Tuple[int, ...]) # (15, 1) +assert_type(t.count("2.3", "2.3", "indices", "lines", "update"), Tuple[int, ...]) # (0, 0) +assert_type(t.count("1.0", "2.3", "indices", "lines", "chars"), Tuple[int, ...]) # (15, 1, 15) +assert_type(t.count("2.3", "2.3", "indices", "lines", "chars"), Tuple[int, ...]) # (0, 0, 0) +assert_type(t.count("1.0", "2.3", "indices", "lines", "chars", "update"), Tuple[int, ...]) # (15, 1, 15) +assert_type(t.count("2.3", "2.3", "indices", "lines", "chars", "update"), Tuple[int, ...]) # (0, 0, 0) +assert_type(t.count("1.0", "2.3", "indices", "lines", "chars", "ypixels"), Tuple[int, ...]) # (15, 1, 15, 19) +assert_type(t.count("2.3", "2.3", "indices", "lines", "chars", "ypixels"), Tuple[int, ...]) # (0, 0, 0, 0) diff --git a/stdlib/tkinter/__init__.pyi b/stdlib/tkinter/__init__.pyi index 3c10a15c2..2a42eb789 100644 --- a/stdlib/tkinter/__init__.pyi +++ b/stdlib/tkinter/__init__.pyi @@ -2908,6 +2908,9 @@ class Scrollbar(Widget): def set(self, first: float | str, last: float | str) -> None: ... _TextIndex: TypeAlias = _tkinter.Tcl_Obj | str | float | Misc +_WhatToCount: TypeAlias = Literal[ + "chars", "displaychars", "displayindices", "displaylines", "indices", "lines", "xpixels", "ypixels" +] class Text(Widget, XView, YView): def __init__( @@ -3022,7 +3025,27 @@ class Text(Widget, XView, YView): config = configure def bbox(self, index: _TextIndex) -> tuple[int, int, int, int] | None: ... # type: ignore[override] def compare(self, index1: _TextIndex, op: Literal["<", "<=", "==", ">=", ">", "!="], index2: _TextIndex) -> bool: ... - def count(self, index1, index2, *args): ... # TODO + @overload + def count(self, index1: _TextIndex, index2: _TextIndex) -> tuple[int] | None: ... + @overload + def count(self, index1: _TextIndex, index2: _TextIndex, arg: _WhatToCount | Literal["update"], /) -> tuple[int] | None: ... + @overload + def count(self, index1: _TextIndex, index2: _TextIndex, arg1: Literal["update"], arg2: _WhatToCount, /) -> int | None: ... + @overload + def count(self, index1: _TextIndex, index2: _TextIndex, arg1: _WhatToCount, arg2: Literal["update"], /) -> int | None: ... + @overload + def count(self, index1: _TextIndex, index2: _TextIndex, arg1: _WhatToCount, arg2: _WhatToCount, /) -> tuple[int, int]: ... + @overload + def count( + self, + index1: _TextIndex, + index2: _TextIndex, + arg1: _WhatToCount | Literal["update"], + arg2: _WhatToCount | Literal["update"], + arg3: _WhatToCount | Literal["update"], + /, + *args: _WhatToCount | Literal["update"], + ) -> tuple[int, ...]: ... @overload def debug(self, boolean: None = None) -> bool: ... @overload