Source code for version

"""Software version setting."""

# this is adapted from https://github.com/cta-observatory/ctapipe/blob/main/ctapipe/version.py
# which is adapted from https://github.com/astropy/astropy/blob/master/astropy/version.py
# see https://github.com/astropy/astropy/pull/10774 for a discussion on why this needed.

from packaging.version import InvalidVersion, Version

MAJOR_MINOR_PATCH = "major.minor.patch"
MAJOR_MINOR = "major.minor"

try:
    try:
        from ._dev_version import version
    except ImportError:
        from ._version import version
except Exception:  # pylint: disable=broad-except
    import warnings

    warnings.warn("Could not determine simtools version; this indicates a broken installation.")
    del warnings
    version = "0.0.0"  # pylint: disable=invalid-name

__version__ = version


[docs] def resolve_version_to_latest_patch(partial_version, available_versions): """ Resolve a partial version (major.minor) to the latest patch version. Given a partial version string (e.g., "6.0") and a list of available versions, finds the latest patch version that matches the major.minor pattern. Parameters ---------- partial_version : str Partial version string in format "major.minor" (e.g., "6.0", "5.2") available_versions : list of str List of available semantic versions (e.g., ["5.0.0", "5.0.1", "6.0.0", "6.0.2"]) Returns ------- str Latest patch version matching the partial version pattern Raises ------ ValueError If partial_version is not in major.minor format ValueError If no matching versions are found Examples -------- >>> versions = ["5.0.0", "5.0.1", "6.0.0", "6.0.2", "6.1.0"] >>> resolve_version_to_latest_patch("6.0", versions) '6.0.2' >>> resolve_version_to_latest_patch("5.0", versions) '5.0.1' >>> resolve_version_to_latest_patch("5.0.1", versions) '5.0.1' """ try: pv = Version(partial_version) except InvalidVersion as exc: raise ValueError(f"Invalid version string: {partial_version}") from exc if pv.release and len(pv.release) >= 3: return str(pv) if len(pv.release) != 2: raise ValueError(f"Partial version must be major.minor, got: {partial_version}") major, minor = pv.release candidates = [ v for v in available_versions if Version(v).major == major and Version(v).minor == minor ] if not candidates: raise ValueError( f"No versions found matching '{partial_version}.x' " f"in available versions: {sorted(available_versions)}" ) return str(max(map(Version, candidates)))
[docs] def semver_to_int(version_string): """ Convert a semantic version string to an integer. Parameters ---------- version_string : str Semantic version string (e.g., "6.0.2") Returns ------- int Integer representation of the version (e.g., 60002 for "6.0.2") """ try: v = Version(version_string) except InvalidVersion as exc: raise ValueError(f"Invalid version: {version_string}") from exc release = v.release + (0,) * (3 - len(v.release)) major, minor, patch = release[:3] return major * 10000 + minor * 100 + patch
[docs] def sort_versions(version_list, reverse=False): """ Sort a list of semantic version strings. Parameters ---------- version_list : list of str List of semantic version strings (e.g., ["5.0.0", "6.0.2", "5.1.0"]) reverse : bool, optional Sort in descending order if True (default False) Returns ------- list of str Sorted list of version strings. """ try: return [str(v) for v in sorted(map(Version, version_list), reverse=reverse)] except InvalidVersion as exc: raise ValueError(f"Invalid version in list: {version_list}") from exc
[docs] def version_kind(version_string): """ Determine the kind of version string. Parameters ---------- version_string : str The version string to analyze. Returns ------- str The kind of version string ("major.minor", "major.minor.patch", or "major"). """ try: ver = Version(version_string) except InvalidVersion as exc: raise ValueError(f"Invalid version string: {version_string}") from exc if ver.release and len(ver.release) >= 3: return MAJOR_MINOR_PATCH if len(ver.release) == 2: return MAJOR_MINOR return "major"
[docs] def compare_versions(version_string_1, version_string_2, level=MAJOR_MINOR_PATCH): """ Compare two versions at the given level: "major", "major.minor", "major.minor.patch". Parameters ---------- version_string_1 : str First version string to compare. version_string_2 : str Second version string to compare. level : str, optional Level of comparison: "major", "major.minor", or "major.minor.patch" Returns ------- int -1 if version_string_1 < version_string_2 0 if version_string_1 == version_string_2 1 if version_string_1 > version_string_2 """ ver1 = Version(version_string_1).release ver2 = Version(version_string_2).release if level == "major": ver1, ver2 = ver1[:1], ver2[:1] elif level == MAJOR_MINOR: ver1, ver2 = ver1[:2], ver2[:2] elif level != MAJOR_MINOR_PATCH: raise ValueError(f"Unknown level: {level}") return (ver1 > ver2) - (ver1 < ver2)