chore: clear linting errors

This commit is contained in:
aclist 2026-02-23 19:39:35 +09:00
parent d6fd7b2494
commit fd9a23c6d6
16 changed files with 82 additions and 96 deletions

View File

@ -1,11 +1,8 @@
import logging
import requests
from pathlib import Path
from typing import Optional, TYPE_CHECKING
from dzgui.config.query import lookup
from dzgui.const.endpoints import BM_SERVERS
from dzgui.const.enum import Preferences
logger = logging.getLogger(__name__)

View File

@ -50,7 +50,7 @@ def get_local_mods(workshop_path: Path) -> list[Path]:
return mods
# TODO: TEST: mock bad meta files with fixtures and remove them
# TODO: TEST: mock bad meta files with fixtures and skip them
def parse_meta(file: Path) -> ModMeta:
mod = file / "meta.cpp"
if mod.exists() is False:
@ -67,7 +67,7 @@ def parse_meta(file: Path) -> ModMeta:
if tok == "protocol" or tok == "publishedid":
ntok = lex.get_token()
elif tok == "timestamp":
# some malformed .NET tick conversions result in numbers < 0
# NOTE: some malformed .NET tick conversions result in numbers < 0
ntok = lex.get_token()
if ntok == "-":
ntok += str(lex.get_token())
@ -99,7 +99,8 @@ def get_delimited_mods(steam_path: Path) -> list[Any]:
if meta is None:
continue
size = get_mod_size(mod)
clean.append([meta.name, symlink, mod_dir, size])
# NOTE: final col is cell renderer highlight toggle
clean.append([meta.name, symlink, mod_dir, size, False])
clean.sort(key=lambda row: row[0])
return clean
@ -147,6 +148,7 @@ def remove_stale_signatures(config: Path, versions: Path) -> None:
for line in lines:
f.write(line)
def find_stale_mods(config: Path) -> list[int]:
def push_record(rec: str) -> list:
add = rec.split(":")
@ -163,10 +165,7 @@ def find_stale_mods(config: Path) -> list[int]:
remote_mods = []
with ThreadPoolExecutor() as executor:
futures = [
executor.submit(push_record, record)
for record in records
]
futures = [executor.submit(push_record, record) for record in records]
wait(futures)
for future in futures:
res = future.result()

View File

@ -7,10 +7,9 @@ import requests
import socket
import subprocess
import threading
import typing # noqa
from dataclasses import dataclass
from typing import Union
from typing import Optional, Union
from dzgui.api.bm import map_id_to_record
from dzgui.const.constants import REQUEST_TIMEOUT
@ -461,7 +460,7 @@ def response_to_fq_ip(res: dict) -> str:
return f"{ip}:{gameport}:{qport}"
def query_id_or_ip(addr: str, key: str) -> None:
def query_id_or_ip(addr: str, key: str) -> Optional[dict]:
# NOTE: Battlemetrics
if addr.isdigit():
try:

View File

@ -3,7 +3,7 @@ from typing import Union, TYPE_CHECKING
import gi
gi.require_version("Gtk", "3.0")
from gi.repository.Gtk import ListStore
from gi.repository.Gtk import ListStore # noqa E402
from gi.repository import Gdk, GObject # noqa E402
if TYPE_CHECKING:
@ -98,16 +98,6 @@ class Emitter(GObject.GObject):
def check_toggled(self, label: str, state: bool) -> None:
pass
@GObject.Signal(
flags=GObject.SignalFlags.RUN_LAST,
arg_types=(
str,
bool,
),
)
def check_toggled(self, label: str, state: bool) -> None:
pass
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(object,))
def servers_loaded(self, tag: "ServerTab") -> None:
pass

View File

