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
15 changes: 15 additions & 0 deletions .github/workflows/Test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@ jobs:
- name: Build wheel and sdist packages
run: python -m build --wheel --sdist --outdir dist

- name: OMPython version
id: ompython_version
shell: bash
run: |
V=$(python -c "
import OMPython
v = OMPython.__version__
assert v != 'unknown', 'Version resolution failed'
print(v)
")
echo "Resolved OMPython version: $V"
echo "version=$V" >> "$GITHUB_OUTPUT"
echo "### OMPython Version" >> "$GITHUB_STEP_SUMMARY"
echo "\`$V\`" >> "$GITHUB_STEP_SUMMARY"

- name: Check twine
run: python -m twine check dist/*

Expand Down
6 changes: 6 additions & 0 deletions OMPython/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
omc.sendExpression("getVersion()")
```


"""

from OMPython._version import __version__, get_version

from OMPython.model_execution import (
ModelExecutionConfig,
ModelExecutionRun,
Expand Down Expand Up @@ -77,6 +80,9 @@

# global names imported if import 'from OMPython import *' is used
__all__ = [
'__version__',
'get_version',

'doe_get_solutions',

'LinearizationResult',
Expand Down
51 changes: 51 additions & 0 deletions OMPython/_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""Version information for OMPython.

Resolves the installed package version via importlib.metadata when
OMPython is installed (pip install, editable install, etc.), and falls
back to reading pyproject.toml directly when running from a source
tree with no installed metadata available.
"""

import sys
from importlib.metadata import PackageNotFoundError, version
from pathlib import Path

if sys.version_info >= (3, 11):
import tomllib
else:
import tomli as tomllib

_FALLBACK_VERSION = "unknown"


def _read_version_from_pyproject() -> str:
"""Return the package version from the pyproject.toml file.

Raises:
FileNotFoundError: if pyproject.toml cannot be found.
KeyError: if the version is not statically defined (e.g. dynamic versioning is used).
"""
pyproject_path = Path(__file__).resolve().parents[1] / "pyproject.toml"
with open(pyproject_path, "rb") as pyproject_file:
pyproject = tomllib.load(pyproject_file)
return pyproject["project"]["version"]


def _resolve_version() -> str:
try:
return version(__package__ or "OMPython")
except PackageNotFoundError:
pass

try:
return _read_version_from_pyproject()
except (FileNotFoundError, KeyError):
return _FALLBACK_VERSION


def get_version() -> str:
"""Return the OMPython version string."""
return __version__


__version__ = _resolve_version()
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies = [
"psutil",
"pyparsing",
"pyzmq",
"tomli; python_version < '3.11'",
]

[tool.setuptools]
Expand Down
67 changes: 67 additions & 0 deletions tests/test_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Tests for OMPython._version."""

import importlib.metadata
from OMPython import _version


def test_version_module_resolves_installed_metadata():
"""When OMPython is installed, __version__ should come from
importlib.metadata and never fall back to 'unknown'."""
assert _version.__version__ != "unknown"
assert isinstance(_version.__version__, str)
assert _version.__version__ != ""


def test_get_version_matches_module_version():
"""get_version() should return the same value as __version__."""
assert _version.get_version() == _version.__version__


def test_installed_metadata_matches_importlib(monkeypatch=None):
"""Sanity check: the resolved version matches what importlib.metadata
reports directly, confirming the installed-metadata path is being used."""
expected = importlib.metadata.version(_version.__package__ or "OMPython")
assert _version.__version__ == expected


def test_resolve_version_falls_back_when_package_not_found(monkeypatch):
"""If importlib.metadata.version() raises PackageNotFoundError,
_resolve_version() should fall back to reading pyproject.toml."""

def raise_not_found(_name):
raise importlib.metadata.PackageNotFoundError

monkeypatch.setattr(_version, "version", raise_not_found)

result = _version._resolve_version()

# Falls back to reading pyproject.toml; should not silently return
# "unknown" unless pyproject.toml is genuinely missing/malformed.
assert result != "unknown"
assert isinstance(result, str)


def test_resolve_version_returns_unknown_if_pyproject_unreadable(monkeypatch):
"""If both importlib.metadata and the pyproject.toml fallback fail,
_resolve_version() should return 'unknown' rather than raising."""

def raise_not_found(_name):
raise importlib.metadata.PackageNotFoundError

def raise_file_not_found():
raise FileNotFoundError

monkeypatch.setattr(_version, "version", raise_not_found)
monkeypatch.setattr(_version, "_read_version_from_pyproject", raise_file_not_found)

result = _version._resolve_version()

assert result == "unknown"


def test_read_version_from_pyproject_returns_string():
"""_read_version_from_pyproject() should return a non-empty string
when pyproject.toml is present and well-formed."""
result = _version._read_version_from_pyproject()
assert isinstance(result, str)
assert result != ""
Loading