-
Notifications
You must be signed in to change notification settings - Fork 192
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1519 from nf-core/feat-mulled
feat: add a modules mulled command
- Loading branch information
Showing
6 changed files
with
172 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
"""Generate the name of a BioContainers mulled image version 2.""" | ||
|
||
|
||
import logging | ||
import re | ||
from packaging.version import Version, InvalidVersion | ||
from typing import Iterable, Tuple, List | ||
|
||
import requests | ||
from galaxy.tool_util.deps.mulled.util import build_target, v2_image_name | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
class MulledImageNameGenerator: | ||
""" | ||
Define a service class for generating BioContainers version 2 mulled image names. | ||
Adapted from https://gist.github.com/natefoo/19cefeedd1942c30f9d88027a61b3f83. | ||
""" | ||
|
||
_split_pattern = re.compile(r"==?") | ||
|
||
@classmethod | ||
def parse_targets(cls, specifications: Iterable[str]) -> List[Tuple[str, str]]: | ||
""" | ||
Parse tool, version pairs from specification strings. | ||
Args: | ||
specifications: An iterable of strings that contain tools and their versions. | ||
""" | ||
result = [] | ||
for spec in specifications: | ||
try: | ||
tool, version = cls._split_pattern.split(spec, maxsplit=1) | ||
except ValueError: | ||
raise ValueError( | ||
f"The specification {spec} does not have the expected format <tool==version> or <tool=version>." | ||
) from None | ||
try: | ||
Version(version) | ||
except InvalidVersion: | ||
raise ValueError(f"{version} in {spec} is not a PEP440 compliant version specification.") from None | ||
result.append((tool.strip(), version.strip())) | ||
return result | ||
|
||
@classmethod | ||
def generate_image_name(cls, targets: Iterable[Tuple[str, str]], build_number: int = 0) -> str: | ||
""" | ||
Generate the name of a BioContainers mulled image version 2. | ||
Args: | ||
targets: One or more tool, version pairs of the multi-tool container image. | ||
build_number: The build number for this image. This is an incremental value that starts at zero. | ||
""" | ||
return v2_image_name([build_target(name, version) for name, version in targets], image_build=str(build_number)) | ||
|
||
@classmethod | ||
def image_exists(cls, image_name: str) -> bool: | ||
"""Check whether a given BioContainers image name exists via a call to the quay.io API.""" | ||
response = requests.get(f"https://quay.io/biocontainers/{image_name}/", allow_redirects=True) | ||
log.debug(response.text) | ||
return response.status_code == 200 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
click | ||
galaxy-tool-util | ||
GitPython | ||
jinja2 | ||
jsonschema>=3.0 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
"""Test the mulled BioContainers image name generation.""" | ||
|
||
import pytest | ||
|
||
from nf_core.modules import MulledImageNameGenerator | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"specs, expected", | ||
[ | ||
(["foo==0.1.2", "bar==1.1"], [("foo", "0.1.2"), ("bar", "1.1")]), | ||
(["foo=0.1.2", "bar=1.1"], [("foo", "0.1.2"), ("bar", "1.1")]), | ||
], | ||
) | ||
def test_target_parsing(specs, expected): | ||
"""Test that valid specifications are correctly parsed into tool, version pairs.""" | ||
assert MulledImageNameGenerator.parse_targets(specs) == expected | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"specs", | ||
[ | ||
["foo<0.1.2", "bar==1.1"], | ||
["foo=0.1.2", "bar>1.1"], | ||
], | ||
) | ||
def test_wrong_specification(specs): | ||
"""Test that unexpected version constraints fail.""" | ||
with pytest.raises(ValueError, match="expected format"): | ||
MulledImageNameGenerator.parse_targets(specs) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"specs", | ||
[ | ||
["foo==0a.1.2", "bar==1.1"], | ||
["foo==0.1.2", "bar==1.b1b"], | ||
], | ||
) | ||
def test_noncompliant_version(specs): | ||
"""Test that version string that do not comply with PEP440 fail.""" | ||
with pytest.raises(ValueError, match="PEP440"): | ||
MulledImageNameGenerator.parse_targets(specs) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"specs, expected", | ||
[ | ||
( | ||
[("chromap", "0.2.1"), ("samtools", "1.15")], | ||
"mulled-v2-1f09f39f20b1c4ee36581dc81cc323c70e661633:bd74d08a359024829a7aec1638a28607bbcd8a58-0", | ||
), | ||
( | ||
[("pysam", "0.16.0.1"), ("biopython", "1.78")], | ||
"mulled-v2-3a59640f3fe1ed11819984087d31d68600200c3f:185a25ca79923df85b58f42deb48f5ac4481e91f-0", | ||
), | ||
( | ||
[("samclip", "0.4.0"), ("samtools", "1.15")], | ||
"mulled-v2-d057255d4027721f3ab57f6a599a2ae81cb3cbe3:13051b049b6ae536d76031ba94a0b8e78e364815-0", | ||
), | ||
], | ||
) | ||
def test_generate_image_name(specs, expected): | ||
"""Test that a known image name is generated from given targets.""" | ||
assert MulledImageNameGenerator.generate_image_name(specs) == expected |