@ -6,7 +6,7 @@ import traceback
from functools import wraps
from pathlib import Path
from typing import Any, Callable, Optional, TYPE_CHECKING
from typing import Any, Callable, TYPE_CHECKING
from warnings import deprecated
import dzgui.api.pefile as PeFile
@ -49,7 +49,7 @@ from dzgui.util._json import read_json, write_json
from dzgui.util.diag import write_diagnostic
from dzgui.util.format import format_mods, format_player_count
from dzgui.util.localize import number
from dzgui.util.open_links import open_workshop_page, open_user_workshop
from dzgui.util.open_links import open_user_workshop
from dzgui.views.dialogs.filepicker import FilePicker
from dzgui.views.dialogs.generic import ExceptionDialog, WaitDialog
@ -161,8 +161,8 @@ class Controller(GObject.GObject):
def is_auto_install(self) -> bool:
return self.query_config(Preferences.INSTALL)
def unblock_signals(self) -> None:
self.block_signals(False)
# def unblock_signals(self) -> None:
# self.block_signals(False)
# @deprecated("Currently unused")
# def block_signals(self, state: bool = True) -> None:
@ -203,7 +203,7 @@ class Controller(GObject.GObject):
# self.config_man().toggle_config(Preferences.DEBUG)
self.toggle_config(Preferences.DEBUG)
def get_active_context(self) -> NotebookPage:
def get_active_context(self) -> Gtk.TreeView:
tv = self.get_active_treeview()
return tv.get_enum()
@ -311,13 +311,9 @@ class Controller(GObject.GObject):
# TODO: delegate to threadmanager
@call_on_thread(strings.dialog.modlist)
def load_mods(self) -> None:
model = ModelFactory().make_mod_store() # self.model_man.new_mod_store()
model = ModelFactory().make_mod_store()
path = self.query_config(Preferences.DEFAULT)
mods = get_delimited_mods(Path(path))
# NOTE: cell renderer highlight toggle
for mod in mods:
mod.append(False)
model.extend(mods)
self.cleanup_func = StoredFunc(self.load_mods_cleanup, model)
@ -394,7 +390,7 @@ class Controller(GObject.GObject):
remove_stale_signatures(self.prefs.paths.config, self.prefs.paths.version)
# TODO: strings
# TODO: delegate to LocalModManager
# TODO: delegate to LocalModManager or api/mods.py
@call_on_thread("deleting mod")
def delete_single_mod(self, tree_path: Gtk.TreePath) -> None:
config = self.prefs.paths.config
@ -584,7 +580,7 @@ class Controller(GObject.GObject):
def refresh_tree(self) -> None:
treeview = self.get_active_treeview()
treeview.set_loaded(False)
self.populate_model()
ServerModelManager(self, treeview).refresh()
def get_player_count(self) -> str:
treeview = self.get_active_treeview()
@ -619,7 +615,7 @@ class Controller(GObject.GObject):
addr = ip.split(":")
return fav, f"{addr[0]}:{addr[2]}"
def get_dist_cache(self) -> dict[str, "Haversine"]:
def get_dist_cache(self) -> dict[str, "Haversine", "ServerTab"]:
return self.dist_cache
def get_filters(self) -> list:

View File

@ -1,6 +1,6 @@
import gi
import logging
from typing import TYPE_CHECKING
from typing import Union, TYPE_CHECKING
from dzgui.const.enum import ContextMenu, Preferences
from dzgui.managers.connection import ConnectionManager
@ -10,6 +10,9 @@ from dzgui.util import strings
from dzgui.util.clip import copy_clipboard
from dzgui.util.open_links import open_workshop_page
from dzgui.views.trees.tree_servers import ServerTreeView
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib, GObject # noqa E402
@ -21,7 +24,11 @@ if TYPE_CHECKING:
class ContextMenuManager:
def __init__(self, treeview: Gtk.TreeView, controller: "Controller") -> None:
def __init__(
self,
treeview: Gtk.TreeView,
controller: "Controller",
) -> None:
self.controller = controller
self.treeview = treeview
self.thread_man = ThreadingManager(parent=controller)
@ -83,6 +90,8 @@ class ContextMenuManager:
pass
def copy_server_ip(self) -> None:
if not isinstance(self.treeview, ServerTreeView):
return
record = self.treeview.get_simplified_ip()
copy_clipboard(record)

View File

