From f092207c6113438a849aadc2bbf50f013179e93f Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 10 Nov 2026 04:37:51 +0900 Subject: [PATCH 1/9] chore: clear strict typehinting errors --- dzgui/managers/config.py | 2 +- dzgui/managers/connection.py | 8 ++++---- dzgui/managers/filter.py | 2 +- dzgui/managers/mods.py | 2 +- dzgui/managers/offline.py | 2 +- dzgui/managers/threading.py | 6 +++--- dzgui/managers/update.py | 4 ++-- dzgui/model/servers.py | 6 +++--- dzgui/views/components/filter_panel.py | 6 +++++- dzgui/views/dialogs/wizard.py | 9 +++++++-- dzgui/views/pages/options.py | 8 ++++---- dzgui/views/pages/preconnect.py | 2 +- dzgui/views/trees/tree_servers.py | 2 +- 13 files changed, 34 insertions(+), 25 deletions(-) diff --git a/dzgui/managers/config.py b/dzgui/managers/config.py index 7490b15..de5d12b 100644 --- a/dzgui/managers/config.py +++ b/dzgui/managers/config.py @@ -162,7 +162,7 @@ class ConfigManager: trace = traceback.format_exc() dialog = ExceptionDialog(self.controller, trace) dialog.show_all() - dialog.run() + dialog.run() # type: ignore[no-untyped-call] def save_res_and_quit(self, tv: "ServerTreeView", window: "OuterWindow") -> None: columns = tv.get_columns() diff --git a/dzgui/managers/connection.py b/dzgui/managers/connection.py index 89c35f0..80291fa 100644 --- a/dzgui/managers/connection.py +++ b/dzgui/managers/connection.py @@ -298,22 +298,22 @@ class ConnectionManager: def _present_modlist_dialog(self, mods: list[list[str]]) -> None: dialog = ServerModDialog(self.controller, mods) - dialog.run() + dialog.run() # type: ignore[no-untyped-call] def _present_details_dialog(self, details: Servers.Details) -> None: dialog = ServerDetailsDialog(self.controller, details) - dialog.run() + dialog.run() # type: ignore[no-untyped-call] def _workshop_timeout(self, msg: str) -> None: dialog = ExceptionDialog(self.controller, msg) dialog.show_all() - dialog.run() + dialog.run() # type: ignore[no-untyped-call] def _server_timeout(self) -> None: dialog = ExceptionDialog(self.controller, server_timeout) dialog.set_details_buffer(kb.DZG_006) dialog.show_all() - dialog.run() + dialog.run() # type: ignore[no-untyped-call] def get_debug_args(self) -> str: addr = f"{self.record.ip}:{self.record.gameport}" diff --git a/dzgui/managers/filter.py b/dzgui/managers/filter.py index 4151bc5..f3f175c 100644 --- a/dzgui/managers/filter.py +++ b/dzgui/managers/filter.py @@ -79,7 +79,7 @@ class FilterManager: """Deep copy of defaults""" return dict(self.default_filters) - def get_filters(self) -> dict: + def get_filters(self) -> dict[str, bool]: return self.enabled_filters def set_filter(self, label: str, state: bool) -> None: diff --git a/dzgui/managers/mods.py b/dzgui/managers/mods.py index 6a98e02..b94a1c5 100644 --- a/dzgui/managers/mods.py +++ b/dzgui/managers/mods.py @@ -221,7 +221,7 @@ class ModManager: total_size += mod[3] return total_mods, total_size - def _on_stale_mods_found(self, stale_mods: list) -> None: + def _on_stale_mods_found(self, stale_mods: list[int]) -> None: """Manipulates attached ListStore in the main event loop""" model = self.treeview.get_model() if model is None: diff --git a/dzgui/managers/offline.py b/dzgui/managers/offline.py index 645a682..d16acaa 100644 --- a/dzgui/managers/offline.py +++ b/dzgui/managers/offline.py @@ -52,7 +52,7 @@ class OfflineManager: is_valid = is_mission(folder) self.emitter.emit("custom_mission_loaded", str(folder), is_valid) - def find_custom_mods(self, callback: Callable) -> None: + def find_custom_mods(self, callback: Callable[[], None]) -> None: folder = self.open_folderpicker(dialogs.custom_mod_dialog) window = self.controller.get_window() window.set_sensitive(False) diff --git a/dzgui/managers/threading.py b/dzgui/managers/threading.py index c20f324..023f017 100644 --- a/dzgui/managers/threading.py +++ b/dzgui/managers/threading.py @@ -22,8 +22,8 @@ logger = logging.getLogger(APP_NAME) def call_on_thread( dialog_str: str, show_dialog: bool = True, show_cancel: bool = False -) -> Callable: - def decorator(func: Callable) -> Callable: +) -> Callable[..., Any]: + def decorator(func: Callable[..., Any]) -> Callable[..., Any]: @wraps(func) def wrapper(*args: Any, **kwargs: Any) -> None: self = args[0] @@ -42,7 +42,7 @@ def call_on_thread( class StoredFunc: - def __init__(self, func: Callable, *args: Any, **kwargs: Any) -> None: + def __init__(self, func: Callable[..., Any], *args: Any, **kwargs: Any) -> None: sig = inspect.signature(func) self.func = func self.bindings = sig.bind(*args, **kwargs) diff --git a/dzgui/managers/update.py b/dzgui/managers/update.py index ff64fb4..4bf201b 100644 --- a/dzgui/managers/update.py +++ b/dzgui/managers/update.py @@ -60,9 +60,9 @@ class UpdateManager: def _on_update_success(self) -> None: msg = dialogs.update_success dialog = QuitDialog(self.controller, msg) - dialog.run() + dialog.run() # type: ignore[no-untyped-call] def _on_update_failure(self, msg: str) -> None: dialog = ExceptionDialog(self.controller, msg) dialog.show_all() - dialog.run() + dialog.run() # type: ignore[no-untyped-call] diff --git a/dzgui/model/servers.py b/dzgui/model/servers.py index a1d3082..22fca92 100644 --- a/dzgui/model/servers.py +++ b/dzgui/model/servers.py @@ -432,7 +432,7 @@ class ServerModelManager: if show_dialog: dialog = ExceptionDialog(self.controller, dialogs.load_error_lan) dialog.show_all() - dialog.run() + dialog.run() # type: ignore[no-untyped-call] def _cleanup_on_failure(self, show_dialog: bool = True) -> None: # TODO: disable map, keyword, and filter widgets if model is None @@ -451,14 +451,14 @@ class ServerModelManager: dialog = ExceptionDialog(self.controller, server_timeout) dialog.set_details_buffer(kb.DZG_006) dialog.show_all() - dialog.run() + dialog.run() # type: ignore[no-untyped-call] def _push_data(self, data: list[Any]) -> None: self._get_proxy_man().push(data) self._sort_unique_maps(data) self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_success)) - def _sort_unique_maps(self, data: list) -> None: + def _sort_unique_maps(self, data: list[Any]) -> None: u_maps = set([row[1] for row in data]) self._set_new_maps(sorted(u_maps)) diff --git a/dzgui/views/components/filter_panel.py b/dzgui/views/components/filter_panel.py index 75c51e9..59c0e46 100644 --- a/dzgui/views/components/filter_panel.py +++ b/dzgui/views/components/filter_panel.py @@ -42,7 +42,10 @@ class ButtonGrid(Gtk.Grid): self.checks: list[Gtk.CheckButton] = [] flowbox = Gtk.FlowBox( - halign=Gtk.Align.CENTER, min_children_per_line=3, max_children_per_line=3, selection_mode=Gtk.SelectionMode.NONE + halign=Gtk.Align.CENTER, + min_children_per_line=3, + max_children_per_line=3, + selection_mode=Gtk.SelectionMode.NONE, ) for check in defaults.keys(): @@ -305,6 +308,7 @@ class FilterPanel(Gtk.Box): Gdk.KEY_0: 9, Gdk.KEY_minus: 10, Gdk.KEY_backslash: 11, + Gdk.KEY_apostrophe: 12, } if keyval not in mappings: return False diff --git a/dzgui/views/dialogs/wizard.py b/dzgui/views/dialogs/wizard.py index 5dbcdb4..9a44e09 100644 --- a/dzgui/views/dialogs/wizard.py +++ b/dzgui/views/dialogs/wizard.py @@ -14,7 +14,7 @@ from dzgui.const.constants import ( HERO_PATH, FLATPAK_ROOT_PATH, LEGACY_CONFIG_PATH, - TMP_PATH + TMP_PATH, ) from dzgui.const.boilerplate import config_boilerplate from dzgui.const.endpoints import STEAM_API_SETUP @@ -168,7 +168,12 @@ class NotificationFrame(Gtk.Frame): class APIValidationPage(EnumeratedWizardPage): def __init__( - self, enum: PageNum, heading: str, description: str, link: str, func: Callable + self, + enum: PageNum, + heading: str, + description: str, + link: str, + func: Callable[[str], None], ) -> None: super().__init__( enum=enum, diff --git a/dzgui/views/pages/options.py b/dzgui/views/pages/options.py index b5633ca..718c556 100644 --- a/dzgui/views/pages/options.py +++ b/dzgui/views/pages/options.py @@ -55,7 +55,7 @@ class SubmitField(Gtk.Box): ) -> None: super().__init__(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) - self.callback: Callable + self.callback: Callable[[], None] self.controller = controller self.context = context @@ -143,7 +143,7 @@ class SubmitField(Gtk.Box): return self.save_option() - def set_callback(self, callback: Callable) -> None: + def set_callback(self, callback: Callable[[], None]) -> None: self.callback = callback def save_option(self) -> None: @@ -210,7 +210,7 @@ class NameSubmitField(SubmitField): Preferences.NAME, private=False, ) - self.entry.set_width_chars(30) # type: ignore + self.entry.set_width_chars(30) self.set_callback(self.save_player_name) def save_player_name(self) -> None: @@ -439,7 +439,7 @@ class Options(ScrollableMixin, Gtk.ScrolledWindow): # type: ignore if prefs.paths.config.is_file() is False: dialog = ExceptionDialog(self.controller, strings.config_not_found) dialog.show_all() - dialog.run() + dialog.run() # type: ignore[no-untyped-call] raise OSError(f"Config file '{prefs.paths.config}' not found") config = query.get_config(prefs.paths.config) diff --git a/dzgui/views/pages/preconnect.py b/dzgui/views/pages/preconnect.py index b737ff0..983e760 100644 --- a/dzgui/views/pages/preconnect.py +++ b/dzgui/views/pages/preconnect.py @@ -231,7 +231,7 @@ class PreConnectionAssistant(Gtk.Box): args = self.controller.get_debug_args() d = DebugDialog(self.controller, args) d.show_all() - d.run() + d.run() # type: ignore[no-untyped-call] def _on_ok_clicked(self, button: Gtk.Button) -> None: self.controller.update_and_connect() diff --git a/dzgui/views/trees/tree_servers.py b/dzgui/views/trees/tree_servers.py index 3143c6d..284b9c6 100644 --- a/dzgui/views/trees/tree_servers.py +++ b/dzgui/views/trees/tree_servers.py @@ -406,7 +406,7 @@ class ServerTreeView(ContextMixin, TreeView): # type: ignore path = model.get_path(it) row_index = path.get_indices()[0] try: - start, end = self.get_visible_range() + start, end = self.get_visible_range() # type: ignore[no-untyped-call] except Exception: return if row_index >= start[0] <= end[0]: From da18b4113604429b8b62b4d8be02eabd86d493d0 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 10 Nov 2026 05:09:02 +0900 Subject: [PATCH 2/9] chore: drop Soup2 stubs --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7d97ce6..65a3d7f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -104,7 +104,7 @@ python-a2s = { path = "./dzgui/lib/a2s", editable = true } dayzquery = { path = "./dzgui/lib/dayzquery", editable = true } [tool.uv] -config-settings-package = { pygobject-stubs = { config = "Gtk3,Gdk3,Soup2" } } +config-settings-package = { pygobject-stubs = { config = "Gtk3,Gdk3" } } [tool.pytest.ini_options] markers = [ From 9f36569fd41c1c41dd68da9a9677ee5eb9295afe Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 10 Nov 2026 05:10:56 +0900 Subject: [PATCH 3/9] drop: LoggerAlertsButton --- dzgui/views/components/buttons.py | 22 ---------------------- dzgui/views/components/statusbar.py | 4 ---- 2 files changed, 26 deletions(-) diff --git a/dzgui/views/components/buttons.py b/dzgui/views/components/buttons.py index bb3d45d..13a8e91 100644 --- a/dzgui/views/components/buttons.py +++ b/dzgui/views/components/buttons.py @@ -252,28 +252,6 @@ class AddButton(IconTextButton): self.set_tooltip_text(connect_panel.add_tooltip) -class LoggerAlertsButton(IconTextButton): - def __init__(self, warnings: int, errors: int) -> None: - warnings_text = "" - errors_text = "" - separator = "" - if warnings > 0: - warnings_plural = pluralize("warnings", warnings) - warnings_text = f"{warnings} {warnings_plural}" - if errors > 0: - errors_plural = pluralize("errors", errors) - errors_text = f" {errors} {errors_plural}" - if warnings + errors > 1: - separator = "," - concat = warnings_text + separator + errors_text - super().__init__( - icon=WARNING, - label=f"Loaded with{concat}", - ) - self.set_halign(Gtk.Align.END) - self.set_hexpand(True) - self.set_tooltip_text(alert_button_tooltip) - class SpinnerButton(Gtk.Button): def __init__(self, label: str) -> None: diff --git a/dzgui/views/components/statusbar.py b/dzgui/views/components/statusbar.py index 7eb75a3..b9dc49b 100644 --- a/dzgui/views/components/statusbar.py +++ b/dzgui/views/components/statusbar.py @@ -2,7 +2,6 @@ from typing import Self, Union, TYPE_CHECKING from dzgui.const.enum import NotebookPage, ServerTab from dzgui.util.strings import esc_to_return, question_to_return -from dzgui.views.components.buttons import LoggerAlertsButton import gi @@ -47,9 +46,6 @@ class Statusbar(Gtk.Grid): self.emitter.connect("servers_loaded", self._on_servers_loaded) self.emitter.connect("mods_updated", self._on_mods_updated) - def _on_alerts_clicked(self, button: LoggerAlertsButton) -> None: - self.controller.populate_log() - def _on_mods_updated(self, emitter: "Emitter", msg: str, mods: int) -> None: self.set_by_context(NotebookPage.MODS, msg) From bfe9b9d147f41eed6e935dfc5b3ae708bc1b6796 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 10 Nov 2026 05:58:02 +0900 Subject: [PATCH 4/9] chore: clear typehinting errors --- dzgui/controllers/mc.py | 6 +++--- dzgui/managers/contextmenu.py | 2 +- dzgui/model/model_factory.py | 2 +- dzgui/util/dist.py | 4 ++-- dzgui/util/ip.py | 2 +- dzgui/views/components/buttons.py | 2 +- dzgui/views/dialogs/calc.py | 2 +- dzgui/views/trees/tree_servers.py | 3 ++- 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index 1a05955..db656ec 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -274,7 +274,7 @@ class Controller(GObject.GObject): except Exception as e: dialog = ExceptionDialog(self, str(e)) dialog.show_all() - dialog.run() + dialog.run() # type: ignore[no-untyped-call] def select_colorized(self) -> None: mod_man = self.mediator.modtreeview.get_mod_man() @@ -308,7 +308,7 @@ class Controller(GObject.GObject): except Exception as e: dialog = ExceptionDialog(self, str(e)) dialog.show_all() - dialog.run() + dialog.run() # type: ignore[no-untyped-call] def update_steam_api_key(self, text: str) -> None: self.config_man.update_steam_api_key(text) @@ -365,7 +365,7 @@ class Controller(GObject.GObject): filter_man = self.get_filter_man() return filter_man.get_map_store() - def get_enabled_filters(self) -> dict: + def get_enabled_filters(self) -> dict[str, bool]: filter_man = self.get_filter_man() return filter_man.get_filters() diff --git a/dzgui/managers/contextmenu.py b/dzgui/managers/contextmenu.py index 016ce7b..03e6350 100644 --- a/dzgui/managers/contextmenu.py +++ b/dzgui/managers/contextmenu.py @@ -44,7 +44,7 @@ class ContextMenuManager: # UNTHREADED case ContextMenu.ADD_NOTE: dialog = NoteDialog(self.controller) - dialog.run() + dialog.run() # type: ignore[no-untyped-call] case ContextMenu.COPY_SERVER_IP: self.copy_server_ip() case ContextMenu.COPY_SERVER_NAME: diff --git a/dzgui/model/model_factory.py b/dzgui/model/model_factory.py index 7dfffbf..a48c0d3 100644 --- a/dzgui/model/model_factory.py +++ b/dzgui/model/model_factory.py @@ -11,7 +11,7 @@ from gi.repository.Gtk import ListStore, TreeIter # noqa E402 from gi.repository import GObject # noqa E402 GTYPE_TO_PYTHON = { - GObject.type_from_name(GObject.type_name(ptype)): ptype + GObject.type_from_name(GObject.type_name(ptype)): ptype # type: ignore[no-untyped-call] for ptype in (int, float, str, bool, object) } diff --git a/dzgui/util/dist.py b/dzgui/util/dist.py index 46c2d44..20db696 100644 --- a/dzgui/util/dist.py +++ b/dzgui/util/dist.py @@ -59,7 +59,7 @@ class CalcDist: self, addr: str, enum: "ServerTab", - result_queue: "Queue", + result_queue: "Queue[tuple[str, Haversine | None, ServerTab]]", controller: "Controller", cache: dict[str, Haversine], ) -> None: @@ -72,7 +72,7 @@ class CalcDist: self.ip = self.addr dist = self.compare(self.ip) - self.result_queue.put([self.addr, dist, self.enum]) + self.result_queue.put((self.addr, dist, self.enum)) def compare(self, remote_ip: str) -> Haversine | None: prefs = self.controller.get_prefs() diff --git a/dzgui/util/ip.py b/dzgui/util/ip.py index d9a2c12..168e036 100644 --- a/dzgui/util/ip.py +++ b/dzgui/util/ip.py @@ -31,7 +31,7 @@ class ReservedIPError(Exception): pass -def ip2list(ip: str) -> list: +def ip2list(ip: str) -> list[int]: return [int(digit) for digit in ip.split(".")] diff --git a/dzgui/views/components/buttons.py b/dzgui/views/components/buttons.py index 13a8e91..ac480be 100644 --- a/dzgui/views/components/buttons.py +++ b/dzgui/views/components/buttons.py @@ -64,7 +64,7 @@ class IconButton(Gtk.Button): self.icon = Icon(icon, margin_start=margin_start, margin_end=margin_end) self.set_image(self.icon) self.set_image_position(position) - self.set_focus_on_click(False) + self.set_focus_on_click(False) # type: ignore[no-untyped-call] self.set_always_show_image(True) def swap_icon(self, icon: str) -> None: diff --git a/dzgui/views/dialogs/calc.py b/dzgui/views/dialogs/calc.py index 979cb0a..9b6267a 100644 --- a/dzgui/views/dialogs/calc.py +++ b/dzgui/views/dialogs/calc.py @@ -10,7 +10,7 @@ from dzgui.views.components.labels import BoldLabel from dzgui.views.components.box import VBox, HBox gi.require_version("Gtk", "3.0") -from gi.repository import Gtk, GLib, GObject # type: ignore # noqa E402 +from gi.repository import Gtk, GLib, GObject # noqa E402 DAY_START_TIME = time(hour=6, minute=0, second=0) DAY_END_TIME = time(hour=18, minute=0, second=0) diff --git a/dzgui/views/trees/tree_servers.py b/dzgui/views/trees/tree_servers.py index 284b9c6..6cfac6e 100644 --- a/dzgui/views/trees/tree_servers.py +++ b/dzgui/views/trees/tree_servers.py @@ -32,6 +32,7 @@ if TYPE_CHECKING: from dzgui.controllers.mc import Controller from dzgui.controllers.emitter import Emitter from dzgui.model.model_factory import FastInsertListStore + from dzgui.util.dist import Haversine QUEUE_CHECK_DELAY = 200 @@ -64,7 +65,7 @@ class ServerTreeView(ContextMixin, TreeView): # type: ignore self.queue_id: int self.handler_id: int - self.queue: Queue = Queue() + self.queue: Queue[tuple[str, "Haversine" | None, ServerTab]] = Queue() self.seen_cache: list[Record] = [] From 8fb3462f35bb84bfd8136b4e26991d8acb1404e8 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 10 Nov 2026 05:58:22 +0900 Subject: [PATCH 5/9] chore: add placeholder for row struct --- dzgui/model/proxy_model.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dzgui/model/proxy_model.py b/dzgui/model/proxy_model.py index c892110..c5ebc66 100644 --- a/dzgui/model/proxy_model.py +++ b/dzgui/model/proxy_model.py @@ -1,5 +1,6 @@ import re +from dataclasses import dataclass from typing import Any, TYPE_CHECKING, Union from dzgui.const.enum import FilterMode @@ -16,6 +17,22 @@ DAY_REG = r"([0][6-9]|[1][0-7])" NIGHT_REG = r"([0][0-5]|[1][8-9]|[2][0-3])" +@dataclass(slots=True, frozen=True) +class ServerRow: + name: str + mapname: str + view: str + time: str + players: int + max_players: int + queue: int + ip: str + qport: int + ping: str + provider: str + modded: bool + + class ProxyModelManager: """ Manages access to cached FastInsertListStore resources and From e03c6905c6715fa9d36e4d0007a4a047269e5256 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 10 Nov 2026 06:30:12 +0900 Subject: [PATCH 6/9] chore: clear typehinting errors --- dzgui/api/acf.py | 2 +- dzgui/api/mods.py | 6 +----- dzgui/config/xdg.py | 4 ++-- dzgui/util/flatpak.py | 8 +++++-- dzgui/views/dialogs/early_alert.py | 2 +- dzgui/views/dialogs/filepicker.py | 12 +++++------ dzgui/views/dialogs/uninstall.py | 8 +++---- dzgui/views/dialogs/wizard.py | 8 +++---- dzgui/views/pages/keys.py | 7 +++--- dzgui/views/pages/options.py | 5 +++-- dzgui/views/trees/tree_base.py | 34 ++++++++---------------------- 11 files changed, 41 insertions(+), 55 deletions(-) diff --git a/dzgui/api/acf.py b/dzgui/api/acf.py index ce243a4..ba36ce0 100644 --- a/dzgui/api/acf.py +++ b/dzgui/api/acf.py @@ -111,7 +111,7 @@ class WorkshopACF(ACF): def __init__(self, file: Path) -> None: super().__init__(file) - def unpack(self, d: dict, lines: list[Any] = []) -> str: + def unpack(self, d: dict[str, str], lines: list[Any] = []) -> str: t1 = "AppWorkshop" t2 = ("WorkshopItemsInstalled", "WorkshopItemDetails") for k, v in d.items(): diff --git a/dzgui/api/mods.py b/dzgui/api/mods.py index c6a076d..f8a9814 100644 --- a/dzgui/api/mods.py +++ b/dzgui/api/mods.py @@ -114,10 +114,6 @@ def get_delimited_mods(steam_path: Path) -> list[Any]: return parse_mods(mods) -def get_missing_mods(local: list, remote: list) -> list: - return [mod for mod in remote if mod not in local] - - def _hash(uid: str, use_custom: bool = False) -> str: md5 = hashlib.md5() md5.update(uid.encode("ascii")) @@ -152,7 +148,7 @@ def remove_stale_signatures( def find_stale_mods(config: Path) -> list[int]: - def push_record(rec: str) -> list: + def push_record(rec: str) -> list[int]: record = fqip_to_record(rec) if record is None: return [] diff --git a/dzgui/config/xdg.py b/dzgui/config/xdg.py index b72ea7b..532c73f 100644 --- a/dzgui/config/xdg.py +++ b/dzgui/config/xdg.py @@ -51,7 +51,7 @@ def is_writeable(path_str: str) -> bool: return True -def get_xdg_paths() -> dict: +def get_xdg_paths() -> dict[str, Path]: home = Path.home() xdg_paths = { "XDG_CONFIG_HOME": home / ".config", @@ -73,7 +73,7 @@ def get_xdg_paths() -> dict: return resolved_paths -def parse_filepaths(xdg: dict) -> Xdg: +def parse_filepaths(xdg: dict[str, Path]) -> Xdg: config = xdg["XDG_CONFIG_HOME"] state = xdg["XDG_STATE_HOME"] share = xdg["XDG_DATA_HOME"] diff --git a/dzgui/util/flatpak.py b/dzgui/util/flatpak.py index 7372fd6..d86663d 100644 --- a/dzgui/util/flatpak.py +++ b/dzgui/util/flatpak.py @@ -1,12 +1,16 @@ import logging import subprocess +from typing import TYPE_CHECKING from dzgui.const.constants import APP_NAME, FLATPAK_APPID, GTK_APP_ID, TMP_PATH logger = logging.getLogger(APP_NAME) +if TYPE_CHECKING: + from pathlib import Path -def apply_overrides(xdg: dict[str, str]) -> None: + +def apply_overrides(xdg: dict[str, "Path"]) -> None: try: # NOTE: D-Bus registration required for sandbox args = [ @@ -19,7 +23,7 @@ def apply_overrides(xdg: dict[str, str]) -> None: subprocess.run([*args], capture_output=True) paths: list[str] = [] - paths.extend([*xdg.values()]) + paths.extend([str(path) for path in xdg.values()]) paths.append(TMP_PATH) for path in paths: diff --git a/dzgui/views/dialogs/early_alert.py b/dzgui/views/dialogs/early_alert.py index b7032a0..ac4dfd4 100644 --- a/dzgui/views/dialogs/early_alert.py +++ b/dzgui/views/dialogs/early_alert.py @@ -46,7 +46,7 @@ class AbortDialog(ColorAwareApp, Gtk.MessageDialog): # type: ignore self.connect("response", self._on_response) - self.run() + self.run() # type: ignore[no-untyped-call] self.destroy() def _on_response(self, dialog: Self, response: Gtk.ResponseType) -> None: diff --git a/dzgui/views/dialogs/filepicker.py b/dzgui/views/dialogs/filepicker.py index 2048598..f72c70d 100644 --- a/dzgui/views/dialogs/filepicker.py +++ b/dzgui/views/dialogs/filepicker.py @@ -16,14 +16,14 @@ class FilePicker(Gtk.FileChooserDialog): transient_for=parent, resizable=True, ) - self.add_buttons("_Cancel", Gtk.ResponseType.CANCEL) - self.add_buttons("_Save", Gtk.ResponseType.OK) + self.add_buttons("_Cancel", Gtk.ResponseType.CANCEL) # type: ignore[no-untyped-call] + self.add_buttons("_Save", Gtk.ResponseType.OK) # type: ignore[no-untyped-call] self.set_default_response(Gtk.ResponseType.OK) self.set_current_name(picker.placeholder) def pick_file(self) -> Path | None: - res = self.run() + res = self.run() # type: ignore[no-untyped-call] if res in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT): self.destroy() return None @@ -43,12 +43,12 @@ class FolderPicker(Gtk.FileChooserDialog): parent=parent, resizable=True, ) - self.add_buttons("_Cancel", Gtk.ResponseType.CANCEL) - self.add_buttons("_OK", Gtk.ResponseType.OK) + self.add_buttons("_Cancel", Gtk.ResponseType.CANCEL) # type: ignore[no-untyped-call] + self.add_buttons("_OK", Gtk.ResponseType.OK) # type: ignore[no-untyped-call] self.set_default_response(Gtk.ResponseType.OK) def pick_folder(self) -> Path | None: - res = self.run() + res = self.run() # type: ignore[no-untyped-call] if res in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT): self.destroy() return None diff --git a/dzgui/views/dialogs/uninstall.py b/dzgui/views/dialogs/uninstall.py index 3e7d2e7..b27f1d6 100644 --- a/dzgui/views/dialogs/uninstall.py +++ b/dzgui/views/dialogs/uninstall.py @@ -22,7 +22,7 @@ from gi.repository import Gtk, GLib, Pango # noqa E402 class Assistant(Gtk.Assistant): - def __init__(self, is_deck: bool, paths: dict[str, str]): + def __init__(self, is_deck: bool, paths: dict[str, Path]): super().__init__() if is_deck: # NOTE: deemed to be "safe" dimensions that exclude taskbar size @@ -63,7 +63,7 @@ class Assistant(Gtk.Assistant): class Window(Gtk.Window): - def __init__(self, is_deck: bool, paths: dict[str, str]) -> None: + def __init__(self, is_deck: bool, paths: dict[str, Path]) -> None: super().__init__(title=APP_NAME, icon_name=APP_NAME) self.assistant = Assistant(is_deck, paths) @@ -121,7 +121,7 @@ class CheckboxWithPath(CheckboxWithLabel): class UninstallPage(ScrolledWizardPage): - def __init__(self, paths: dict[str, str], pyapp: str | None): + def __init__(self, paths: dict[str, Path], pyapp: str | None): super().__init__(heading=uninstall.pg1_heading, description=uninstall.pg1_blurb) self.pyapp = pyapp @@ -219,7 +219,7 @@ class UninstallPage(ScrolledWizardPage): class UninstallWizard(ColorAwareApp, Gtk.Application): # type: ignore - def __init__(self, is_deck: bool, paths: dict[str, str]) -> None: + def __init__(self, is_deck: bool, paths: dict[str, Path]) -> None: super().__init__() config = Path(paths["XDG_CONFIG_HOME"]) if not config.is_dir() or not config.joinpath("config.json").is_file(): diff --git a/dzgui/views/dialogs/wizard.py b/dzgui/views/dialogs/wizard.py index 9a44e09..c2f38af 100644 --- a/dzgui/views/dialogs/wizard.py +++ b/dzgui/views/dialogs/wizard.py @@ -426,7 +426,7 @@ class PreferencesPage(EnumeratedWizardPage): class FlatpakOverridePage(EnumeratedWizardPage): - def __init__(self, xdg_paths: dict[str, str]) -> None: + def __init__(self, xdg_paths: dict[str, Path]) -> None: super().__init__( enum=PageNum.FLATPAK, heading=wizard.heading_flatpak, @@ -476,7 +476,7 @@ class CompletionPage(EnumeratedWizardPage): class Assistant(Gtk.Assistant): - def __init__(self, is_deck: bool, XDG: "Xdg", xdg_paths: dict[str, str]): + def __init__(self, is_deck: bool, XDG: "Xdg", xdg_paths: dict[str, Path]): super().__init__() if is_deck: # NOTE: deemed to be "safe" dimensions that exclude taskbar size @@ -781,7 +781,7 @@ class SteamPathPage(EnumeratedWizardPage): class SetupWizard(ColorAwareApp, Gtk.Application): # type: ignore - def __init__(self, is_deck: bool, XDG: "Xdg", xdg_paths: dict[str, str]) -> None: + def __init__(self, is_deck: bool, XDG: "Xdg", xdg_paths: dict[str, Path]) -> None: super().__init__() GLib.set_prgname(APP_NAME) self.win = Window(is_deck, XDG, xdg_paths) @@ -792,7 +792,7 @@ class SetupWizard(ColorAwareApp, Gtk.Application): # type: ignore class Window(Gtk.Window): - def __init__(self, is_deck: bool, XDG: "Xdg", xdg_paths: dict[str, str]) -> None: + def __init__(self, is_deck: bool, XDG: "Xdg", xdg_paths: dict[str, Path]) -> None: super().__init__(title=APP_NAME, icon_name=APP_NAME) self.assistant = Assistant(is_deck, XDG, xdg_paths) diff --git a/dzgui/views/pages/keys.py b/dzgui/views/pages/keys.py index ea12476..1da56d3 100644 --- a/dzgui/views/pages/keys.py +++ b/dzgui/views/pages/keys.py @@ -13,6 +13,7 @@ if TYPE_CHECKING: from dzgui.controllers.mc import Controller +# TODO: refactor into autopopulated ListStores class Keybindings(ScrollableMixin, Gtk.ScrolledWindow): # type: ignore """ Notebook page holding a prearranged grid @@ -35,7 +36,7 @@ class Keybindings(ScrollableMixin, Gtk.ScrolledWindow): # type: ignore self.connect("key-press-event", self._on_keypress) - def build_keys(self, items: list) -> Gtk.Grid: + def build_keys(self, items: list[dict[str, str]]) -> Gtk.Grid: grid = Gtk.Grid(row_spacing=10, column_homogeneous=True) grid.set_halign(Gtk.Align.START) row, col = 1, 0 @@ -72,7 +73,7 @@ class Keybindings(ScrollableMixin, Gtk.ScrolledWindow): # type: ignore row += 1 return grid - def build_sidebar(self, categories: list) -> Gtk.Grid: + def build_sidebar(self, categories: list[str]) -> Gtk.Grid: row, col = 0, 0 w, h = 1, 1 sidebar = Gtk.Grid(row_homogeneous=True, orientation=Gtk.Orientation.VERTICAL) @@ -83,7 +84,7 @@ class Keybindings(ScrollableMixin, Gtk.ScrolledWindow): # type: ignore sidebar.attach(label, col, row, w, h) return sidebar - def build_grid(self, items: list) -> Gtk.Grid: + def build_grid(self, items: list[dict[str, str]]) -> Gtk.Grid: grid = Gtk.Grid( row_spacing=20, halign=Gtk.Align.CENTER, diff --git a/dzgui/views/pages/options.py b/dzgui/views/pages/options.py index 718c556..6269e89 100644 --- a/dzgui/views/pages/options.py +++ b/dzgui/views/pages/options.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Callable, TYPE_CHECKING +from typing import Any, Callable, TYPE_CHECKING from dzgui.api import pefile as PeFile from dzgui.api.steam import get_last_updated @@ -406,7 +406,8 @@ class Options(ScrollableMixin, Gtk.ScrolledWindow): # type: ignore def _on_link_button_clicked(self, button: Gtk.Button, url: str) -> None: open_links.open_link_by_url(url) - def _make_grid(self, rows: list) -> Gtk.Grid: + # TODO: use FlowBox + def _make_grid(self, rows: list[list[Any]]) -> Gtk.Grid: grid = Gtk.Grid( orientation=Gtk.Orientation.VERTICAL, column_spacing=10, diff --git a/dzgui/views/trees/tree_base.py b/dzgui/views/trees/tree_base.py index 5d7b6a2..0919b08 100644 --- a/dzgui/views/trees/tree_base.py +++ b/dzgui/views/trees/tree_base.py @@ -79,11 +79,6 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore index = path.get_indices()[0] return index - def get_selected_records(self) -> list: - sel = self.get_selection() - model, rows = sel.get_selected_rows() - return [model[row] for row in rows] - def _on_keypress(self, treeview: Gtk.TreeView, event: Gdk.EventKey) -> bool: from dzgui.views.trees.tree_servers import ServerTreeView @@ -145,9 +140,11 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore self.set_cursor(path) def get_value_at_index(self, index: int) -> Any: - (model, pathlist) = self.get_model_and_pathlist() + model, pathlist = self.get_model_and_pathlist() if len(pathlist) < 1: return "" + if model is None: + return "" path = pathlist[0] tree_iter = model.get_iter(path) value = model.get_value(tree_iter, index) @@ -161,20 +158,16 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore sel = self.get_selection() self._on_tree_selection_changed(sel) - def get_model_and_pathlist(self) -> tuple: + def get_model_and_pathlist( + self, + ) -> tuple[Gtk.TreeModel | None, list[Gtk.TreePath]]: select = self.get_selection() sels = select.get_selected_rows() - (model, pathlist) = sels + model: Gtk.TreeModel | None + pathlist: list[Gtk.TreePath] + model, pathlist = sels return (model, pathlist) - # @deprecated("Currently unused") - # def get_mpath(self) -> Optional[Gtk.TreePath]: - # (model, pathlist) = self.get_model_and_pathlist() - # if len(pathlist) < 1: - # return None - # path = pathlist[0] - # return path - def _on_row_activated( self, treeview: Gtk.TreeView, @@ -189,15 +182,6 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore return True return False - # @deprecated("unused") - # def get_selected_row(self) -> Optional[Gtk.TreeModelRow]: - # ind = self.get_selected_row_index() - # model = self.get_model() - # if model is None: - # return None - # row = model[ind] - # return row - def get_col_value_by_path_index(self, path: Gtk.TreePath, index: int) -> Any: model = self.get_model() if model is None: From 0c4026daf8bc0d3c542b484b2f63007450396fc7 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Tue, 10 Nov 2026 10:02:41 +0900 Subject: [PATCH 7/9] chore: clear typehinting errors --- dzgui/api/acf.py | 3 ++- dzgui/api/servers.py | 10 ++++++---- dzgui/controllers/mc.py | 6 +++--- dzgui/managers/filter.py | 5 ++--- dzgui/model/proxy_model.py | 10 +++------- dzgui/util/format.py | 3 ++- dzgui/views/components/buttons.py | 14 ++++---------- dzgui/views/components/connect_panel.py | 2 +- dzgui/views/components/entry.py | 9 ++++----- dzgui/views/components/filter_panel.py | 4 ++-- dzgui/views/dialogs/boot.py | 2 +- dzgui/views/dialogs/generic.py | 2 +- dzgui/views/mixins/context_mixin.py | 6 ++---- 13 files changed, 33 insertions(+), 43 deletions(-) diff --git a/dzgui/api/acf.py b/dzgui/api/acf.py index ba36ce0..4b1dc71 100644 --- a/dzgui/api/acf.py +++ b/dzgui/api/acf.py @@ -111,7 +111,8 @@ class WorkshopACF(ACF): def __init__(self, file: Path) -> None: super().__init__(file) - def unpack(self, d: dict[str, str], lines: list[Any] = []) -> str: + def unpack(self, d: dict[str, Any], lines: list[Any] = []) -> str: + self.indent: int t1 = "AppWorkshop" t2 = ("WorkshopItemsInstalled", "WorkshopItemDetails") for k, v in d.items(): diff --git a/dzgui/api/servers.py b/dzgui/api/servers.py index 8c331e4..6ac446b 100644 --- a/dzgui/api/servers.py +++ b/dzgui/api/servers.py @@ -111,7 +111,7 @@ def get_netmask() -> str: # TODO: rename -def test_ip(suffix: int, port: int, event: threading.Event) -> dict | None: +def test_ip(suffix: int, port: int, event: threading.Event) -> dict[str, Any] | None: if event.is_set(): return None netmask = get_netmask() @@ -139,7 +139,9 @@ def sanitize(name: str) -> str: return name -def parse_json(json: list) -> list: +def parse_json( + json: list[dict[str, Any]], +) -> list[tuple[str, str, str, str, int, int, int, str, int, int, str, bool]]: """ Server metadata is underspecified and server operators tend to insert random garbage in the headers. In case @@ -507,14 +509,14 @@ def record_to_fqip(record: Record) -> str: return f"{record.ip}:{record.gameport}:{record.qport}" -def response_to_fqip(res: dict) -> str: +def response_to_fqip(res: dict[str, Any]) -> str: ip = res["addr"].split(":")[0] gameport = res["gameport"] qport = res["addr"].split(":")[1] return f"{ip}:{gameport}:{qport}" -def response_to_record(res: dict) -> Record: +def response_to_record(res: dict[str, Any]) -> Record: ip = res["addr"].split(":")[0] gameport = res["gameport"] qport = res["addr"].split(":")[1] diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index db656ec..6074046 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -77,7 +77,7 @@ class AppNavigation: class Controller(GObject.GObject): def __init__(self) -> None: - self.dist_cache: dict[str, "Haversine"] = {} + self.dist_cache: dict[str, "Haversine" | None] = {} self.mediator = AppNavigation() self.prefs: UserPrefs @@ -355,10 +355,10 @@ class Controller(GObject.GObject): filter_man.set_filter(filt, state) self.mediator.filters.set_filters(filters) - def get_dist_cache(self) -> dict[str, "Haversine"]: + def get_dist_cache(self) -> dict[str, Union["Haversine", None]]: return self.dist_cache - def set_dist_cache(self, addr: str, haversine: "Haversine") -> None: + def set_dist_cache(self, addr: str, haversine: Union["Haversine", None]) -> None: self.dist_cache[addr] = haversine def get_map_store(self) -> Gtk.ListStore: diff --git a/dzgui/managers/filter.py b/dzgui/managers/filter.py index f3f175c..357318f 100644 --- a/dzgui/managers/filter.py +++ b/dzgui/managers/filter.py @@ -51,7 +51,6 @@ class FilterManager: self.active_map = (0, all_maps) self.prior_map = all_maps - self.filters: list self.enabled_filters = dict(self.default_filters) def get_tooltips(self) -> dict[str, str]: @@ -75,7 +74,7 @@ class FilterManager: def set_active_keyword(self, word: str) -> None: self.active_keyword = word - def get_default_filters(self) -> dict: + def get_default_filters(self) -> dict[str, bool]: """Deep copy of defaults""" return dict(self.default_filters) @@ -116,7 +115,7 @@ class FilterManager: def get_unique_maps(self) -> list[str]: return [row[0] for row in self.map_store if row[0] != "All maps"] - def get_all_filters(self) -> tuple: + def get_all_filters(self) -> tuple[str, ...]: map_name = self.get_active_map_name() enabled = self.get_filters() kw = self.get_active_keyword() diff --git a/dzgui/model/proxy_model.py b/dzgui/model/proxy_model.py index c5ebc66..023da66 100644 --- a/dzgui/model/proxy_model.py +++ b/dzgui/model/proxy_model.py @@ -47,7 +47,7 @@ class ProxyModelManager: def __init__(self, filter_man: "FilterManager") -> None: self.filter_cache: dict[ - tuple[str], + tuple[str, ...], list[tuple[str, str, str, str, int, int, int, str, int, int, str, bool]], ] = {} @@ -68,9 +68,6 @@ class ProxyModelManager: return False return True - def append_row(self, row: list) -> None: - self.proxy_model.append(row) - def append_row_to_control( self, row: tuple[str, str, str, str, int, int, int, str, int, int, str, bool] ) -> None: @@ -84,7 +81,6 @@ class ProxyModelManager: self.proxy_model[treeiter][4] = playercount.players self.proxy_model[treeiter][6] = playercount.queue - # TODO: use dataclass for record rows def append_row_to_history( self, history: tuple[str, str, str, str, int, int, int, str, int, int, str, bool], @@ -264,7 +260,7 @@ class ProxyModelManager: rows = [row for row in rows if row[11]] return rows - def filter_toggle_on(self, filters: tuple[str]) -> list: + def filter_toggle_on(self, filters: tuple[str, ...]) -> list: """Effectively applies all filters""" self.set_filtered(self.control_model) self.set_filtered(self.filter_map(filters)) @@ -275,7 +271,7 @@ class ProxyModelManager: self.set_filtered(self.filter_toggle_off(filters, f)) return self.filtered - def set_cache(self, filters: tuple[str], filtered_rows: list[tuple]) -> None: + def set_cache(self, filters: tuple[str, ...], filtered_rows: list[tuple]) -> None: self.filter_cache[filters] = filtered_rows def set_filtered(self, rows: list | None) -> None: diff --git a/dzgui/util/format.py b/dzgui/util/format.py index e7b4d07..203ab3f 100644 --- a/dzgui/util/format.py +++ b/dzgui/util/format.py @@ -1,4 +1,5 @@ import re +from typing import Any from dzgui.util.localize import number from dzgui.strings.generic import selectable_tree @@ -60,7 +61,7 @@ def format_server_mods(mods: int) -> str: return f"Found {mods:n} {plural}. {workshop}" -def format_player_count(model: Gtk.TreeModel | None, control: list) -> str: +def format_player_count(model: Gtk.TreeModel | None, control: list[Any]) -> str: players = 0 hits: int status: str diff --git a/dzgui/views/components/buttons.py b/dzgui/views/components/buttons.py index ac480be..cd150c7 100644 --- a/dzgui/views/components/buttons.py +++ b/dzgui/views/components/buttons.py @@ -1,10 +1,8 @@ from typing import Callable, Literal, Self, TYPE_CHECKING, Union from dzgui.util.clip import copy_clipboard -from dzgui.util.format import pluralize from dzgui.strings import buttons from dzgui.util.strings import ( - alert_button_tooltip, atomic_buttons, ) from dzgui.const.constants import ( @@ -14,7 +12,6 @@ from dzgui.const.constants import ( LIST_ADD, REFRESH_ICON, STEAM_ICON, - WARNING, WEB_BROWSER, ) from dzgui.strings import connect_panel @@ -101,15 +98,14 @@ class LargeIconTextButton(IconButton): class ClipboardButton(IconTextButton): - def __init__(self, controller: Union["Controller", None], func: Callable) -> None: + def __init__(self, func: Callable[[], str]) -> None: super().__init__(CLIPBOARD, atomic_buttons.copy) - self.controller = controller self.connect("clicked", self._on_button_clicked, func) # TODO: strings self.set_tooltip_text("Copy to clipboard") - def _on_button_clicked(self, button: Self, func: Callable) -> None: + def _on_button_clicked(self, button: Self, func: Callable[[], str]) -> None: def revert() -> Literal[False]: self.revert_icon() return False @@ -120,10 +116,9 @@ class ClipboardButton(IconTextButton): GLib.timeout_add(600, revert) -# TODO: determine when controller would be passed to this button or drop class CopyIpButton(ClipboardButton): - def __init__(self, controller: Union["Controller", None], func: Callable) -> None: - super().__init__(controller, func) + def __init__(self, func: Callable[[], str]) -> None: + super().__init__(func) # TODO: strings self.set_tooltip_text("Copy IP to clipboard") @@ -252,7 +247,6 @@ class AddButton(IconTextButton): self.set_tooltip_text(connect_panel.add_tooltip) - class SpinnerButton(Gtk.Button): def __init__(self, label: str) -> None: super().__init__() diff --git a/dzgui/views/components/connect_panel.py b/dzgui/views/components/connect_panel.py index 17d0a71..0f91f84 100644 --- a/dzgui/views/components/connect_panel.py +++ b/dzgui/views/components/connect_panel.py @@ -187,7 +187,7 @@ class FavPanel(Gtk.Frame): self.fav_button = SteamConnectButton() self.fav_button.connect("clicked", self._on_connect_clicked) - self.copy_button = CopyIpButton(self.controller, self.get_fav_ip) + self.copy_button = CopyIpButton(self.get_fav_ip) # TODO: strings self.unset_button = CloseButton("Unset") diff --git a/dzgui/views/components/entry.py b/dzgui/views/components/entry.py index e1b3e7e..408ead8 100644 --- a/dzgui/views/components/entry.py +++ b/dzgui/views/components/entry.py @@ -38,7 +38,7 @@ class ValidatedEntry(Gtk.Entry): def __init__( self, controller: "Controller", - func: Callable, + func: Callable[[str], bool], placeholder_text: str = "", tooltip_text: str = "", ) -> None: @@ -46,7 +46,6 @@ class ValidatedEntry(Gtk.Entry): hexpand=True, placeholder_text=placeholder_text, tooltip_text=tooltip_text ) - self.func: Callable self.set_validation_func(func) self.controller = controller @@ -72,7 +71,7 @@ class ValidatedEntry(Gtk.Entry): self.emit("string_validated", False) remove_class(self, self.classname) - def set_validation_func(self, func: Callable) -> None: + def set_validation_func(self, func: Callable[[str], bool]) -> None: self.func = func def insert_icon(self) -> None: @@ -141,7 +140,7 @@ class APIEntry(Gtk.Box): def __init__(self) -> None: super().__init__(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) - self.func: Callable | None = None + self.func: Callable[[str], None] | None = None # TODO: strings self.entry = Gtk.Entry( @@ -222,7 +221,7 @@ class APIEntry(Gtk.Box): res = self.func(text) return res - def set_validation_func(self, func: Callable | None) -> None: + def set_validation_func(self, func: Callable[[str], None] | None) -> None: self.func = func def disable_button(self) -> None: diff --git a/dzgui/views/components/filter_panel.py b/dzgui/views/components/filter_panel.py index 59c0e46..2fa69a5 100644 --- a/dzgui/views/components/filter_panel.py +++ b/dzgui/views/components/filter_panel.py @@ -30,7 +30,7 @@ class ButtonGrid(Gtk.Grid): def __init__( self, controller: "Controller", - defaults: dict[str, str], + defaults: dict[str, bool], tooltips: dict[str, str], ) -> None: super().__init__( @@ -96,7 +96,7 @@ class ButtonGrid(Gtk.Grid): logger.info(f"User toggled button '{label}' to {state}") self.emitter.emit("check_toggled", label, state) - def get_checkboxes(self) -> list: + def get_checkboxes(self) -> list[Gtk.CheckButton]: return self.checks diff --git a/dzgui/views/dialogs/boot.py b/dzgui/views/dialogs/boot.py index d4aa557..f3809a6 100644 --- a/dzgui/views/dialogs/boot.py +++ b/dzgui/views/dialogs/boot.py @@ -105,7 +105,7 @@ class BootDialog(ColorAwareApp, Gtk.Dialog): # type: ignore self.error_label = Gtk.Label(margin_start=15, margin_end=15) # TODO: abstract class - self.copy_button = ClipboardButton(None, lambda: self.error_label.get_text()) + self.copy_button = ClipboardButton(self.error_label.get_text) self.button_hbox = Gtk.Box( orientation=Gtk.Orientation.HORIZONTAL, halign=Gtk.Align.CENTER, spacing=10 ) diff --git a/dzgui/views/dialogs/generic.py b/dzgui/views/dialogs/generic.py index cff1e2a..08dc77b 100644 --- a/dzgui/views/dialogs/generic.py +++ b/dzgui/views/dialogs/generic.py @@ -187,7 +187,7 @@ class TextBufferDialog(GenericDialog): secondary=secondary, ) self.text = text - copy_button = ClipboardButton(controller, self.get_text) + copy_button = ClipboardButton(self.get_text) self.add_action_widget(copy_button, Gtk.ResponseType.NONE) self.add_button("OK", Gtk.ResponseType.OK) self.connect("response", self._on_response) diff --git a/dzgui/views/mixins/context_mixin.py b/dzgui/views/mixins/context_mixin.py index 5befa2c..2fd7ca1 100644 --- a/dzgui/views/mixins/context_mixin.py +++ b/dzgui/views/mixins/context_mixin.py @@ -15,9 +15,7 @@ logger = logging.getLogger(APP_NAME) class ContextMixin(TreeView): - def present_menu( - self, widget: Gtk.Widget, event: Gdk.Event - ) -> bool: + def present_menu(self, widget: Gtk.Widget, event: Gdk.Event) -> bool: if self.menu is None: return False @@ -26,7 +24,7 @@ class ContextMixin(TreeView): match event.type: case Gdk.EventType.BUTTON_PRESS: - if event.button != 3: + if event.button != Gdk.BUTTON_SECONDARY: # type: ignore[comparison-overlap] return False self._process_button_event(event) # type: ignore case Gdk.EventType.KEY_PRESS: From bb04854cd7311ecfd2e1382f00ee8affc68fcd8e Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Wed, 11 Nov 2026 03:17:29 +0900 Subject: [PATCH 8/9] chore: add keybinding to strings --- dzgui/util/strings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dzgui/util/strings.py b/dzgui/util/strings.py index 931ca88..21790a9 100644 --- a/dzgui/util/strings.py +++ b/dzgui/util/strings.py @@ -118,6 +118,7 @@ servers = { "0": "toggle filter 10", "Minus": "toggle filter 11", "Backslash": "toggle filter 12", + "Apostrophe": "toggle filter 13", } vim = { "j": "Move down a row/scroll up", From 8aa7328d8f3a30fb5312d8926526948acd94ac36 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Wed, 11 Nov 2026 03:18:40 +0900 Subject: [PATCH 9/9] chore: drop unused import --- dzgui/views/components/buttons.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dzgui/views/components/buttons.py b/dzgui/views/components/buttons.py index cd150c7..a913168 100644 --- a/dzgui/views/components/buttons.py +++ b/dzgui/views/components/buttons.py @@ -1,4 +1,4 @@ -from typing import Callable, Literal, Self, TYPE_CHECKING, Union +from typing import Callable, Literal, Self, TYPE_CHECKING from dzgui.util.clip import copy_clipboard from dzgui.strings import buttons