Restore resolution of Conda environments generated from non-lowercase package names

Fix https://github.com/galaxyproject/galaxy/issues/16435 .
This commit is contained in:
Nicola Soranzo
2023-07-27 13:23:32 +01:00
parent c6a56b95ca
commit dd811cf0cc
3 changed files with 124 additions and 21 deletions
+85 -10
View File
@@ -1,6 +1,8 @@
import os.path
import tempfile
import pytest
from galaxy.tool_util.deps import DependencyManager
from galaxy.tool_util.deps.conda_util import (
best_search_result,
@@ -9,10 +11,16 @@ from galaxy.tool_util.deps.conda_util import (
install_conda,
installed_conda_targets,
)
from galaxy.tool_util.deps.requirements import ToolRequirement
from galaxy.tool_util.deps.requirements import (
ToolRequirement,
ToolRequirements,
)
from galaxy.tool_util.deps.resolvers import NullDependency
from galaxy.tool_util.deps.resolvers.conda import (
CondaDependency,
CondaDependencyResolver,
DEFAULT_ENSURE_CHANNELS,
MergedCondaDependency,
)
from .util import external_dependency_management
@@ -27,27 +35,94 @@ def test_install_conda_build(tmp_path) -> None:
assert cc.conda_build_available
@external_dependency_management
def test_conda_resolution(tmp_path) -> None:
job_dir = os.path.join(tmp_path, "000")
dependency_manager = DependencyManager(tmp_path)
resolver = CondaDependencyResolver(
@pytest.fixture(scope="module")
def resolver(tmp_path_factory):
dependency_manager = DependencyManager(tmp_path_factory.mktemp("dependencies"))
return CondaDependencyResolver(
dependency_manager,
auto_init=True,
auto_install=True,
use_path_exec=False, # For the test ensure this is always a clean install
)
@external_dependency_management
def test_single_package_resolution(resolver: CondaDependencyResolver) -> None:
# Test that a read-only resolver returns a NullDependency
resolver.read_only = True
req = ToolRequirement(name="samtools", version=None, type="package")
dependency = resolver.resolve(req, job_directory=job_dir)
package_name = "eXpress"
req = ToolRequirement(name=package_name, version=None, type="package")
dependency = resolver.resolve(req)
assert isinstance(dependency, NullDependency)
assert dependency.shell_commands() is None
# Test that a (fake) environment generated from a non-lowercase package name
# is still accepted by the resolver
env_path = resolver.conda_context.env_path(f"__{package_name}@_uv_")
os.mkdir(env_path)
dependency = resolver.resolve(req)
assert isinstance(dependency, CondaDependency)
assert dependency.name == package_name
assert dependency.version is None
assert dependency.exact
assert dependency.environment_path == env_path
os.rmdir(env_path)
# Test that a non-read-only resolver creates a conda environment (with a
# lowercase package name) and returns a CondaDependency
resolver.read_only = False
req = ToolRequirement(name="samtools", version=None, type="package")
dependency = resolver.resolve(req, job_directory=job_dir)
dependency = resolver.resolve(req)
assert isinstance(dependency, CondaDependency)
assert dependency.name == package_name
assert dependency.version is None
assert dependency.exact
assert dependency.environment_path == resolver.conda_context.env_path(f"__{package_name.lower()}@_uv_")
assert dependency.shell_commands() is not None
@external_dependency_management
def test_multi_package_resolution(resolver: CondaDependencyResolver) -> None:
# Test that a read-only resolver returns an empty list
resolver.read_only = True
reqs = ToolRequirements(
[
ToolRequirement(name="samtools", version=None, type="package"),
ToolRequirement(name="eXpress", version=None, type="package"),
]
)
dependency_list = resolver.resolve_all(reqs)
assert dependency_list == []
# Test that a (fake) mulled environment generated from non-lowercase package
# names is still accepted by the resolver
env_path = resolver.conda_context.env_path(
"mulled-v1-37955d8b3667efa38f1fe42bc37b4c9a03e67a90f0055d1db9d388b2f98fe3a1"
)
os.mkdir(env_path)
dependency_list = resolver.resolve_all(reqs)
assert len(dependency_list) == 2
for dependency in dependency_list:
assert isinstance(dependency, MergedCondaDependency)
assert dependency.version is None
assert dependency.exact
assert dependency.environment_path == env_path
os.rmdir(env_path)
# Test that a non-read-only resolver creates a mulled conda environment
# (with a hash from lowercase package names) and returns a list of
# MergedCondaDependency
resolver.read_only = False
dependency_list = resolver.resolve_all(reqs)
assert len(dependency_list) == 2
for dependency in dependency_list:
assert isinstance(dependency, MergedCondaDependency)
assert dependency.version is None
assert dependency.exact
assert dependency.environment_path == resolver.conda_context.env_path(
"mulled-v1-f36491d362c22cdb24f7de3e1ff978a5ee02cadc8c12a12ae06bce57bbf0765c"
)
@external_dependency_management
def test_against_conda_prefix_regression() -> None:
"""Test that would fail if https://github.com/rtfd/readthedocs.org/issues/1902 regressed."""