Source code for mantidimaging.core.utility.version_check

# Copyright (C) 2022 ISIS Rutherford Appleton Laboratory UKRI
# SPDX - License - Identifier: GPL-3.0-or-later

import json
import os
import subprocess
from logging import getLogger
import requests
from typing import Optional
from packaging import version
import shutil

from mantidimaging import __version__

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: _conda_installed_version: Optional[str] _conda_installed_label: Optional[str] _conda_available_version: Optional[str] def __init__(self): self._version = __version__ self._conda_installed_version = None self._conda_installed_label = None self._conda_available_version = None self._conda_exe = self.find_conda_executable() # To test update warning message uncomment # self._use_test_values(False) def _retrieve_versions(self) -> None: self._retrieve_conda_installed_version() self._retrieve_conda_available_version() def _use_test_values(self, uptodate: bool = True) -> None: """Avoid fetching version info""" self._conda_installed_version = "1.0.0_1" self._conda_installed_label = "main" if uptodate: self._conda_available_version = "1.0.0_1" else: self._conda_available_version = "2.0.0_1"
[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"conda_installed_version {self.get_conda_installed_version()}") print(f"conda_installed_label {self.get_conda_installed_label()}") print(f"conda_available_version {self.get_conda_available_version()}")
[docs] def get_version(self) -> str: """Get built in version""" return self._version
[docs] def get_conda_installed_version(self) -> Optional[str]: """Get version number of installed package from conda""" if self._conda_installed_version is None: self._retrieve_conda_installed_version() return self._conda_installed_version
[docs] def get_conda_installed_label(self) -> Optional[str]: """Get with 'main' or 'unstable' from conda installed package""" if self._conda_installed_label is None: self._retrieve_conda_installed_version() return self._conda_installed_label
[docs] def get_conda_available_version(self) -> Optional[str]: """Get latest version number from conda""" if self._conda_available_version is None: self._retrieve_conda_available_version() return self._conda_available_version
[docs] def is_conda_uptodate(self) -> bool: """Check if up to date with lasted version in conda""" if (self.get_conda_installed_version() == "" or self.get_conda_available_version() == ""): # If unable to get conda versions then assume everything is good return True return _version_is_uptodate(_parse_version(self.get_conda_installed_version()), _parse_version(self.get_conda_available_version()))
[docs] def conda_update_message(self) -> tuple: suffix = self.get_conda_installed_label() msg = "Not running the latest Mantid Imaging" if suffix != "main": msg += f"-{suffix}" msg += f".\nFound version {self.get_conda_installed_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_conda_installed_version()}, " detailed += f"latest: {self.get_conda_available_version()}.\n" detailed += "To update your environment please copy and run the following command:\n" detailed += f"source {os.environ['CONDA_EXE'].rsplit('/',1)[0]}/activate {os.environ['CONDA_PREFIX']} && " detailed += f"{self._conda_exe} update -c mantid/label/{suffix} mantidimaging" return msg, detailed
def _retrieve_conda_installed_version(self) -> None: query_result = subprocess.check_output(f"{self._conda_exe} list mantidimaging", shell=True, env=os.environ).decode("utf-8").strip() local_packages = [line.split() for line in query_result.splitlines() if not line.startswith('#')] if not local_packages: LOG.info("Running a development build without a local Mantid Imaging package installation.") # no local installation, no point sending out API requests # just returns as "unstable" label self._conda_installed_version = "" self._conda_installed_label = "unstable" return local_package = local_packages[-1] self._conda_installed_version = local_package[1] self._conda_installed_label = local_package[3].rpartition("/")[2] 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.get_conda_installed_label() == "main": self._conda_available_version = remote_main_version else: self._conda_available_version = remote_unstable_version
versions = CheckVersion() def _parse_version(package_version_string: Optional[str]) -> version.Version: if package_version_string is None: raise ValueError normalised_version_string = package_version_string.replace("_", ".") return version.parse(normalised_version_string) def _version_is_uptodate(local: version.Version, remote: version.Version): return local >= remote