@ -18,7 +18,7 @@ logger = logging.getLogger(__name__)
def call_on_thread(dialog_str: str) -> Callable:
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(*args, **kwargs):
def wrapper(*args: Any, **kwargs: Any) -> Callable:
self = args[0]
stored = StoredFunc(func, *args, **kwargs)
if not hasattr(self, "thread_man"):

View File

@ -1,4 +1,3 @@
import datetime
import re
from typing import Optional, TYPE_CHECKING
@ -281,5 +280,5 @@ class FilteredModelManager:
self.filtered = None
self.filter_cache = {}
self.ping_cache = {}
if full:
self.control_model = None
# if full:
# self.control_model = None

View File

@ -1,5 +1,5 @@
from dataclasses import dataclass
from typing import Any
from typing import Any, Sequence, Union
from dzgui.const.enum import HELP_MENU_ROWS
from dzgui.util.redact import redact_log
@ -8,7 +8,7 @@ from dzgui.util.strings import delimiter
import gi
gi.require_version("Gtk", "3.0")
from gi.repository.Gtk import ListStore # noqa E402
from gi.repository.Gtk import ListStore, TreeIter # noqa E402
from gi.repository import GObject # noqa E402
GTYPE_TO_PYTHON = {
@ -53,27 +53,27 @@ class LogCols:
@dataclass(slots=True, frozen=True)
class ServerModCols:
name: str
uid: GObject.TYPE_INT64
uid: int # GObject.TYPE_INT64
installed: str
@dataclass(slots=True, frozen=True)
class MenuCols:
name: GObject.TYPE_STRING # str
hidden: GObject.TYPE_PYOBJECT
name: str
hidden: object # GObject.TYPE_PYOBJECT
class FastInsertListStore(ListStore):
def __init__(self, *args, **kwargs) -> None:
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
def _is_same_length(self, lists: list[list[Any]]) -> bool:
def _is_same_length(self, lists: Sequence[Any]) -> bool:
first_len = len(lists[0])
if not all(len(sublist) == first_len for sublist in lists):
return False
return True
def _is_type_homogeneous(self, lists: list[list[Any]]) -> bool:
def _is_type_homogeneous(self, lists: Sequence[Any]) -> bool:
transposed = zip(*lists)
for column in transposed:
@ -82,7 +82,7 @@ class FastInsertListStore(ListStore):
return False
return True
def extend(self, rows: list[list[Any]]) -> None:
def extend(self, rows: Sequence[Any]) -> None:
"""
Compared to calling append() directly, introduces negligible overhead,
but guarantees type and length equivalence prior to insertion
@ -103,7 +103,7 @@ class FastInsertListStore(ListStore):
for row in rows:
self.append(row)
def append(self, row) -> None:
def append(self, row: list[Any] | tuple[Any, ...] | None = ...) -> TreeIter:
"""
Optimized for speed, but makes no assurances about row homogeneity
and may segfault if types and length are not identical to ListStore.
@ -120,7 +120,7 @@ class ModelFactory:
def __init__(self) -> None:
pass
def new_model_from_logfile(self, path: str) -> None:
def new_model_from_logfile(self, path: str) -> FastInsertListStore:
store = self.make_log_store()
with open(path, "r") as f:
lines = [line.split(delimiter) for line in f.read().splitlines()]
@ -137,17 +137,12 @@ class ModelFactory:
return store
def make_map_store(self) -> FastInsertListStore:
return ListStore(str)
return FastInsertListStore(str)
def make_help_store(self) -> FastInsertListStore:
store = self.new_model_from_class(MenuCols)
rows = [[row.dict["label"], row] for row in HELP_MENU_ROWS]
# for row in rows:HELP_MENU_ROWS:
# print(type(row) is object)
store.extend(rows)
# for row in HELP_MENU_ROWS:
# label = row.dict["label"]
# store.append([label, row])
return store
def make_mod_store(self) -> FastInsertListStore:

View File

@ -42,7 +42,7 @@ class ServerModelManager:
self.emitter = controller.get_emitter()
self.first_iteration: bool
self.preserve_on_fail: False
self.preserve_on_fail = False
self.jobs = 1
# NOTE: store filter man for access inside thread
@ -80,6 +80,8 @@ class ServerModelManager:
def refresh(self) -> None:
self.preserve_on_fail = True
self.load()
# TODO: if refresh is active, callback to button decrement signal
# and do not mark refresh as sensitive
@call_on_thread(dialog.fetching)
def _dump_api(self) -> None:
@ -109,14 +111,14 @@ class ServerModelManager:
)
return
# NOTE: This step is allowed to fail, since this metadata is incidental
# NOTE: this step is allowed to fail, since this metadata is incidental
res = Servers.query_api(key, APPID_DAYZ_EXP, "")
if res.status == 200 and res.parsed is True:
j = res.json
servers += j["response"]["servers"]
parsed = Servers.parse_json(servers)
self._push_data(parsed, FilterMode.INITIAL)
self._push_data(parsed)
@call_on_thread(dialog.scanning)
def dump_lan(self, port: int, early_abort: bool) -> None:
@ -149,14 +151,16 @@ class ServerModelManager:
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure))
return
parsed = Servers.parse_json(servers)
self._push_data(parsed, FilterMode.INITIAL)
self._push_data(parsed)
@call_on_thread(dialog.fetching)
def _dump_ips(self, ips: list[str]) -> None:
# NOTE: block malformed records (TODO: add github issue no.)
# TODO: sanitize ip list at config time and drop this
# TODO: make test for this
ips = [ip for ip in ips if len(ip.split(":")) == 3 and ip.split(":")[2] != ""]
job = Servers.query_direct
servers = []
with ThreadPoolExecutor() as executor:
futures = [
executor.submit(
@ -166,9 +170,8 @@ class ServerModelManager:
)
for ip in ips
]
servers = []
for future in as_completed(futures):
res = future.result()
res = future.result(timeout=API_TIMEOUT)
self.thread_man.increment_dialog()
# NOTE: failing entries are culled
if res is None:
@ -181,7 +184,7 @@ class ServerModelManager:
return
parsed = Servers.parse_json(servers)
self._push_data(parsed, FilterMode.INITIAL)
self._push_data(parsed)
@call_on_thread(dialog.querying)
def add_by_id_or_ip(self, addr: str) -> None:
@ -199,8 +202,8 @@ class ServerModelManager:
config_man = self.controller.get_config_man()
config_man.add_saved_server(fqip)
# NOTE: tab was not instantiated yet
if model is None:
# NOTE: if tab was not instantiated yet
if raw_model is None:
return
raw_model.append(record[0])
@ -250,8 +253,9 @@ class ServerModelManager:
self.tv.set_model(proxy)
# TODO: if current tab != self.saved, add label
# TODO: adding a row may update available maps
self.emitter.emit("servers_loaded", self.enum)
# NOTE: adding a row may update available maps
# TODO: test this
self._update_maps()
def _update_maps(self) -> None:
@ -263,8 +267,8 @@ class ServerModelManager:
def _cleanup_on_success(self) -> None:
self.tv.set_model(self.to_insert)
# inserting a row serializes file on disk, updates control model for that tab, and updates model
# TODO: make sure control model len is N + 1
# inserting a row serializes file on disk, updates control model for that tab, and updates model
# NOTE: when inserting new rows, the entire control model is wiped and rebuilt, then proxy model is swapped in
# TODO: signals or other approach to deferring map
# model insertion after thread closes
@ -296,21 +300,21 @@ class ServerModelManager:
dialog = ExceptionDialog(self.controller, api_warn_msg)
dialog.run()
# TODO: break into initial dump and refilter modes, can drop filtermode kwarg
def _push_data(self, data: tuple, mode: Optional[FilterMode]) -> None:
def _push_data(self, data: list) -> None:
# if data is None:
# self.to_insert = None
# else:
# FIXME: filterman calls GTK methods in thread
# if mode == FilterMode.INITIAL:
manager = self._get_filter_man()
manager.wipe_cache()
manager.set_control(data)
manager.filter(FilterMode.INITIAL)
self.to_insert = manager.get_proxy_model()
if data is None:
self.to_insert = None
else:
# FIXME: filterman calls GTK methods in thread
if mode == FilterMode.INITIAL:
manager.set_control(data)
manager.filter(mode)
self.to_insert = manager.get_proxy_model()
u_maps = set([row[1] for row in data])
self._set_new_maps(sorted(u_maps))
u_maps = set([row[1] for row in data])
self._set_new_maps(sorted(u_maps))
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_success))

