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
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ The changelog format is based on [Keep a Changelog](https://keepachangelog.com/e
* -/-


## [0.0.5] - 2026-05-07

### Changed
* Changed the approach how dynamic versioning is realised
* Old:
* `src/pystclient/__about__.py` was single source of truth for version number.
* Version inside `pyproject.toml` was dynamically resolved via `hatch.version`.
* New:
* `pyproject.toml` is single source of truth for version number.
* `__version__` attribute inside `src/pystclient/__init__.py` gets dynamically resolved from project metadata
* NOTE: Project metadata (and hence the project version number) gets populated with data from `pyproject.toml` whenever the package is installed in the local environment, i.e. with every call to `uv sync`, `uv run`, or when a user installs the package via pip.
This means: As long as the package is _installed_ (even when installed in "just" editable mode) the dynamic resolution of the version number from `pyproject.toml` as single source of truth works just fine.
With that, the dynamic version is reliably resolved independent of whether or not the package is actually being _built_ (as in the former approach, via `hatch.version`). It is now sufficient that the package is _installed_ in the local environment. Only in the hypothetical case that one runs code from the package directly from source, without installing the package beforehand, the version resolution would fail. However, using code from a package without installing it has, latest since the advent of `uv`, become a very uncommon case.


## [0.0.4] - 2026-05-04

### Changed
Expand Down Expand Up @@ -197,7 +212,8 @@ This removes the need to manually add /src to the PythonPath environment variabl


<!-- Markdown link & img dfn's -->
[unreleased]: https://github.com/dnv-opensource/pystclient/compare/v0.0.4...HEAD
[unreleased]: https://github.com/dnv-opensource/pystclient/compare/v0.0.5...HEAD
[0.0.5]: https://github.com/dnv-opensource/pystclient/compare/v0.0.4...v0.0.5
[0.0.4]: https://github.com/dnv-opensource/pystclient/compare/v0.0.3...v0.0.4
[0.0.3]: https://github.com/dnv-opensource/pystclient/compare/v0.0.2...v0.0.3
[0.0.2]: https://github.com/dnv-opensource/pystclient/compare/v0.0.1...v0.0.2
Expand Down
42 changes: 21 additions & 21 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
title: pystclient
version: 0.0.4
version: 0.0.5
abstract: >-
Python client library for STC.
Python client library for STC.
type: software
authors:
- name: DNV AS
address: 'Veritasveien 1'
post-code: '1363'
city: Høvik
country: NO
website: 'https://www.dnv.com/'
- given-names: Hee Jong
family-names: Park
affiliation: DNV
email: hee.jong.park@dnv.com
website: 'https://www.linkedin.com/in/heejongpark/'
- given-names: Claas
family-names: Rostock
affiliation: DNV
email: claas.rostock@dnv.com
website: 'https://www.linkedin.com/in/claasrostock/?locale=en_US'
- name: DNV AS
address: 'Veritasveien 1'
post-code: '1363'
city: Høvik
country: NO
website: 'https://www.dnv.com/'
- given-names: Hee Jong
family-names: Park
affiliation: DNV
email: hee.jong.park@dnv.com
website: 'https://www.linkedin.com/in/heejongpark/'
- given-names: Claas
family-names: Rostock
affiliation: DNV
email: claas.rostock@dnv.com
website: 'https://www.linkedin.com/in/claasrostock/?locale=en_US'
keywords:
- STC
- Python
- Client
- STC
- Python
- Client
license: MIT
license-url: 'https://dnv-opensource.github.io/pystclient/LICENSE.html'
url: 'https://dnv-opensource.github.io/pystclient/README.html'
Expand Down
15 changes: 3 additions & 12 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,8 @@

sys.path.insert(0, str(Path("../../src").absolute()))

# Read version from src/pystclient/__about__.py
import importlib.util

_spec = importlib.util.spec_from_file_location(
"_about", Path(__file__).parent.parent.parent / "src" / "pystclient" / "__about__.py"
)
assert _spec
assert _spec.loader, "Could not load __about__.py"
_about = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_about)

