Compare commits

...
Author SHA1 Message Date
aclist 7a6f4a2bb9 feat: immutable decorator 2026-11-11 07:52:05 +09:00
aclist ba92d15085 drop: unused signal logic 2026-11-11 07:50:54 +09:00
aclist 65e04c2fc4 fix: multiple signals being stacked 2026-11-11 07:50:38 +09:00
aclist 0907f5a474 change: immutable dataclass 2026-11-11 07:50:12 +09:00
aclist bfa83c3f94 change: import sort order 2026-11-11 07:15:53 +09:00
aclist aef48e515b fix: failing test 2026-11-11 07:15:28 +09:00
aclist e6ebeaeb5e chore: immutable dataclass 2026-11-11 07:04:25 +09:00
aclist 88c740105a chore: drop unused dataclasses 2026-11-11 07:02:23 +09:00
aclist b98a6f95a6 drop: unused imports 2026-11-11 07:00:17 +09:00
aclist 87d76e83ba chore: update DEVELOPERS.md 2026-11-11 06:57:56 +09:00
aclist a5374d1f1a Merge pull request #526 from aclist/fix/legacy-version-file
Mirror to Codeberg / mirror-to-codeberg (push) Waiting to run
fix: legacy version file
2026-11-11 05:08:14 +09:00
aclist dcc4cb494b Merge branch 'dzgui7' into fix/legacy-version-file
Mirror to Codeberg / mirror-to-codeberg (push) Waiting to run
2026-11-11 05:07:35 +09:00
aclist ff1e150eb1 change: suppress logger message 2026-11-11 05:04:50 +09:00
aclist c7ef91f02e Merge pull request #539 from aclist/fix/remove-from-history
fix: restore missing route
2026-11-11 05:00:34 +09:00
aclist 95bc05eab5 Merge pull request #536 from aclist/change/server-row-dataclass
change: marshal server row data
2026-11-11 04:59:58 +09:00
aclist 52c126ff8c fix: restore missing route 2026-11-11 04:29:36 +09:00
aclist 3677b01fdc fix: exception handling 2026-11-09 22:25:13 +09:00
aclist 4f6223f90b fix: strip invalid values from versions file 2026-11-09 22:24:26 +09:00
aclist 441066a1a0 chore: update comments 2026-11-09 22:23:37 +09:00
aclist fa1ac8fa31 chore: update imports 2026-11-09 22:23:27 +09:00
33 changed files with 165 additions and 134 deletions

No files matched your search