View File

@ -13,6 +13,7 @@ from gi.repository import Gtk # noqa E402
if TYPE_CHECKING:
from dzgui.const.enum import ServerTab
from dzgui.controllers.mc import Controller
from queue import Queue
logger = logging.getLogger(__name__)
@ -53,9 +54,9 @@ class CalcDist:
self.controller = controller
self.result_queue = result_queue
self.addr = addr
self.ip = self.addr #.split(":")[0]
self.ip = self.addr # .split(":")[0]
#def run(self) -> None:
# def run(self) -> None:
cache = self.controller.get_dist_cache()
if self.addr in cache:
logger.info(f"Address '{self.addr}' already in cache")

View File

@ -273,7 +273,6 @@ class Notebook(ScrollableMixin, Gtk.Notebook): # type: ignore
if widget is None:
return
# FIXME: deprecated
widget.grab_content_area()
def get_page(self) -> Gtk.Widget | None:

View File

@ -103,6 +103,7 @@ class RefreshButton(IconTextButton):
# FIXME: do this after threaded call fully finishes
# FIXME: other signals cause refresh button to become sensitive
# after model is loaded
# TODO: put in smm cleanup func, use signal
GLib.timeout_add_seconds(1, self.decrement)
self.controller.refresh_tree()

View File

@ -45,10 +45,6 @@ class RightPanel(Gtk.Box):
for widget in (self.refresh_button, self.filters_vbox):
widget.set_sensitive(state)
# FIXME: may wish to reload these in place to show new data
# if context in (ServerTab.RECENT, ServerTab.SAVED):
# self.refresh_button.set_sensitive(False)
# TODO: reference for ping pass
# def _on_ping_clicked(self, button: Gtk.Button) -> None:
# block_signals()