# Read version from project metadata (i.e. from pyproject.toml)
from pystclient import __version__

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
Expand All @@ -36,7 +27,7 @@
author = "Hee Jong Park, Claas Rostock"

# The full version, including alpha/beta/rc tags
release = _about.__version__
release = __version__

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
5 changes: 1 addition & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "hatchling.build"

[project]
name = "pystclient"
dynamic = ["version"]
version = "0.0.5"
description = "Python client library for STC."
readme = "README.md"
requires-python = ">= 3.11"
Expand Down Expand Up @@ -67,9 +67,6 @@ packages = [
"src/pystclient",
]

[tool.hatch.version]
path = "src/pystclient/__about__.py"

[tool.pip-licenses]
format = "markdown"
order = "license"
Expand Down
11 changes: 0 additions & 11 deletions src/pystclient/__about__.py

This file was deleted.

28 changes: 27 additions & 1 deletion src/pystclient/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,38 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

"""pystclient package."""
"""pystclient - Python client library for STC."""

import warnings
from importlib import metadata

# Filter the internal authlib deprecation warning triggered by authlib's own imports
# (authlib._joserfc_helpers imports from authlib.jose which emits this warning)
from authlib.deprecate import AuthlibDeprecationWarning

warnings.filterwarnings("ignore", message="authlib.jose module is deprecated", category=AuthlibDeprecationWarning)


def _get_package_version() -> str:
"""Dynamically retrieve the version of `pystclient`.

NOTE: The single authoritative source for the version number of the package
is the `version` attribute in `pyproject.toml`.

The function retrieves this version number from the metadata of the (installed) package,
ensuring that the version number is consistent across the package and its documentation.

If the package is not installed (e.g. when running from source), fallback to "(version unknown)".

Returns:
The version of the package, or "(version unknown)" if the version cannot be determined.
"""
try:
version = metadata.version("pystclient")
except metadata.PackageNotFoundError:
# Fallback
version = "(version unknown)"
return version


__version__: str = _get_package_version()
13 changes: 2 additions & 11 deletions src/pystclient/cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,15 @@
import argparse
import logging
import pprint
from importlib import metadata
from pathlib import Path

from pystclient import __version__
from pystclient.api import run
from pystclient.utils.logging import configure_logging

logger = logging.getLogger(__name__)


def _get_version() -> str:
"""Return the installed package version, or a safe fallback if unavailable."""
try:
return metadata.version("pystclient")
except metadata.PackageNotFoundError:
# Fallback when package metadata is not available (e.g. running from source)
return "pystclient (version unknown)"


def _argparser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog="pystclient",
Expand Down Expand Up @@ -109,7 +100,7 @@ def _argparser() -> argparse.ArgumentParser:
"-V",
"--version",
action="version",
version=_get_version(),
version=__version__,
)

return parser
Expand Down
6 changes: 4 additions & 2 deletions tests/cli/test_pystclient_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@

import pytest

from pystclient import __version__
from pystclient.cli import __main__
from pystclient.cli.__main__ import _argparser, _get_version, main
from pystclient.cli.__main__ import _argparser, main

# *****Test commandline interface (CLI)************************************************************

Expand Down Expand Up @@ -93,12 +94,13 @@ def test_cli_version(
# Prepare
monkeypatch.setattr(sys, "argv", ["pystclient", flag])
parser = _argparser()
version_expected = __version__
# Execute & Assert
with pytest.raises(SystemExit) as exc_info:
_ = parser.parse_args()
assert exc_info.value.code == 0
captured = capsys.readouterr()
assert _get_version() in captured.out
assert version_expected in captured.out


# *****Ensure the CLI correctly configures logging*************************************************
Expand Down
Loading
Loading