From e41bef7b00b2a55d8cba5a2860789d4a9f281b19 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Mon, 22 Jun 2026 17:00:34 +0900 Subject: [PATCH 1/4] fix: use list comprehension --- dzgui/api/mods.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/dzgui/api/mods.py b/dzgui/api/mods.py index 81b6d1c..4089859 100644 --- a/dzgui/api/mods.py +++ b/dzgui/api/mods.py @@ -49,6 +49,7 @@ def get_local_mods(workshop_path: Path) -> list[Path]: mods = [file for file in workshop_path.iterdir() if file.is_dir()] return mods + def is_mission(path: Path) -> bool: # TODO: parse integrity of other files parent = path.parent.name @@ -57,9 +58,10 @@ def is_mission(path: Path) -> bool: file = path / "init.c" return file.exists() + def tokenize(mod: Path) -> dict[str, Any] | None: file = mod.joinpath("meta.cpp") - delimiter=r"\s*=\s*" + delimiter = r"\s*=\s*" modmeta = {} try: with open(file, "r", encoding="utf-8") as f: @@ -76,6 +78,7 @@ def tokenize(mod: Path) -> dict[str, Any] | None: logger.critical(e) return None + def get_mod_size(path: Path) -> float: s = 0 for f in path.rglob("*"): @@ -123,20 +126,27 @@ def _hash(uid: str, use_custom: bool = False) -> str: return prefix + md5.hexdigest()[:8] -def remove_stale_signatures(config: Path, versions: Path) -> None: +def remove_stale_signatures( + config: Path, versions: Path, ids: list[int] | None = None +) -> None: if versions.is_file() is False: logger.warning("Creating new version signatures file") versions.touch() return + path = lookup(config, Preferences.DEFAULT) steam_path = Path(path) - ids = get_local_mod_ids(steam_path) + if ids is None: + local_ids = get_local_mod_ids(steam_path) + with open(versions, "r") as f: lines = f.readlines() - for line in lines: - uid = int(line.split(",")[0]) - if uid not in ids: - lines.remove(line) + + if ids is None: + lines = [line for line in lines if int(line.split(",")[0]) in local_ids] + else: + lines = [line for line in lines if int(line.split(",")[0]) not in ids] + with open(versions, "w") as f: for line in lines: f.write(line) From 4e7c831a5336bda5e533c26f642c61f969b36e41 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Mon, 22 Jun 2026 17:02:27 +0900 Subject: [PATCH 2/4] fix: pass mods and iters to callback --- dzgui/managers/mods.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/dzgui/managers/mods.py b/dzgui/managers/mods.py index 87e9994..d609378 100644 --- a/dzgui/managers/mods.py +++ b/dzgui/managers/mods.py @@ -118,8 +118,7 @@ class ModManager: self.thread_man.increment_dialog() time.sleep(API_RATE_LIMIT) - iters = [_iter for mod, _iter in mods] - func = StoredFunc(self._on_mods_unsubbed, iters) + func = StoredFunc(self._on_mods_unsubbed, mods) self.thread_man.set_cleanup_func(func) def unsub_atomic_mod(self, mod: str) -> None: @@ -146,18 +145,21 @@ class ModManager: pass time.sleep(API_RATE_LIMIT) - def _on_mods_unsubbed(self, iters: list[Gtk.TreeIter]) -> None: + def _on_mods_unsubbed(self, mod_iter: list[tuple[str, Gtk.TreeIter]]) -> None: + mods = [int(mod) for mod, _iter in mod_iter] + iters = [_iter for mod, _iter in mod_iter] if self.store is None: return for _iter in iters: self.store.remove(_iter) - remove_stale_signatures(self.prefs.paths.config, self.prefs.paths.version) + # TODO: process config path in called function + remove_stale_signatures(self.prefs.paths.config, self.prefs.paths.version, mods) model = self.treeview.get_model() if model is None: return - mods = len(model) + total_mods = len(model) msg = self.format_mod_statusbar() - self.emitter.emit("mods_updated", msg, mods) + self.emitter.emit("mods_updated", msg, total_mods) def uncolorize_mods(self) -> None: model = self.treeview.get_model() From 525dc24508b7e4dbd8ee7b3140ba990e43d63a6a Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Mon, 22 Jun 2026 17:02:39 +0900 Subject: [PATCH 3/4] fix: missing import --- dzgui/init/proc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dzgui/init/proc.py b/dzgui/init/proc.py index 42647e9..1c97f74 100644 --- a/dzgui/init/proc.py +++ b/dzgui/init/proc.py @@ -1,6 +1,7 @@ import psutil import subprocess import shutil +import logging from warnings import deprecated From 0653f064b26495812b1192b5e77e71465a38806f Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Mon, 22 Jun 2026 22:55:44 +0900 Subject: [PATCH 4/4] chore: add tests for mod signatures --- tests/fixtures/dzg.versions | 8 ++++++ tests/test_mod_signatures.py | 52 ++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 tests/fixtures/dzg.versions create mode 100644 tests/test_mod_signatures.py diff --git a/tests/fixtures/dzg.versions b/tests/fixtures/dzg.versions new file mode 100644 index 0000000..6ebdc35 --- /dev/null +++ b/tests/fixtures/dzg.versions @@ -0,0 +1,8 @@ +1559212036,1771519119 +1564026768,1770917948 +2545327648,1780174455 +2276010135,1756744083 +1654462998,1780501511 +3410710885,1752864732 +2918418331,1780413260 +3739934289,1780855136 diff --git a/tests/test_mod_signatures.py b/tests/test_mod_signatures.py new file mode 100644 index 0000000..8aa5dd6 --- /dev/null +++ b/tests/test_mod_signatures.py @@ -0,0 +1,52 @@ +import pytest +import shutil +import tempfile + +from pathlib import Path +from typing import TYPE_CHECKING + +import dzgui.api.mods +import dzgui.config.query + +from tests.fixtures import fixture_path + +if TYPE_CHECKING: + from dzgui.const.enums import Preferences + +pytestmark = pytest.mark.mods + +@pytest.fixture +def versions() -> str: + return fixture_path("dzg.versions") + +@pytest.fixture +def tmp() -> str: + with tempfile.NamedTemporaryFile(delete=False) as f: + tmp = f.name + return tmp + +def mock_local_ids(path: Path) -> list[int]: + return [3410710885, 3739934289] + +def mock_lookup(path: Path, prefs: "Preferences") -> str: + return "" + +def test_signatures(monkeypatch, tmp: str, versions: str) -> None: + ids = [1559212036, 1654462998] + shutil.copyfile(versions, tmp) + path = Path(tmp) + monkeypatch.setattr("dzgui.api.mods.lookup", mock_lookup) + dzgui.api.mods.remove_stale_signatures(path, path, ids) + with open(tmp, "r") as f: + lines = f.readlines() + assert ids not in lines + +def test_signatures_with_no_ids(monkeypatch, tmp: str, versions: str) -> None: + shutil.copyfile(versions, tmp) + path = Path(tmp) + monkeypatch.setattr("dzgui.api.mods.get_local_mod_ids", mock_local_ids) + monkeypatch.setattr("dzgui.api.mods.lookup", mock_lookup) + dzgui.api.mods.remove_stale_signatures(path, path) + with open(tmp, "r") as f: + lines = f.readlines() + assert lines == ["3410710885,1752864732\n", "3739934289,1780855136\n"]