misc: fix all ty diagnostics

ty reported 20 diagnostics, and 0.0.89 adds a few more; this clears
them all without suppressions.

- The quest monster is held in a local before being stored on the
  quest book, so its name no longer reads from an Optional.
- PgUp/PgDn narrow the focused window with isinstance against a
  runtime-checkable PageScrollable protocol instead of hasattr.
- The ^t cheat used to monkeypatch SignalMixin.emit. SignalMixin now
  has a muted() context manager that emit() checks, and it restores
  emission even if a tick raises.
- GameView keeps its children as GameWindow, a protocol declaring
  stop() and sync(), so the cheat's resync type-checks.
- curses.ascii is imported explicitly where it is used.
- ProgressBarWindow is now Focusable itself, instead of calling
  Focusable.focus_standout() on a class that is not Focusable. Its
  four subclasses drop the duplicate Focusable base; the MRO and
  initialisation order are unchanged.
- MainMenu narrows the Optional pad before colouring the logo.
- The tests that record tasks assert player.task is set.
- Context managers are annotated as Generator rather than Iterator,
  which ty flags as deprecated for @contextmanager.
- The redundant cast() around getch() is gone.
- The frozen GameData test assigns through setattr(), since the
  direct assignment is an error by design.

Bug fixes:

- ListBox.select(None) crashed on `None < 0`; it now clears the
  selection, as DataTable.select(None) already does.
- ListBox.get() caught ValueError, which indexing never raises; it
  now catches IndexError, so an out-of-range index returns None as
  intended.
This commit is contained in:
Dash committed 2026-10-17 15:55:58 +02:00
1 parent 0c1d5185a4
commit 9155ef418b
14 files changed
+80 -51

No files matched your search

+19 -5
View File
@@ -1,10 +1,11 @@
import contextlib
import datetime
import functools
import itertools
import logging
import math
from collections import defaultdict
from collections.abc import Callable, Iterator, Sequence
from collections.abc import Callable, Generator, Iterator, Sequence
from dataclasses import dataclass
from typing import Any, cast
@@ -42,7 +43,21 @@ _SIGNALS: dict[tuple["SignalMixin", str], list[Callable[..., Any]]] = (
class SignalMixin:
_muted = 0
@staticmethod
@contextlib.contextmanager
def muted() -> Generator[None, None, None]:
"""Suppress all signal emission for the duration of the block."""
SignalMixin._muted += 1
try:
yield
finally:
SignalMixin._muted -= 1
def emit(self, signal_name: str, *user_data: Any) -> None:
if SignalMixin._muted:
return
for callback in _SIGNALS[self, signal_name]:
callback(*user_data)
@@ -683,12 +698,11 @@ class Simulation:
caption = ""
choice = random.below(5)
if choice == 0:
self.player.quest_book.monster = unnamed_monster(
monster = unnamed_monster(
self.data, self.player.level, iterations=3
)
caption = "Exterminate " + definite(
self.player.quest_book.monster.name, 2
)
self.player.quest_book.monster = monster
caption = "Exterminate " + definite(monster.name, 2)
elif choice == 1:
caption = "Seek " + definite(interesting_item(self.data), 1)
elif choice == 2: