misc: replace Any with precise types

Curses screens, windows and pads are typed as curses.window, and the
widgets that may get no parent window take curses.window | None.

- EventHandler is generic over a ParamSpec, so each handler declares
  the arguments it passes, and MenuView is generic over the item its
  on_confirm hands out. Choice callbacks take no arguments.
- Scrollable is generic over its items, which DataTable and ListBox
  fix to tuple[str, str] and str.
- random.choice() and choice_low() are generic over the sequence, so
  the casts at their call sites are gone. BasicUserInterface.menu()
  and util.first() are generic too.
- Signal callbacks and their payloads are Callable[..., object] and
  object, since emit() only forwards them.
- JSON values in game_data are object and narrowed by isinstance,
  and data files are Traversable.
- Signal handlers take an int and a FrameType | None, and
  list_players() takes a TextIO.
- The focus_standout() context managers return
  Generator[None, None, None].

Any remains in three places: Player.__setstate__, whose pickled
__dict__ holds values of every type; Focusable.__init__, a mixin that
passes *args and **kwargs through to the next class; and the values
load_game_data() collects, whose element type depends on the field
each one fills.
This commit is contained in:
Dash committed 2026-10-17 15:55:59 +02:00
1 parent 00794aca37
commit fd4a7d151d
34 files changed
+219 -153

No files matched your search

+8 -4
View File
@@ -6,7 +6,8 @@ import sys
import time
from collections.abc import Sequence
from datetime import datetime, timedelta
from typing import Any
from types import FrameType
from typing import TypeVar
from pqcli import lingo
from pqcli.config import PRIME_STATS
@@ -25,6 +26,9 @@ LOGO = r"""
"""
T = TypeVar("T")
class MainMenu(enum.IntEnum):
create = 1
play = 2
@@ -43,7 +47,7 @@ class BasicUserInterface(BaseUserInterface):
) -> None:
super().__init__(roster, player, args, data)
def signal_handler(sig: Any, frame: Any) -> None:
def signal_handler(sig: int, frame: FrameType | None) -> None:
logging.info("Quitting")
if self.args.use_saves:
self.roster.save()
@@ -217,9 +221,9 @@ class BasicUserInterface(BaseUserInterface):
def menu(
self,
options: Sequence[tuple[Any, str]],
options: Sequence[tuple[T, str]],
title: str | None = None,
) -> Any:
) -> T:
print()
if title:
print(f"{title}:")