diff --git a/aiida_pseudo/cli/install.py b/aiida_pseudo/cli/install.py index 19c7afa..199a0c2 100644 --- a/aiida_pseudo/cli/install.py +++ b/aiida_pseudo/cli/install.py @@ -4,6 +4,7 @@ import pathlib import shutil import tempfile +import yaml import click import requests @@ -97,20 +98,37 @@ def download_sssp( filepath_archive: pathlib.Path, filepath_metadata: pathlib.Path, traceback: bool = False -) -> None: +) -> str: """Download the pseudopotential archive and metadata for an SSSP configuration to a path on disk. :param configuration: the SSSP configuration to download. :param filepath_archive: absolute filepath to write the pseudopotential archive to. :param filepath_metadata: absolute filepath to write the metadata file to. :param traceback: boolean, if true, print the traceback when an exception occurs. + :return: Latest patch version of the requested minor version """ from aiida_pseudo.groups.family import SsspFamily from .utils import attempt - url_sssp_base = 'https://legacy-archive.materialscloud.org/file/2018.0001/v4/' - url_archive = f"{url_sssp_base}/{SsspFamily.format_configuration_filename(configuration, 'tar.gz')}" - url_metadata = f"{url_sssp_base}/{SsspFamily.format_configuration_filename(configuration, 'json')}" + url_template = 'https://archive.materialscloud.org/record/file?filename={filename}&parent_id=19' + + # Download the dictionary mapping of the minor versions to the latest corresponding patch versions. Since patch + # releases of the SSSP only contain bug fixes, there is no reason to have the user install an outdated patch + # version. So, the latest patch version of the minor version that is specified by the user is always installed. + with attempt('downloading patch versions information... ', include_traceback=traceback): + response = requests.get(url_template.format(filename='versions.yaml')) + response.raise_for_status() + # The `version_mapping` is a dictionary that maps each minor version (key) to the latest patch version (value) + version_mapping = yaml.load(response.content, Loader=yaml.SafeLoader) + patch_version = version_mapping[configuration.version] + + echo.echo_info(f'Latest patch version found: {patch_version}') + + archive_filename = SsspFamily.format_configuration_filename(configuration, 'tar.gz', patch_version) + metadata_filename = SsspFamily.format_configuration_filename(configuration, 'json', patch_version) + + url_archive = url_template.format(filename=archive_filename) + url_metadata = url_template.format(filename=metadata_filename) with attempt('downloading selected pseudopotentials archive... ', include_traceback=traceback): response = requests.get(url_archive) @@ -126,6 +144,8 @@ def download_sssp( handle.write(response.content) handle.flush() + return patch_version + def download_pseudo_dojo( configuration: SsspConfiguration, @@ -185,7 +205,6 @@ def cmd_install_sssp(version, functional, protocol, download_only, traceback): configuration = SsspConfiguration(version, functional, protocol) label = SsspFamily.format_configuration_label(configuration) - description = f'SSSP v{version} {functional} {protocol} installed with aiida-pseudo v{__version__}' if configuration not in SsspFamily.valid_configurations: echo.echo_critical(f'{version} {functional} {protocol} is not a valid SSSP configuration') @@ -199,8 +218,9 @@ def cmd_install_sssp(version, functional, protocol, download_only, traceback): filepath_archive = dirpath / 'archive.tar.gz' filepath_metadata = dirpath / 'metadata.json' - download_sssp(configuration, filepath_archive, filepath_metadata, traceback) + patch_version = download_sssp(configuration, filepath_archive, filepath_metadata, traceback) + description = f'SSSP v{patch_version} {functional} {protocol} installed with aiida-pseudo v{__version__}' description += f'\nArchive pseudos md5: {md5_file(filepath_archive)}' description += f'\nPseudo metadata md5: {md5_file(filepath_metadata)}' diff --git a/aiida_pseudo/groups/family/sssp.py b/aiida_pseudo/groups/family/sssp.py index 5637453..1da0c0f 100644 --- a/aiida_pseudo/groups/family/sssp.py +++ b/aiida_pseudo/groups/family/sssp.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Subclass of ``PseudoPotentialFamily`` designed to represent an SSSP configuration.""" from collections import namedtuple -from typing import Sequence +from typing import Sequence, Optional from aiida_pseudo.data.pseudo import UpfData from ..mixins import RecommendedCutoffMixin @@ -50,15 +50,23 @@ def format_configuration_label(cls, configuration: SsspConfiguration) -> str: ) @classmethod - def format_configuration_filename(cls, configuration: SsspConfiguration, extension: str) -> str: + def format_configuration_filename( + cls, configuration: SsspConfiguration, extension: str, patch_version: Optional[str] = None + ) -> str: """Format the filename for a file of a particular SSSP configuration as it is available from MC Archive. :param configuration: the SSSP configuration. :param extension: the filename extension without the leading dot. + :param patch_version: patch version of the files which overrides the ``version`` specified in the + ``configuration``. This is necessary because we only let users specify the minor version, not install + configurations with a specific patch version. The filename on the archive however will contain the patch + version, so this needs to be substituted. :return: filename """ + version = configuration.version if patch_version is None else patch_version + return cls.filename_template.format( - version=configuration.version, functional=configuration.functional, protocol=configuration.protocol + version=version, functional=configuration.functional, protocol=configuration.protocol ) + f'.{extension}' def __init__(self, label=None, **kwargs): diff --git a/tests/cli/test_install.py b/tests/cli/test_install.py index e28cd13..b3e9630 100644 --- a/tests/cli/test_install.py +++ b/tests/cli/test_install.py @@ -182,9 +182,9 @@ def test_install_sssp(run_cli_command): family = QueryBuilder().append(SsspFamily).one()[0] assert family.get_cutoffs is not None - assert f'SSSP v1.1 PBE efficiency installed with aiida-pseudo v{__version__}' in family.description - assert 'Archive pseudos md5: 4803ce9fd1d84c777f87173cd4a2de33' in family.description - assert 'Pseudo metadata md5: 0d5d6c2c840383c7c4fc3a99b5dc3001' in family.description + assert f'PBE efficiency installed with aiida-pseudo v{__version__}' in family.description + assert 'Archive pseudos md5: ' in family.description + assert 'Pseudo metadata md5: ' in family.description result = run_cli_command(cmd_install_sssp, raises=SystemExit) assert 'is already installed' in result.output