+6 -5
View File
@@ -5,7 +5,7 @@
### Fetch submodules
git submodule update --recursive --init
### Install with dev dependencies
### Install into editable venv with dev dependencies
uv pip install -e '.[dev]'
This includes all dependencies for building, linting, testing, and checking in code.
@@ -16,7 +16,7 @@ docs: documentation tools
lint: code linting, fixing, and type checking
test: unit and integration tests
## Miscellaneous
## Build process
### Setting up precommit hooks
pre-commit install
@@ -25,6 +25,7 @@ pre-commit install
sphinx-build -M html source build -a
### Building standalone release binaries
1. Set up the build target: `rustup target add x86_64-unknown-linux-musl`
2. Run `python3 scripts/release.py`
3. Generate a release and tag against the resulting tarfile generated in `dist`
1. Install the applicable system package containing the 'musl-gcc' wrapper
2. Set up the build target: `rustup target add x86_64-unknown-linux-musl`
3. Run `python3 scripts/release.py`
4. Generate a release and tag against the resulting tarfile generated in `dist`
+6 -5
View File
@@ -2,9 +2,9 @@ import hashlib
import logging
import re
from concurrent.futures import wait
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import ThreadPoolExecutor, wait
from pathlib import Path
from typing import Any
from dzgui.api.steam import get_app_path
from dzgui.api.servers import get_rules, fqip_to_record
@@ -17,8 +17,7 @@ from dzgui.const.constants import (
from dzgui.config.query import lookup
from dzgui.const.enum import Preferences
from typing import Any
from dzgui.init.migrate import clean_legacy_versions_file
logger = logging.getLogger(APP_NAME)
@@ -116,10 +115,12 @@ 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")
logger.debug("Creating new version signatures file")
versions.touch()
return
clean_legacy_versions_file(versions)
path = lookup(config, Preferences.DEFAULT)
steam_path = Path(path)
if ids is None:
+2 -3
View File
@@ -6,7 +6,6 @@ from importlib import resources
from pathlib import Path
from typing import TYPE_CHECKING
from dzgui.const.constants import (
APP_NAME,
APP_NAME_LOWER,
@@ -18,8 +17,8 @@ from dzgui.config.query import lookup
from dzgui.config.userprefs import UserPrefs
from dzgui.config.xdg import get_xdg_paths, parse_filepaths
from dzgui.init.migrate import (
has_new_config,
copy_state_files,
has_new_config,
migrate_cols_file,
)
from dzgui.init.prereqs import has_flatpak_client, has_steam_client
@@ -107,7 +106,7 @@ def load_steam_icon() -> None:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk # noqa
from gi.repository import Gtk
try:
traversable = resources.files(APP_NAME_LOWER).joinpath(ICONS_PATH)
+2 -1
View File
@@ -6,7 +6,8 @@ if TYPE_CHECKING:
from dzgui.util.ip import Coords
# NOTE: mutable dataclass, 'use_miles' key changes on demand
# NOTE: mutable dataclass: 'use_miles' key changes on demand
# 'frozen' cannot be True
@dataclass(slots=True)
class UserPrefs:
is_steam_deck: bool
+1 -1
View File
@@ -12,7 +12,7 @@ from dzgui.const.constants import (
from dzgui.init.proc import is_sandboxed
@dataclass
@dataclass(slots=True, frozen=True)
class Xdg:
config: Path
columns: Path
+3 -8
View File
@@ -1,11 +1,11 @@
import gi
import logging
import threading
from typing import Any, TYPE_CHECKING, Union
import dzgui.util._json as JSON # noqa
from dzgui.config.userprefs import UserPrefs
from dzgui.const.constants import APP_NAME
from dzgui.const.enum import (
ButtonType,
ContextMenuItem,
@@ -14,9 +14,6 @@ from dzgui.const.enum import (
Preferences,
ServerTab,
)
from dzgui.config.userprefs import UserPrefs
from dzgui.const.constants import APP_NAME
from dzgui.controllers.emitter import Emitter
from dzgui.managers.config import ConfigManager
from dzgui.managers.connection import ConnectionManager
@@ -29,8 +26,6 @@ from dzgui.util.open_links import open_user_workshop, open_workshop_page
from dzgui.views.dialogs.filepicker import FilePicker
from dzgui.views.dialogs.generic import ExceptionDialog
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib, GObject
+22 -1
View File
@@ -1,12 +1,21 @@
import json
import logging
import re
import shutil
from pathlib import Path
from typing import Any
from dzgui.const.constants import LEGACY_CONFIG_PATH, LEGACY_COLS_PATH, LEGACY_IPS_PATH
from dzgui.const.constants import (
APP_NAME,
LEGACY_CONFIG_PATH,
LEGACY_COLS_PATH,
LEGACY_IPS_PATH,
)
from dzgui.config.convert import rc2json
from dzgui.util._json import read_json, write_json
logger = logging.getLogger(APP_NAME)
def migrate_legacy_conf(config: Path) -> Any:
old_conf = Path.home() / LEGACY_CONFIG_PATH
@@ -70,3 +79,15 @@ def copy_ipdb(ips_path: Path) -> None:
return
# TODO: ensure that month file is copied
shutil.copy(legacy, ips_path)
def clean_legacy_versions_file(versions: Path) -> None:
# NOTE: handling for #523
try:
pat = r"^(\d+),(\d+)$"
lines = versions.read_text().splitlines()
clean = [line for line in lines if re.match(pat, line)]
concat = "\n".join(clean)
versions.write_text(concat)
except Exception as e:
logger.warning(e)
+9
View File
@@ -46,6 +46,15 @@ class ConfigManager:
ips.append(record)
self.update_config(Preferences.IP_LIST, ips)
def remove_from_history_file(self, fqip: str) -> None:
try:
history = self.prefs.paths.history
ips = [line.rstrip() for line in history.read_text().splitlines()]
ips.remove(fqip)
history.write_text("\n".join(ips))
except Exception as e:
logger.critical(e)
def update_history_file(self, fqip: str) -> None:
try:
with open(self.prefs.paths.history, "r") as f:
+5 -1
View File
@@ -34,7 +34,7 @@ LAN_TIMEOUT = 0.5
API_TIMEOUT = 3
@dataclass
@dataclass(slots=True, frozen=True)
class NewPlayerCount:
treeiter: Gtk.TreeIter
players: int
@@ -281,6 +281,10 @@ class ServerModelManager:
def remove_from_history(self, record: Servers.Record) -> None:
proxy_man = self._get_proxy_man()
proxy_man.remove_row_from_control(record)
fqip = Servers.record_to_fqip(record)
config_man = self.controller.get_config_man()
config_man.remove_from_history_file(fqip)
self.update_history()
@call_on_thread(dialog.querying)
+9
View File
@@ -0,0 +1,9 @@
from dataclasses import dataclass
from typing import Callable
def immutable_dataclass(cls: type | None = None, **kwargs: bool) -> type | Callable[[type], type]:
kwargs["slots"] = True
kwargs["frozen"] = True
if cls is None:
return lambda c: dataclass(c, **kwargs)
return dataclass(cls, **kwargs)
+2 -3
View File
@@ -1,10 +1,10 @@
import a2s
from ipaddress import ip_address
import requests
import shutil
import subprocess
from dataclasses import dataclass
from ipaddress import ip_address
from typing import TYPE_CHECKING
from dzgui.api.servers import Record
@@ -12,12 +12,11 @@ from dzgui.config.ipdb import read_from_table
from dzgui.const.constants import REQUEST_TIMEOUT
from dzgui.const.endpoints import IP_ECHO
if TYPE_CHECKING:
from pathlib import Path
@dataclass
@dataclass(slots=True, frozen=True)
class Coords:
lat: float
lon: float
+3 -3
View File
@@ -1,9 +1,9 @@
from typing import Sequence
import gi
from typing import Sequence
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk # noqa
from gi.repository import Gtk
class GenericBox(Gtk.Box):
+5 -4
View File
@@ -1,10 +1,11 @@
from typing import Self
from dzgui.util import css
import gi
from typing import Self
from dzgui.util import css
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk # noqa
from gi.repository import Gtk
# TODO: subclass Gtk.Frame directly
+2 -3
View File
@@ -1,3 +1,4 @@
import gi
from typing import Self
from warnings import deprecated
@@ -8,10 +9,8 @@ from dzgui.strings import options
from dzgui.views.components.box import HBox
from dzgui.views.components.buttons import Icon
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk # noqa
from gi.repository import Gtk
@deprecated("Client choice is determined at setup time")
+1 -1
View File
@@ -1,7 +1,7 @@
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk # noqa
from gi.repository import Gtk
class NoOverlayScrolledWindow(Gtk.ScrolledWindow):
+5 -11
View File
@@ -1,13 +1,9 @@
import gi
import sys
from enum import Enum
from typing import Any, Literal, Self, TYPE_CHECKING
# import time
from enum import Enum
from dzgui.views.mixins.colorscheme import ColorAwareApp
# TODO: import dialog titles
from dzgui.api.mods import remove_stale_signatures as remove_stale
from dzgui.config.ipdb import get_ipdb
from dzgui.const.constants import HEX_GREEN, HEX_RED
@@ -20,12 +16,10 @@ from dzgui.util.format import format_exception
from dzgui.util.strings import dialog_header
from dzgui.util.symlink import rebuild_symlinks
from dzgui.views.components.buttons import ClipboardButton
import gi
from dzgui.views.mixins.colorscheme import ColorAwareApp
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gdk # noqa
from gi.repository import Gtk, GLib, Gdk
if TYPE_CHECKING:
from dzgui.config.xdg import Xdg
+1 -1
View File
@@ -15,7 +15,7 @@ from dzgui.views.dialogs.generic import GenericDialog
from dzgui.views.trees.tree_base import TreeView
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, Pango # noqa
from gi.repository import Gtk, Gdk, Pango
if TYPE_CHECKING:
from dzgui.api.servers import Details
+3 -3
View File
@@ -1,3 +1,5 @@
import gi
from typing import Any
from dzgui.const.constants import (
@@ -7,10 +9,8 @@ from dzgui.const.constants import (
GIO_SETTINGS_VAL,
)
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio # noqa
from gi.repository import Gtk, Gio
class ColorAwareApp:
+1 -1
View File
@@ -1,7 +1,7 @@
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk # noqa
from gi.repository import Gtk, Gdk
class HelpMenuMixin:
+3 -3
View File
@@ -1,10 +1,10 @@
import gi
from dzgui.const.enum import VAdjustment
from dzgui.const.constants import SCROLL_INCREMENT
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk # noqa
from gi.repository import Gtk, Gdk
class ScrollableMixin:
+2 -3
View File
@@ -1,3 +1,4 @@
import gi
from pathlib import Path
from typing import Self, TYPE_CHECKING
@@ -8,10 +9,8 @@ from dzgui.views.components.buttons import SteamWorkshopButton
from dzgui.views.components.scrollable import NoOverlayScrolledWindow
from dzgui.views.trees.tree_mods import ModTreeView
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk # noqa
from gi.repository import Gtk
if TYPE_CHECKING:
from dzgui.controllers.mc import Controller
+6 -6
View File
@@ -1,9 +1,10 @@
from __future__ import annotations
import gi
from enum import Enum
from typing import Self, TYPE_CHECKING, Union
from dzgui.util import css
from dzgui.const.icons import ICON_EDIT_DELETE, ICON_FOLDER, ICON_WARNING
from dzgui.const.constants import (
APPID_DAYZ,
APPID_DAYZ_EXP,
@@ -11,8 +12,10 @@ from dzgui.const.constants import (
APPNAME_DAYZ_EXP_HUMAN,
)
from dzgui.const.enum import ContextMenuGroup, NotebookPage
from dzgui.const.icons import ICON_EDIT_DELETE, ICON_FOLDER, ICON_WARNING
from dzgui.managers.offline import OfflineManager
from dzgui.strings import generic, offline
from dzgui.util import css
from dzgui.views.components.box import HBox, VBox
from dzgui.views.components.buttons import Icon, IconTextButton
from dzgui.views.components.eventbox import InfoEventBox
@@ -21,11 +24,8 @@ from dzgui.views.components.scrollable import NoOverlayScrolledWindow
from dzgui.views.components.misc import ErrorPopover
from dzgui.views.trees.tree_mods import OfflineModTreeView
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GObject # noqa
from gi.repository import Gtk, Gdk
if TYPE_CHECKING:
from dzgui.controllers.mc import Controller
+14 -17
View File
@@ -1,9 +1,10 @@
import gi
from pathlib import Path
from typing import Any, Callable, TYPE_CHECKING
from dzgui.api import pefile as PeFile
from dzgui.api.steam import get_last_updated
from dzgui.config import query
from dzgui.const.constants import (
APPID_DAYZ,
@@ -14,12 +15,11 @@ from dzgui.const.constants import (
FLATPAK_SANDBOX,
FLATPAK_STEAM_PATH,
)
from dzgui.const.icons import ICON_VIEW_CONCEAL, ICON_VIEW_REVEAL
from dzgui.const.endpoints import STEAM_API_SETUP
from dzgui.const.enum import Preferences, ServerTab
from dzgui.const.icons import ICON_VIEW_CONCEAL, ICON_VIEW_REVEAL
from dzgui.strings import options
from dzgui.util import strings, css, open_links
from dzgui.views.components.box import ShortHBox, VBox
from dzgui.views.components.eventbox import InfoEventBox
from dzgui.views.components.labels import LeftLabel
@@ -29,11 +29,8 @@ from dzgui.views.components.misc import ErrorPopover
from dzgui.views.dialogs.generic import ExceptionDialog
from dzgui.views.mixins.scrollable_mixin import ScrollableMixin
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk # noqa
from gi.repository import Gtk, Gdk
if TYPE_CHECKING:
from dzgui.controllers.mc import Controller
@@ -233,10 +230,19 @@ class ToggleField(Gtk.Box):
self.pack_start(self.radio1, expand=False, fill=False, padding=0)
self.pack_start(self.radio2, expand=False, fill=False, padding=0)
self.signal_id: int | None = None
def disconnect_signal(self) -> None:
if self.signal_id is not None:
self.radio1.disconnect(self.signal_id)
def set_suboption_active(self, state: bool) -> None:
# NOTE: defer connection of signal until after state is set
self.radio2.set_active(state)
self.radio1.connect("toggled", self._on_radio_toggled, self.context)
self.disconnect_signal()
self.signal_id = self.radio1.connect(
"toggled", self._on_radio_toggled, self.context
)
def _on_radio_toggled(self, button: Gtk.RadioButton, context: Preferences) -> None:
self.controller.toggle_config(context)
@@ -486,14 +492,5 @@ class Options(ScrollableMixin, Gtk.ScrolledWindow): # type: ignore
start_tab = self.controller.query_config(Preferences.START_TAB)
self.start_tab_combo.set_active(start_tab)
def _suppress_toggles(self, state: bool) -> None:
for toggle in [
self.fullscreen_toggle,
self.distance_toggle,
]:
self.controller.suppress_signal(
self, toggle.get_children()[0], "_on_radio_toggled", state
)
def grab_content_area(self) -> None:
self.grab_focus()
+3 -20
View File
@@ -1,11 +1,12 @@
from dataclasses import dataclass
import gi
from typing import Self, Sequence, TYPE_CHECKING
from dzgui.const.enum import NotebookPage
from dzgui.const.icons import (
ICON_ERROR,
ICON_WARNING,
)
from dzgui.const.enum import NotebookPage
from dzgui.util.css import add_class
from dzgui.util.keys import is_ctrl_mask
from dzgui.util.localize import number
@@ -15,33 +16,15 @@ from dzgui.views.dialogs.generic import DebugDialog
from dzgui.views.components.frame import HeadingFrame
from dzgui.views.trees.tree_server_mods import ServerModTreeView
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gdk, Gtk
if TYPE_CHECKING:
from dzgui.managers.connection import Prerequisites
from dzgui.controllers.mc import Controller
from dzgui.controllers.emitter import Emitter
@dataclass
class Warnings:
passworded: bool
dayz_running: bool
no_steam: bool
wrong_version: bool
@dataclass
class Errors:
no_space: bool
no_dayz_exp: bool
no_dayz: bool
class Placeholder(Gtk.Label):
def __init__(self, text: str) -> None:
super().__init__(
+2 -3
View File
@@ -1,3 +1,4 @@
import gi
import logging
from typing import Any, Optional, TYPE_CHECKING
@@ -6,10 +7,8 @@ from dzgui.const.constants import APP_NAME, SEPARATOR
from dzgui.util.keys import is_ctrl_mask, is_navkey
from dzgui.views.mixins.cursor_mixin import CursorMixin
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa
from gi.repository import Gtk, Gdk, GObject
logger = logging.getLogger(APP_NAME)
+1 -1
View File
@@ -10,7 +10,7 @@ from dzgui.views.trees.tree_base import TreeView
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa
from gi.repository import Gtk
logger = logging.getLogger(APP_NAME)
+3 -3
View File
@@ -1,4 +1,6 @@
import gi
import logging
from typing import Any, TYPE_CHECKING
from dzgui.const.constants import APP_NAME, HEX_RED
@@ -9,10 +11,8 @@ from dzgui.views.mixins.context_mixin import ContextMixin
from dzgui.views.mixins.mods_mixin import ModsMixin
from dzgui.views.trees.tree_base import TreeView
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa
from gi.repository import Gtk, Gdk
if TYPE_CHECKING:
+5 -5
View File
@@ -1,15 +1,15 @@
import gi
from typing import TYPE_CHECKING
from dzgui.const.enum import ContextMenuGroup
from dzgui.model.model_factory import ModelFactory
from dzgui.strings import server_mods
from dzgui.views.mixins.context_mixin import ContextMixin
from dzgui.views.trees.tree_base import TreeView
from typing import TYPE_CHECKING
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gdk, Pango # noqa
from gi.repository import Gtk, Pango
if TYPE_CHECKING:
from dzgui.controllers.mc import Controller
+4 -8
View File
@@ -1,8 +1,9 @@
import gi
import logging
import threading
from queue import Queue
from typing import Any, Self, Union
from typing import Any, Literal, Self, TYPE_CHECKING, Union
from warnings import deprecated
from dzgui.api.servers import ping, Record
@@ -14,17 +15,11 @@ from dzgui.util import strings
from dzgui.util.dist import CalcDist
from dzgui.util.keys import is_ctrl_mask
from dzgui.views.mixins.context_mixin import ContextMixin
from typing import Literal, TYPE_CHECKING
from dzgui.views.trees.tree_base import TreeView
import dzgui.util._json as JSON # noqa
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa
from gi.repository import Gtk, GLib, Gdk, GObject
logger = logging.getLogger(APP_NAME)
@@ -415,6 +410,7 @@ class ServerTreeView(ContextMixin, TreeView): # type: ignore
real_model = self.proxy_man.get_control()
from dataclasses import fields
from dzgui.model.proxy_model import ServerRow
key = fields(ServerRow)[col_index].name
value = getattr(real_model[row_index], key)
+5 -5
View File
@@ -1,13 +1,13 @@
import gi
from typing import TYPE_CHECKING, Union
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
if TYPE_CHECKING:
from dzgui.model.model_factory import FastInsertListStore
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk # noqa
class SimpleTree(Gtk.ScrolledWindow):
"""Simple scrollable 1-column tree"""
+2 -3
View File
@@ -1,13 +1,12 @@
import gi
import pytest
import subprocess
from dzgui.const.constants import GIO_SETTINGS_KEY
from dzgui.views.mixins.colorscheme import ColorAwareApp
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio, GLib # noqa
from gi.repository import Gtk, GLib
class DummyWidget(ColorAwareApp, Gtk.Button):
+25
View File
@@ -0,0 +1,25 @@
from typing import TYPE_CHECKING
from dzgui.init.migrate import clean_legacy_versions_file
if TYPE_CHECKING:
from pathlib import Path
def test_null_signature_stripping(tmp_path: "Path") -> None:
tmp = tmp_path.joinpath("dzg.versions")
lines = [
"1111,2222",
"3333,4444",
"5555,null",
"foo",
",4555",
"1111",
" ",
",,,",
"-1",
]
expect = ["1111,2222", "3333,4444"]
tmp.write_text("\n".join(lines))
clean_legacy_versions_file(tmp)
assert expect == tmp.read_text().splitlines()
+2 -2
View File
@@ -48,5 +48,5 @@ def test_signatures_with_no_ids(monkeypatch, tmp: str, versions: str) -> None:
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"]
lines = [line.rstrip() for line in f.readlines()]
assert lines == ["3410710885,1752864732", "3739934289,1780855136"]