From e040d7eb5ff125ba6201ffa6c28ebe867ffb2ce2 Mon Sep 17 00:00:00 2001 From: Christopher Barber Date: Sat, 13 Apr 2024 18:14:16 -0400 Subject: [PATCH] Drop classic solver workaround if conda-libmamba-solver is at least 24.1 Fixes #118 --- CHANGELOG.md | 4 +++ Makefile | 1 + src/whl2conda/cli/install.py | 27 ++++++++++----- test/cli/test_install.py | 64 +++++++++++++++++++++++++++++++----- 4 files changed, 79 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aeb507..f89eb75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # whl2conda changes ## [24.4.0] - *in progress* +### Changes +* Only use classic installer in `whl2conda install` environments if + `conda-libmamba-solver` in base environment has version less than 24.1.0 (see #118) + ### Bug fixes * Transfer executable file permissions from wheel (#135) * Correct typos in documentation. diff --git a/Makefile b/Makefile index f893bb8..2e66a5b 100644 --- a/Makefile +++ b/Makefile @@ -109,6 +109,7 @@ ruff: check-format: $(CONDA_RUN) ruff format --check src test +.PHONY: test test: pytest coverage: diff --git a/src/whl2conda/cli/install.py b/src/whl2conda/cli/install.py index f031366..3c53035 100644 --- a/src/whl2conda/cli/install.py +++ b/src/whl2conda/cli/install.py @@ -286,17 +286,26 @@ def conda_env_install(parsed: InstallArgs, dependencies: list[str]): else: subprocess.check_call(install_pkg_cmd) - # Workaround for https://github.com/conda/conda/issues/13479 - # If a package is installed directly from file, then set solver to classic - set_solver_cmd = ( - ["conda", "run"] - + env_opts - + ["conda", "config", "--env", "--set", "solver", "classic"] - ) + check_libmamba_cmd = "conda list -n base conda-libmamba-solver --json".split() if parsed.dry_run: - print("Running ", set_solver_cmd) + print("running ", check_libmamba_cmd) else: - subprocess.check_call(set_solver_cmd) + jsonstr = subprocess.check_output(check_libmamba_cmd, encoding="utf-8") + jobj = json.loads(jsonstr) + version_str = jobj and jobj[0].get("version") + version = tuple(int(s) for s in version_str.split(".")) + if version < (24, 1, 0): + # Workaround for https://github.com/conda/conda/issues/13479 + # If a package is installed directly from file, then set solver to classic + set_solver_cmd = ( + ["conda", "run"] + + env_opts + + ["conda", "config", "--env", "--set", "solver", "classic"] + ) + if parsed.dry_run: + print("Running ", set_solver_cmd) + else: + subprocess.check_call(set_solver_cmd) conda_depend_re = re.compile(r"\s*(?P[\w\d.-]+)\s*(?P.*)") diff --git a/test/cli/test_install.py b/test/cli/test_install.py index 446abfa..54a75f0 100644 --- a/test/cli/test_install.py +++ b/test/cli/test_install.py @@ -20,6 +20,7 @@ import re from pathlib import Path +from textwrap import dedent from typing import Any, Sequence import pytest @@ -187,13 +188,6 @@ def test_env_install( assert "quaternion" in packages_by_name assert "simple" in packages_by_name - # solver should be set to classic to avoid https://github.com/conda/conda/issues/13479 - d = conda_json( - "run", "-p", str(prefix), "conda", "config", "--json", "--show", "solver" - ) - assert d["solver"] == "classic" - - conda_output("create", "-n", "test-env", "python=3.9") assert test_env.is_dir() main([ @@ -223,9 +217,36 @@ def test_env_install_whitebox( prefix = tmp_path.joinpath("prefix") call_args: list[list[str]] = [] + fake_call_results: list[Any] = [ + None, + None, + dedent( + """ + [ + { + "base_url": "https://conda.anaconda.org/conda-forge", + "build_number": 0, + "build_string": "pyhd8ed1ab_0", + "channel": "conda-forge", + "dist_name": "conda-libmamba-solver-24.1.0-pyhd8ed1ab_0", + "name": "conda-libmamba-solver", + "platform": "noarch", + "version": "24.1.0" + } + ] + """ + ), + ] - def fake_call(cmd: Sequence[str]) -> Any: + def fake_call(cmd: Sequence[str], encoding=None) -> Any: + if encoding: + assert encoding == "utf-8" + i = len(call_args) call_args.append(list(cmd)) + if len(fake_call_results) > i: + return fake_call_results[i] + else: + return None monkeypatch.setattr("subprocess.check_call", fake_call) monkeypatch.setattr("subprocess.check_output", fake_call) @@ -283,6 +304,33 @@ def fake_call(cmd: Sequence[str]) -> Any: out, err = capsys.readouterr() assert "Running" in out + # Test for presence of conda solver workaround for conda-libmamba-solver < 24.1 + call_args.clear() + fake_call_results[2] = dedent( + """ + [ + { + "base_url": "https://conda.anaconda.org/conda-forge", + "build_number": 0, + "build_string": "pyhd8ed1ab_0", + "channel": "conda-forge", + "dist_name": "conda-libmamba-solver-23.12.0-pyhd8ed1ab_0", + "name": "conda-libmamba-solver", + "platform": "noarch", + "version": "23.12.0" + } + ] + """ + ) + + main(cmd_start + ["--name", "test-env", "--create", "--mamba"]) + assert len(call_args) == 4 + call4 = call_args[3] + assert call4[:4] == "conda run --name test-env".split() + assert call4[4:6] == "conda config".split() + assert "--set solver classic" in " ".join(call4) + assert "--env" in call4 + def test_prune_dependencies() -> None: """Unit test for internal _prune_dependencies function"""