View File

@ -150,10 +150,11 @@ class Statusbar(Gtk.Grid):
def set_cache(self, string: str) -> None:
self.cache = string
def set_text(self, string: str, context: str) -> None:
def set_text(self, string: str, context: str) -> int:
meta = self.statusbar.get_context_id(context)
self.statusbar.push(meta, string)
self.set_cache(string)
return meta
def _help_row_changed(self, tree: "TreeView", sel: Gtk.TreeSelection) -> None:
row = tree.get_value_at_index(1)

View File

@ -55,8 +55,8 @@ class ContextMixin(TreeView):
self.context_menu.select_first(False)
def _process_dynamic_row(self, row: ContextMenu) -> None:
if row == ContextMenu.ADD_SERVER and self.is_in_favs():
def _process_dynamic_row(self, row: ContextMenu) -> Gtk.MenuItem:
if row == ContextMenu.ADD_SERVER and self.is_in_favs(): # type: ignore
row = ContextMenu.REMOVE_SERVER
item = Gtk.MenuItem(label=row.dict["label"])
@ -71,7 +71,7 @@ class ContextMixin(TreeView):
# if self.get_record_string() in notes_cache:
# item.set_label(strings.edit_note)
def _process_button_event(self, event: Gdk.EventButton) -> None:
def _process_button_event(self, event: Gdk.EventButton) -> bool:
try:
pathinfo = self.get_path_at_pos(int(event.x), int(event.y))
if pathinfo is None:
@ -89,7 +89,7 @@ class ContextMixin(TreeView):
return True
# FIXME: if selection is not multiple, change cursor
except AttributeError:
pass
return False
def _on_menu_click(self, widget: Gtk.MenuItem, enum: ContextMenu) -> None:
self.controller.menu_action(enum, self)