From 60e3d77489300529545f1ca3dd6d2e91f8b2dbc6 Mon Sep 17 00:00:00 2001 From: Asher Norland Date: Wed, 28 Jan 2026 20:38:08 -0800 Subject: [PATCH] Version Check --- synodic_client/__init__.py | 7 +++-- synodic_client/application/qt.py | 5 +--- synodic_client/client.py | 23 +++------------ tests/unit/test_client_version.py | 48 ------------------------------- tests/unit/test_install.py | 9 +++--- 5 files changed, 14 insertions(+), 78 deletions(-) diff --git a/synodic_client/__init__.py b/synodic_client/__init__.py index e38ae54..f080961 100644 --- a/synodic_client/__init__.py +++ b/synodic_client/__init__.py @@ -1,5 +1,7 @@ """The `synodic_client` package provides the core functionality for the Synodic Client application.""" +import importlib.metadata + from synodic_client.client import Client from synodic_client.schema import ( UpdateChannel, @@ -15,10 +17,9 @@ UpdateState, ) -# Version is generated at build time by pdm-backend, not committed to repo try: - from synodic_client._version import __version__ -except ImportError: + __version__ = importlib.metadata.version('synodic_client') +except importlib.metadata.PackageNotFoundError: __version__ = '0.0.0.dev0' __all__ = [ diff --git a/synodic_client/application/qt.py b/synodic_client/application/qt.py index 0a6b8d7..3e4f40e 100644 --- a/synodic_client/application/qt.py +++ b/synodic_client/application/qt.py @@ -2,7 +2,6 @@ import logging import sys -from typing import LiteralString from porringer.api import API, APIParameters from porringer.schema import ListPluginsParameters, LocalConfiguration @@ -14,8 +13,6 @@ from synodic_client.client import Client from synodic_client.updater import UpdateChannel, UpdateConfig -icon: LiteralString = 'icon.png' - def application() -> None: """Entrypoint""" @@ -47,7 +44,7 @@ def application() -> None: app.setAttribute(Qt.ApplicationAttribute.AA_CompressHighFrequencyEvents) _screen = Screen() - _tray = TrayScreen(app, client, icon, _screen.window) + _tray = TrayScreen(app, client, Client.icon, _screen.window) # sys.exit ensures proper cleanup and exit code propagation # Leading underscore indicates references kept alive intentionally until exec() returns diff --git a/synodic_client/client.py b/synodic_client/client.py index db88453..5848980 100644 --- a/synodic_client/client.py +++ b/synodic_client/client.py @@ -1,22 +1,18 @@ """The client type""" -from __future__ import annotations - import importlib.metadata import logging from collections.abc import Callable from contextlib import AbstractContextManager from importlib.resources import as_file, files from pathlib import Path -from typing import TYPE_CHECKING, LiteralString +from typing import LiteralString from packaging.version import Version +from porringer.api import API from synodic_client.updater import UpdateConfig, UpdateInfo, Updater -if TYPE_CHECKING: - from porringer.api import API - logger = logging.getLogger(__name__) @@ -24,31 +20,20 @@ class Client: """The client""" distribution: LiteralString = 'synodic_client' + icon: LiteralString = 'icon.png' _updater: Updater | None = None @property def version(self) -> Version: """Extracts the version from the installed client. - Priority: - 1. importlib.metadata - 2. _version.py - Returns: The version data """ try: return Version(importlib.metadata.version(self.distribution)) except importlib.metadata.PackageNotFoundError: - # Frozen executable or missing metadata - use bundled version from SCM - # Import lazily since _version.py is generated at build time and not committed - try: - from synodic_client._version import __version__ as bundled_version # noqa: PLC0415 - - return Version(bundled_version) - except ImportError: - # Development without build - no version file exists - return Version('0.0.0.dev0') + return Version('0.0.0.dev0') @property def package(self) -> str: diff --git a/tests/unit/test_client_version.py b/tests/unit/test_client_version.py index e76833b..aed2580 100644 --- a/tests/unit/test_client_version.py +++ b/tests/unit/test_client_version.py @@ -1,7 +1,6 @@ """Tests for Client.version property behavior.""" import importlib.metadata -import sys from unittest.mock import patch from packaging.version import Version @@ -22,53 +21,6 @@ def test_version_from_metadata() -> None: assert version == Version('1.2.3') - @staticmethod - def test_version_fallback_to_bundled() -> None: - """Verify fallback to _version.py when metadata unavailable.""" - client = Client() - - with ( - patch.object( - importlib.metadata, - 'version', - side_effect=importlib.metadata.PackageNotFoundError('synodic_client'), - ), - patch.dict('sys.modules', {'synodic_client._version': None}), - patch('synodic_client.client.Version') as mock_version, - ): - # Simulate _version module with __version__ - mock_version_module = type(sys)('synodic_client._version') - mock_version_module.__version__ = '2.0.0.dev5' - sys.modules['synodic_client._version'] = mock_version_module - mock_version.side_effect = Version - - version = client.version - - assert version == Version('2.0.0.dev5') - - @staticmethod - def test_version_fallback_to_dev_default() -> None: - """Verify fallback to 0.0.0.dev0 when both metadata and _version.py unavailable.""" - client = Client() - - # Remove _version from sys.modules if present to force ImportError - sys.modules.pop('synodic_client._version', None) - - with ( - patch.object( - importlib.metadata, - 'version', - side_effect=importlib.metadata.PackageNotFoundError('synodic_client'), - ), - patch.dict('sys.modules', {'synodic_client._version': None}), - ): - # Force ImportError by making the module None (import will fail) - del sys.modules['synodic_client._version'] - - version = client.version - - assert version == Version('0.0.0.dev0') - @staticmethod def test_version_is_version_object() -> None: """Verify version property returns a Version object.""" diff --git a/tests/unit/test_install.py b/tests/unit/test_install.py index ce5ec49..e845d34 100644 --- a/tests/unit/test_install.py +++ b/tests/unit/test_install.py @@ -5,7 +5,6 @@ from packaging.version import Version -from synodic_client.application.qt import icon from synodic_client.client import Client @@ -37,9 +36,11 @@ def test_entrypoints() -> None: assert entry.load() @staticmethod - def icon_exists() -> None: - """Verifies that the icon file used exists""" - assert Path(icon).exists() + def test_icon_exists() -> None: + """Verifies that the icon file used exists.""" + client = Client() + with client.resource(Client.icon) as icon_path: + assert icon_path.exists() @staticmethod def test_data() -> None: