import os.path import tempfile from contextlib import contextmanager from os import ( chmod, makedirs, stat, symlink, ) from shutil import rmtree from stat import S_IXUSR from subprocess import ( PIPE, Popen, ) from typing import ( Any, Dict, Optional, ) from galaxy.tool_util.deps import ( build_dependency_manager, DependencyManager, ) from galaxy.tool_util.deps.requirements import ( ToolRequirement, ToolRequirements, ) from galaxy.tool_util.deps.resolvers import NullDependency from galaxy.tool_util.deps.resolvers.galaxy_packages import GalaxyPackageDependency from galaxy.tool_util.deps.resolvers.lmod import ( LmodDependency, LmodDependencyResolver, ) from galaxy.tool_util.deps.resolvers.modules import ( ModuleDependency, ModuleDependencyResolver, ) from galaxy.util import unicodify from galaxy.util.bunch import Bunch from .util import modify_environ # If true, test created DependencyManager objects by serializing out to json and re-constituting. ROUND_TRIP_TEST_DEPENDENCY_MANAGER_SERIALIZATION = True def test_tool_dependencies(): # Setup directories with __test_base_path() as base_path: for name, version, sub in [("dep1", "1.0", "env.sh"), ("dep1", "2.0", "bin"), ("dep2", "1.0", None)]: if sub == "bin": p = os.path.join(base_path, name, version, "bin") else: p = os.path.join(base_path, name, version) try: makedirs(p) except Exception: pass if sub == "env.sh": __touch(os.path.join(p, "env.sh")) dm = __dependency_manager_for_base_path(default_base_path=base_path) dependency = dm.find_dep("dep1", "1.0") assert dependency.script == os.path.join(base_path, "dep1", "1.0", "env.sh") assert dependency.path == os.path.join(base_path, "dep1", "1.0") assert dependency.version == "1.0" dependency = dm.find_dep("dep1", "2.0") assert dependency.script is None assert dependency.path == os.path.join(base_path, "dep1", "2.0") assert dependency.version == "2.0" # Test default versions symlink(os.path.join(base_path, "dep1", "2.0"), os.path.join(base_path, "dep1", "default")) dependency = dm.find_dep("dep1", None) assert dependency.version == "2.0" # Test default resolve will be fall back on default package dependency # when using the default resolver. dependency = dm.find_dep("dep1", "2.1") assert dependency.version == "2.0" # 2.0 is defined as default_version TEST_REPO_USER = "devteam" TEST_REPO_NAME = "bwa" TEST_REPO_CHANGESET = "12abcd41223da" TEST_VERSION = "0.5.9" def test_toolshed_set_enviornment_requiremetns(): with __test_base_path() as base_path: test_repo = __build_test_repo("set_environment") dm = __dependency_manager_for_base_path(default_base_path=base_path) env_settings_dir = os.path.join( base_path, "environment_settings", TEST_REPO_NAME, TEST_REPO_USER, TEST_REPO_NAME, TEST_REPO_CHANGESET ) os.makedirs(env_settings_dir) dependency = dm.find_dep( TEST_REPO_NAME, version=None, type="set_environment", installed_tool_dependencies=[test_repo] ) assert dependency.version is None assert dependency.script == os.path.join(env_settings_dir, "env.sh") def test_toolshed_package_requirements(): with __test_base_path() as base_path: test_repo = __build_test_repo("package", version=TEST_VERSION) dm = __dependency_manager_for_base_path(default_base_path=base_path) package_dir = __build_ts_test_package(base_path) dependency = dm.find_dep( TEST_REPO_NAME, version=TEST_VERSION, type="package", installed_tool_dependencies=[test_repo] ) assert dependency.version == TEST_VERSION assert dependency.script == os.path.join(package_dir, "env.sh") def test_toolshed_tools_fallback_on_manual_dependencies(): with __test_base_path() as base_path: dm = __dependency_manager_for_base_path(default_base_path=base_path) test_repo = __build_test_repo("package", version=TEST_VERSION) env_path = __setup_galaxy_package_dep(base_path, "dep1", "1.0") dependency = dm.find_dep("dep1", version="1.0", type="package", installed_tool_dependencies=[test_repo]) assert dependency.version == "1.0" assert dependency.script == env_path def test_toolshed_greater_precendence(): with __test_base_path() as base_path: dm = __dependency_manager_for_base_path(default_base_path=base_path) test_repo = __build_test_repo("package", version=TEST_VERSION) ts_package_dir = __build_ts_test_package(base_path) gx_env_path = __setup_galaxy_package_dep(base_path, TEST_REPO_NAME, TEST_VERSION) ts_env_path = os.path.join(ts_package_dir, "env.sh") dependency = dm.find_dep( TEST_REPO_NAME, version=TEST_VERSION, type="package", installed_tool_dependencies=[test_repo] ) assert dependency.script != gx_env_path # Not the galaxy path, it should be the tool shed path used. assert dependency.script == ts_env_path def __build_ts_test_package(base_path, script_contents=""): package_dir = os.path.join( base_path, TEST_REPO_NAME, TEST_VERSION, TEST_REPO_USER, TEST_REPO_NAME, TEST_REPO_CHANGESET ) __touch(os.path.join(package_dir, "env.sh"), script_contents) return package_dir REQUIREMENT_A = {"name": "gnuplot", "type": "package", "version": "4.6"} REQUIREMENT_B = REQUIREMENT_A.copy() REQUIREMENT_B["version"] = "4.7" def test_tool_requirement_equality(): a = ToolRequirement.from_dict(REQUIREMENT_A) assert a == ToolRequirement(**REQUIREMENT_A) # type: ignore[arg-type] # https://github.com/python/mypy/issues/10008 b = ToolRequirement(**REQUIREMENT_B) # type: ignore[arg-type] # https://github.com/python/mypy/issues/10008 assert a != b def test_tool_requirements(): tool_requirements_ab = ToolRequirements([REQUIREMENT_A, REQUIREMENT_B]) tool_requirements_ab_dup = ToolRequirements([REQUIREMENT_A, REQUIREMENT_B]) tool_requirements_b = ToolRequirements([REQUIREMENT_A]) assert tool_requirements_ab == ToolRequirements([REQUIREMENT_B, REQUIREMENT_A]) assert tool_requirements_ab == ToolRequirements([REQUIREMENT_B, REQUIREMENT_A, REQUIREMENT_A]) assert tool_requirements_ab != tool_requirements_b assert len({tool_requirements_ab, tool_requirements_ab_dup}) == 1 def test_module_dependency_resolver(): with __test_base_path() as temp_directory: module_script = _setup_module_command( temp_directory, """ -------------------------- /soft/modules/modulefiles --------------------------- JAGS/3.2.0-gcc45 JAGS/3.3.0-gcc4.7.2 ProbABEL/0.1-3 ProbABEL/0.1-9e R/2.12.2 R/2.13.1 R/2.14.1 R/2.15.0 R/2.15.1 R/3.0.1(default) abokia-blast/2.0.2-130524/ompi_intel abokia-blast/2.0.2-130630/ompi_intel --------------------------- /soft/intel/modulefiles ---------------------------- advisor/2013/update1 intel/11.1.075 mkl/10.2.1.017 advisor/2013/update2 intel/11.1.080 mkl/10.2.5.035 advisor/2013/update3 intel/12.0 mkl/10.2.7.041 """, ) resolver = ModuleDependencyResolver(_SimpleDependencyManager(), modulecmd=module_script) module = resolver.resolve(ToolRequirement(name="R", version=None, type="package")) assert module.module_name == "R" assert module.module_version is None module = resolver.resolve(ToolRequirement(name="R", version="3.0.1", type="package")) assert module.module_name == "R" assert module.module_version == "3.0.1" module = resolver.resolve(ToolRequirement(name="R", version="3.0.4", type="package")) assert isinstance(module, NullDependency) def test_module_resolver_with_mapping(): with __test_base_path() as temp_directory: module_script = _setup_module_command( temp_directory, """ -------------------------- /soft/modules/modulefiles --------------------------- blast/2.24 """, ) mapping_file = os.path.join(temp_directory, "mapping") with open(mapping_file, "w") as f: f.write(""" - from: blast+ to: blast """) resolver = ModuleDependencyResolver( _SimpleDependencyManager(), modulecmd=module_script, mapping_files=mapping_file ) module = resolver.resolve(ToolRequirement(name="blast+", version="2.24", type="package")) assert module.module_name == "blast" assert module.module_version == "2.24", module.module_version def test_module_resolver_with_mapping_specificity_rules(): # If a requirement demands a specific version, # do not map to a different version when the version # has not been specified explicitly with __test_base_path() as temp_directory: module_script = _setup_module_command( temp_directory, """ -------------------------- /soft/modules/modulefiles --------------------------- blast/2.24 """, ) mapping_file = os.path.join(temp_directory, "mapping") with open(mapping_file, "w") as f: f.write(""" - from: name: blast unversioned: true to: name: blast version: 2.24 """) resolver = ModuleDependencyResolver( _SimpleDependencyManager(), modulecmd=module_script, mapping_files=mapping_file ) module = resolver.resolve(ToolRequirement(name="blast", type="package")) assert module.module_name == "blast" assert ( module.module_version == "2.24" ), module.module_version # successful resolution, because Requirement does not ask for a specific version module = resolver.resolve(ToolRequirement(name="blast", version="2.22", type="package")) assert isinstance( module, NullDependency ) # NullDependency, because we don't map `version: Null` over a Requirement that asks for a specific version def test_module_resolver_with_mapping_versions(): with __test_base_path() as temp_directory: module_script = _setup_module_command( temp_directory, """ -------------------------- /soft/modules/modulefiles --------------------------- blast/2.22.0-mpi blast/2.23 blast/2.24.0-mpi """, ) mapping_file = os.path.join(temp_directory, "mapping") with open(mapping_file, "w") as f: f.write(""" - from: name: blast+ version: 2.24 to: name: blast version: 2.24.0-mpi - from: name: blast version: 2.22 to: version: 2.22.0-mpi """) resolver = ModuleDependencyResolver( _SimpleDependencyManager(), modulecmd=module_script, mapping_files=mapping_file ) module = resolver.resolve(ToolRequirement(name="blast+", version="2.24", type="package")) assert module.module_name == "blast" assert module.module_version == "2.24.0-mpi", module.module_version resolver = ModuleDependencyResolver( _SimpleDependencyManager(), modulecmd=module_script, mapping_files=mapping_file ) module = resolver.resolve(ToolRequirement(name="blast+", version="2.23", type="package")) assert isinstance(module, NullDependency) module = resolver.resolve(ToolRequirement(name="blast", version="2.22", type="package")) assert module.module_name == "blast" assert module.module_version == "2.22.0-mpi", module.module_version def test_module_dependency_resolver_skip_availability_check(): with __test_base_path() as temp_directory: module_script = _setup_module_command( temp_directory, """ -------------------------- /soft/modules/modulefiles --------------------------- BlastPlus/2.4.0+ Infernal/1.1.2 Mothur/1.36.1 """, ) resolver = ModuleDependencyResolver( _SimpleDependencyManager(), modulecmd=module_script, skip_availability_check="true" ) module = resolver.resolve(ToolRequirement(name="Mothur", version="1.36.1", type="package")) assert module.module_name == "Mothur" assert module.module_version == "1.36.1" module = resolver.resolve(ToolRequirement(name="BlastPlus", version="2.3", type="package")) assert module.module_name == "BlastPlus" assert module.module_version == "2.3" module = resolver.resolve(ToolRequirement(name="Infernal", version=None, type="package")) assert module.module_name == "Infernal" assert module.module_version is None module = resolver.resolve(ToolRequirement(name="Foo", version="0.1", type="package")) assert module.module_name == "Foo" assert module.module_version == "0.1" module = resolver.resolve(ToolRequirement(name="Bar", version=None, type="package")) assert module.module_name == "Bar" assert module.module_version is None def _setup_module_command(temp_directory, contents): module_script = os.path.join(temp_directory, "modulecmd") __write_script( module_script, f"""#!/bin/sh cat {temp_directory}/example_output 1>&2; """, ) with open(os.path.join(temp_directory, "example_output"), "w") as f: # Subset of module avail from MSI cluster. f.write(contents) return module_script def test_module_dependency(): with __test_base_path() as temp_directory: # Create mock modulecmd script that just exports a variable # the way modulecmd sh load would, but also validate correct # module name and version are coming through. mock_modulecmd = os.path.join(temp_directory, "modulecmd") __write_script( mock_modulecmd, """#!/bin/sh if [ $3 != "foomodule/1.0" ]; then exit 1 fi echo 'FOO="bar"' """, ) resolver = Bunch(modulecmd=mock_modulecmd, modulepath="/something") dependency = ModuleDependency(resolver, "foomodule", "1.0") __assert_foo_exported(dependency.shell_commands()) def test_lmod_dependency_resolver(): with __test_base_path() as temp_directory: lmod_script = _setup_lmod_command( temp_directory, """ /opt/apps/modulefiles: BlastPlus/ BlastPlus/2.2.31+ BlastPlus/2.4.0+ Infernal/ Infernal/1.1.2 Mothur/ Mothur/1.33.3 Mothur/1.36.1 Mothur/1.38.1.1 """, ) resolver = LmodDependencyResolver( _SimpleDependencyManager(), lmodexec=lmod_script, modulepath="/path/to/modulefiles" ) lmod = resolver.resolve(ToolRequirement(name="Infernal", version=None, type="package")) assert lmod.module_name == "Infernal" assert lmod.module_version is None lmod = resolver.resolve(ToolRequirement(name="BlastPlus", version="2.4.0+", type="package")) assert lmod.module_name == "BlastPlus" assert lmod.module_version == "2.4.0+" lmod = resolver.resolve(ToolRequirement(name="Mothur", version="1.39", type="package")) assert isinstance(lmod, NullDependency) def test_lmod_dependency_resolver_versionless(): with __test_base_path() as temp_directory: lmod_script = _setup_lmod_command( temp_directory, """ /opt/apps/modulefiles: BlastPlus/2.4.0+ Infernal/1.1.2 Mothur/1.36.1 """, ) resolver = LmodDependencyResolver( _SimpleDependencyManager(), lmodexec=lmod_script, versionless="true", modulepath="/path/to/modulefiles" ) lmod = resolver.resolve(ToolRequirement(name="Infernal", version=None, type="package")) assert lmod.module_name == "Infernal" assert lmod.module_version is None lmod = resolver.resolve(ToolRequirement(name="Mothur", version="1.36.1", type="package")) assert lmod.module_name == "Mothur" assert lmod.module_version == "1.36.1" lmod = resolver.resolve(ToolRequirement(name="BlastPlus", version="2.3", type="package")) assert lmod.module_name == "BlastPlus" assert lmod.module_version is None lmod = resolver.resolve(ToolRequirement(name="Foo", version="0.1", type="package")) assert isinstance(lmod, NullDependency) def test_lmod_dependency_resolver_with_mapping_file(): with __test_base_path() as temp_directory: lmod_script = _setup_lmod_command( temp_directory, """ /opt/apps/modulefiles: BlastPlus/ BlastPlus/2.2.31+ BlastPlus/2.4.0+ Infernal/ Infernal/1.1.2 Mothur/ Mothur/1.33.3 Mothur/1.36.1 Mothur/1.38.1.1 """, ) mapping_file = os.path.join(temp_directory, "mapping") with open(mapping_file, "w") as f: f.write(""" - from: name: blast+ unversioned: true to: name: BlastPlus version: 2.4.0+ - from: name: Mothur version: 1.38 to: version: 1.38.1.1 """) resolver = LmodDependencyResolver( _SimpleDependencyManager(), lmodexec=lmod_script, mapping_files=mapping_file, modulepath="/path/to/modulefiles", ) lmod = resolver.resolve(ToolRequirement(name="BlastPlus", version="2.2.31+", type="package")) assert lmod.module_name == "BlastPlus" assert lmod.module_version == "2.2.31+", lmod.module_version lmod = resolver.resolve(ToolRequirement(name="blast+", type="package")) assert lmod.module_name == "BlastPlus" assert lmod.module_version == "2.4.0+", lmod.module_version lmod = resolver.resolve(ToolRequirement(name="blast+", version="2.23", type="package")) assert isinstance(lmod, NullDependency) lmod = resolver.resolve(ToolRequirement(name="Infernal", version="1.2", type="package")) assert isinstance(lmod, NullDependency) lmod = resolver.resolve(ToolRequirement(name="Mothur", version="1.38", type="package")) assert lmod.module_name == "Mothur" assert lmod.module_version == "1.38.1.1", lmod.module_version def test_lmod_dependency_resolver_skip_availability_check(): with __test_base_path() as temp_directory: lmod_script = _setup_lmod_command( temp_directory, """ /opt/apps/modulefiles: BlastPlus/2.4.0+ Infernal/1.1.2 Mothur/1.36.1 """, ) resolver = LmodDependencyResolver( _SimpleDependencyManager(), lmodexec=lmod_script, skip_availability_check="true", modulepath="/path/to/modulefiles", ) lmod = resolver.resolve(ToolRequirement(name="Mothur", version="1.36.1", type="package")) assert lmod.module_name == "Mothur" assert lmod.module_version == "1.36.1" lmod = resolver.resolve(ToolRequirement(name="BlastPlus", version="2.3", type="package")) assert lmod.module_name == "BlastPlus" assert lmod.module_version == "2.3" lmod = resolver.resolve(ToolRequirement(name="Infernal", version=None, type="package")) assert lmod.module_name == "Infernal" assert lmod.module_version is None lmod = resolver.resolve(ToolRequirement(name="Foo", version="0.1", type="package")) assert lmod.module_name == "Foo" assert lmod.module_version == "0.1" lmod = resolver.resolve(ToolRequirement(name="Bar", version=None, type="package")) assert lmod.module_name == "Bar" assert lmod.module_version is None def _setup_lmod_command(temp_directory, contents): lmod_script = os.path.join(temp_directory, "lmod") __write_script( lmod_script, f"""#!/bin/sh cat {temp_directory}/lmod_example_output 1>&2; """, ) with open(os.path.join(temp_directory, "lmod_example_output"), "w") as f: # Subset of a "lmod -t avail" command of the LMOD environment module system. f.write(contents) return lmod_script def test_lmod_dependency(): with __test_base_path() as temp_directory: # Create mock lmod script that just exports a variable # the way "lmod load" would, but also validate correct # module name and version are coming through. mock_lmodexec = os.path.join(temp_directory, "pouet") __write_script( mock_lmodexec, """#!/bin/sh if [ "$2" != "foomodule/1.0" ]; then exit 1 fi echo 'FOO="bar"' """, ) resolver = Bunch(lmodexec=mock_lmodexec, settargexec=None, modulepath="/path/to/modulefiles") dependency = LmodDependency(resolver, "foomodule", "1.0") __assert_foo_exported(dependency.shell_commands()) def __write_script(path, contents): with open(path, "w") as f: f.write(contents) st = stat(path) chmod(path, st.st_mode | S_IXUSR) def test_galaxy_dependency_object_script(): with __test_base_path() as base_path: # Create env.sh file that just exports variable FOO and verify it # shell_commands export it correctly. env_path = __setup_galaxy_package_dep(base_path, TEST_REPO_NAME, TEST_VERSION, 'export FOO="bar"') dependency = GalaxyPackageDependency( env_path, os.path.dirname(env_path), TEST_REPO_NAME, "package", TEST_VERSION ) __assert_foo_exported(dependency.shell_commands()) def test_shell_commands_built(): # Test that dependency manager builds valid shell commands for a list of # requirements. with __test_base_path() as base_path: dm = __dependency_manager_for_base_path(default_base_path=base_path) __setup_galaxy_package_dep(base_path, TEST_REPO_NAME, TEST_VERSION, contents='export FOO="bar"') mock_requirements = ToolRequirements([{"type": "package", "version": TEST_VERSION, "name": TEST_REPO_NAME}]) commands = dm.dependency_shell_commands(mock_requirements) __assert_foo_exported(commands) def __assert_foo_exported(commands): command = ["bash", "-c", '{}; echo "$FOO"'.format("".join(commands))] process = Popen(command, stdout=PIPE) output = process.communicate()[0].strip() assert output == b"bar", f"Command {command} exports FOO as {unicodify(output)}, not bar" def __setup_galaxy_package_dep(base_path, name, version, contents=""): dep_directory = os.path.join(base_path, name, version) env_path = os.path.join(dep_directory, "env.sh") __touch(env_path, contents) return env_path def __touch(fname, data=None): dirname = os.path.dirname(fname) if not os.path.exists(dirname): makedirs(dirname) f = open(fname, "w") try: if data: f.write(data) finally: f.close() def __build_test_repo(type, version=None): return Bunch( owner=TEST_REPO_USER, name=TEST_REPO_NAME, type=type, version=version, tool_shed_repository=Bunch( owner=TEST_REPO_USER, name=TEST_REPO_NAME, installed_changeset_revision=TEST_REPO_CHANGESET ), ) @contextmanager def __test_base_path(): base_path = tempfile.mkdtemp() try: yield base_path finally: rmtree(base_path) def test_parse(): with __parse_resolvers(""" """) as dependency_resolvers: assert "ToolShed" in dependency_resolvers[0].__class__.__name__ assert "Galaxy" in dependency_resolvers[1].__class__.__name__ with __parse_resolvers(""" """) as dependency_resolvers: assert "Galaxy" in dependency_resolvers[0].__class__.__name__ assert "ToolShed" in dependency_resolvers[1].__class__.__name__ with __parse_resolvers(""" """) as dependency_resolvers: assert not dependency_resolvers[0].versionless assert dependency_resolvers[2].versionless with __parse_resolvers(""" """) as dependency_resolvers: # Unspecified base_paths are both default_base_paths assert dependency_resolvers[0].base_path == dependency_resolvers[1].base_path # Can specify custom base path... assert dependency_resolvers[2].base_path == "/opt/galaxy/legacy" # ... that is different from the default. assert dependency_resolvers[0].base_path != dependency_resolvers[2].base_path def test_uses_tool_shed_dependencies(): with __dependency_manager(""" """) as dm: assert not dm.uses_tool_shed_dependencies() with __dependency_manager(""" """) as dm: assert dm.uses_tool_shed_dependencies() def test_config_module_defaults(): with __parse_resolvers(""" """) as dependency_resolvers: module_resolver = dependency_resolvers[0] assert module_resolver.module_checker.__class__.__name__ == "AvailModuleChecker" with __parse_resolvers( """ - type: modules prefetch: false """, extension=".yml", ) as dependency_resolvers: module_resolver = dependency_resolvers[0] assert module_resolver.module_checker.__class__.__name__ == "AvailModuleChecker" def test_config_modulepath(): # Test reads and splits MODULEPATH if modulepath is not specified. with __parse_resolvers(""" """) as dependency_resolvers: assert dependency_resolvers[0].module_checker.directories == [ "/opt/modules/modulefiles", "/usr/local/modules/modulefiles", ] def test_config_MODULEPATH(): # Test reads and splits MODULEPATH if modulepath is not specified. with modify_environ({"MODULEPATH": "/opt/modules/modulefiles:/usr/local/modules/modulefiles"}): with __parse_resolvers(""" """) as dependency_resolvers: assert dependency_resolvers[0].module_checker.directories == [ "/opt/modules/modulefiles", "/usr/local/modules/modulefiles", ] def test_config_MODULESHOME(): # Test fallbacks to read MODULESHOME if modulepath is not specified and # neither is MODULEPATH. with modify_environ({"MODULESHOME": "/opt/modules"}, keys_to_remove=["MODULEPATH"]): with __parse_resolvers(""" """) as dependency_resolvers: assert dependency_resolvers[0].module_checker.directories == ["/opt/modules/modulefiles"] def test_config_module_directory_searcher(): with __parse_resolvers(""" """) as dependency_resolvers: module_resolver = dependency_resolvers[0] assert module_resolver.module_checker.directories == ["/opt/Modules/modulefiles"] def test_dependency_manager_config_options_global(): app_config = { "tool_dependency_dir": "/tmp", "tool_dependency_cache_dir": "/tmp", "conda_auto_init": False, } dm = __dependency_manager_for_config(app_config.copy()) assert not dm.to_dict()["cache"] app_config["use_cached_dependency_manager"] = True dm = __dependency_manager_for_config(app_config.copy()) assert dm.to_dict()["cache"] assert dm.to_dict()["precache"] app_config["precache_dependencies"] = False dm = __dependency_manager_for_config(app_config.copy()) assert not dm.to_dict()["precache"] conda_opts = _first_conda_resolver_options(dm) assert conda_opts["use_local"] is False app_config["conda_use_local"] = True dm = __dependency_manager_for_config(app_config.copy()) conda_opts = _first_conda_resolver_options(dm) assert conda_opts["use_local"] is True def test_dependency_manager_config_options_embedded_config(): dependency_config: Dict[str, Any] = { "default_base_path": "/tmp", "cache_dir": "/tmp", } app_config = { "dependency_resolution": dependency_config, "conda_auto_init": False, } dm = __dependency_manager_for_config(app_config.copy()) assert not dm.to_dict()["cache"] dependency_config["cache"] = True dm = __dependency_manager_for_config(app_config.copy()) assert dm.to_dict()["cache"] assert dm.to_dict()["precache"] dependency_config["precache"] = False dm = __dependency_manager_for_config(app_config.copy()) assert not dm.to_dict()["precache"] conda_opts = _first_conda_resolver_options(dm) assert conda_opts["use_local"] is False app_config["conda_use_local"] = True dm = __dependency_manager_for_config(app_config.copy()) conda_opts = _first_conda_resolver_options(dm) assert conda_opts["use_local"] is True def test_dependency_manager_config_options_resolution_config(): app_config = { "conda_auto_init": False, } resolution_config: Dict[str, Any] = { "default_base_path": "/tmp", "cache_dir": "/tmp", } dm = __dependency_manager_for_config(app_config.copy(), resolution_config=resolution_config.copy()) assert not dm.to_dict()["cache"] resolution_config["cache"] = True dm = __dependency_manager_for_config(app_config.copy(), resolution_config=resolution_config.copy()) assert dm.to_dict()["cache"] assert dm.to_dict()["precache"] resolution_config["precache"] = False dm = __dependency_manager_for_config(app_config.copy(), resolution_config=resolution_config.copy()) assert not dm.to_dict()["precache"] conda_opts = _first_conda_resolver_options(dm) assert conda_opts["use_local"] is False app_config["conda_use_local"] = True dm = __dependency_manager_for_config(app_config.copy(), resolution_config=resolution_config.copy()) conda_opts = _first_conda_resolver_options(dm) assert conda_opts["use_local"] is True def test_dependency_manager_none(): # by default tool_dependency_dir will be use to create some default resolvers... app_config = { "conda_auto_init": False, "tool_dependency_dir": "some_not_none_value", } dm = __dependency_manager_for_config(app_config.copy()) assert dm.to_dict()["use"] # but setting it none disables dependency resolution unless explicit resolvers # are configured. app_config = { "conda_auto_init": False, "tool_dependency_dir": "none", } dm = __dependency_manager_for_config(app_config.copy()) assert not dm.to_dict()["use"] def _first_conda_resolver_options(dm): return [r for r in dm.to_dict()["resolvers"] if r["resolver_type"] == "conda"][0] @contextmanager def __parse_resolvers(file_content, extension=".xml"): with __dependency_manager(file_content, extension=extension) as dm: yield dm.dependency_resolvers @contextmanager def __dependency_manager(file_content, extension=".xml"): with __test_base_path() as base_path: with tempfile.NamedTemporaryFile("w+", suffix=extension) as tmp: tmp.write(file_content) tmp.flush() dm = __dependency_manager_for_base_path(default_base_path=base_path, conf_file=tmp.name) yield dm def __dependency_manager_for_base_path(default_base_path: str, conf_file: Optional[str] = None) -> DependencyManager: dm = DependencyManager( default_base_path=default_base_path, conf_file=conf_file, app_config={"conda_auto_init": False} ) if ROUND_TRIP_TEST_DEPENDENCY_MANAGER_SERIALIZATION: as_dict = dm.to_dict() dm = build_dependency_manager(resolution_config_dict=as_dict) return dm def __dependency_manager_for_config(app_config, resolution_config=None): dm = build_dependency_manager(app_config_dict=app_config, resolution_config_dict=resolution_config) if ROUND_TRIP_TEST_DEPENDENCY_MANAGER_SERIALIZATION: as_dict = dm.to_dict() dm = build_dependency_manager(resolution_config_dict=as_dict) return dm class _SimpleDependencyManager: default_base_path = None def get_resolver_option(self, resolver, key, explicit_resolver_options=None): if explicit_resolver_options is None: explicit_resolver_options = {} return explicit_resolver_options.get(key)