Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions synodic_client/__init__.py
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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__ = [
Expand Down
5 changes: 1 addition & 4 deletions synodic_client/application/qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import logging
import sys
from typing import LiteralString

from porringer.api import API, APIParameters
from porringer.schema import ListPluginsParameters, LocalConfiguration
Expand All @@ -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"""
Expand Down Expand Up @@ -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
Expand Down
23 changes: 4 additions & 19 deletions synodic_client/client.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,39 @@
"""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__)


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:
Expand Down
48 changes: 0 additions & 48 deletions tests/unit/test_client_version.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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."""
Expand Down
9 changes: 5 additions & 4 deletions tests/unit/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from packaging.version import Version

from synodic_client.application.qt import icon
from synodic_client.client import Client


Expand Down Expand Up @@ -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:
Expand Down
Loading