Source code for mantidimaging.core.utility.version_check

# Copyright (C) 2024 ISIS Rutherford Appleton Laboratory UKRI
# SPDX - License - Identifier: GPL-3.0-or-later
from __future__ import annotations

import json
import os
import sys
from logging import getLogger
import requests
from packaging.version import Version, parse
import shutil

try:
    from mantidimaging.versions import package_version, git_hash, package_type  # type: ignore
except ImportError:
    package_version = '0.0.0.dev1'
    git_hash = ''
    package_type = ''

LOG = getLogger(__name__)

# Import as
#   from mantidimaging.core.utility.version_check import versions
# and use accessors
#   versions.get_conda_installed_version()
# Actual version lookups will only be performed once.


[docs] class CheckVersion: _version: str _package_type: str _conda_available_version: str | None def __init__(self): self._version = package_version self._package_type = package_type self._conda_available_version = None def _retrieve_versions(self) -> None: self._retrieve_conda_available_version()
[docs] @staticmethod def find_conda_executable() -> str: if shutil.which("mamba"): return "mamba" if shutil.which("conda"): return "conda" raise FileNotFoundError
[docs] def show_versions(self) -> None: print(f"Mantid imaging {self.get_version()}") print(f"Install method {self._package_type}") if self._package_type == "conda": print(f"conda_available_version {self.get_conda_available_version()}") if git_hash: print(f"Git hash {git_hash}")
[docs] def get_version(self) -> str: """Get built in version""" return self._version
[docs] def is_prerelease(self) -> bool: return Version(self.get_version()).is_prerelease
[docs] def get_conda_available_version(self) -> str: """Get latest version number from conda""" if self._conda_available_version is None: self._retrieve_conda_available_version() assert self._conda_available_version is not None return self._conda_available_version
[docs] def needs_update(self) -> bool: if self._package_type == "conda" and not self.is_conda_uptodate(): return True return False
[docs] def is_conda_uptodate(self) -> bool: """Check if up to date with lasted version in conda""" if self.get_conda_available_version() == "": # If unable to get conda versions then assume everything is good return True return _version_is_uptodate(self.get_version(), self.get_conda_available_version())
[docs] def conda_update_message(self) -> tuple: conda_exe = self.find_conda_executable() suffix = "unstable" if self.is_prerelease() else "main" msg = "Not running the latest Mantid Imaging" if suffix != "main": msg += f"-{suffix}" msg += f".\nFound version {self.get_version()}, " msg += f"latest: {self.get_conda_available_version()}.\nPlease check the terminal for an update command!" detailed = f"Not running the latest Mantid Imaging {suffix}.\n" detailed += f"Found version {self.get_version()}, " detailed += f"latest: {self.get_conda_available_version()}.\n" detailed += "To update your environment please copy and run the following command:\n" if sys.platform == 'linux': detailed += f"{conda_exe} activate {os.environ['CONDA_PREFIX']} && " detailed += f"{conda_exe} update -c mantid/label/{suffix} mantidimaging" return msg, detailed
def _retrieve_conda_available_version(self) -> None: try: response = requests.get("https://api.anaconda.org/package/mantid/mantidimaging") remote_main_version = json.loads(response.content)["latest_version"] remote_unstable_version = json.loads(response.content)["versions"][-1] if len( json.loads(response.content)["versions"]) > 0 else '' except Exception: # if anything goes wrong, in the end we don't have the version LOG.info("Could not connect to Anaconda remote to retrieve the latest version") self._conda_available_version = "" return if self.is_prerelease(): self._conda_available_version = remote_unstable_version else: self._conda_available_version = remote_main_version
versions = CheckVersion() def _parse_version(package_version_string: str) -> Version: normalised_version_string = package_version_string.replace("_", ".post") return parse(normalised_version_string) def _version_is_uptodate(local: str, remote: str): return _parse_version(local) >= _parse_version(remote)