Skip to content

Commit

Permalink
Do not allow conflicts that appear in history to be uninstalled (#345)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaimergp authored Nov 1, 2023
1 parent 78ab86e commit 27d164c
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 9 deletions.
11 changes: 8 additions & 3 deletions conda_libmamba_solver/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,6 @@ def _log_info(self):
def _setup_solver(self, index: LibMambaIndexHelper):
self._solver_options = solver_options = [
(api.SOLVER_FLAG_ALLOW_DOWNGRADE, 1),
(api.SOLVER_FLAG_INSTALL_ALSO_UPDATES, 1),
]
if context.channel_priority is ChannelPriority.STRICT:
solver_options.append((api.SOLVER_FLAG_STRICT_REPO_PRIORITY, 1))
Expand Down Expand Up @@ -499,8 +498,14 @@ def _specs_to_tasks_add(self, in_state: SolverInputState, out_state: SolverOutpu
elif name == "python" and installed and not pinned:
pyver = ".".join(installed.version.split(".")[:2])
tasks[("ADD_PIN", api.SOLVER_NOOP)].append(f"python {pyver}.*")
elif history and not history.is_name_only_spec and not conflicting:
tasks[("ADD_PIN", api.SOLVER_NOOP)].append(self._spec_to_str(history))
elif history:
if conflicting and history.strictness == 3:
# relax name-version-build (strictness=3) history specs that cause conflicts
# this is called neutering and makes test_neutering_of_historic_specs pass
spec = f"{name} {history.version}.*" if history.version else name
tasks[("INSTALL", api.SOLVER_INSTALL)].append(spec)
else:
tasks[("INSTALL", api.SOLVER_INSTALL)].append(self._spec_to_str(history))
elif installed:
if conflicting:
tasks[("ALLOW_UNINSTALL", api.SOLVER_ALLOWUNINSTALL)].append(name)
Expand Down
10 changes: 5 additions & 5 deletions conda_libmamba_solver/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -1049,13 +1049,13 @@ def post_solve(self, solver: Type["Solver"]):

# ## Neutered ###
# annotate overridden history specs so they are written to disk
for name, spec in self.specs.items():
history_spec = sis.history.get(name)
if history_spec and spec.strictness < history_spec.strictness:
for name, spec in sis.history.items():
record = self.records.get(name)
if record and not spec.match(record):
self.neutered.set(
name,
MatchSpec(name, version=history_spec.get("version")),
reason="Spec needs less strict constrains than history",
MatchSpec(name, version=record.version),
reason="Solution required a history override",
)

# ## Add inconsistent packages back ###
Expand Down
19 changes: 19 additions & 0 deletions news/345-keep-history
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
### Enhancements

* <news item>

### Bug fixes

* Ensure that historic specs are kept in the environment, even if that means raising a conflict. (#341 via #345)

### Deprecations

* <news item>

### Docs

* <news item>

### Other

* <news item>
43 changes: 42 additions & 1 deletion tests/test_solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,17 @@
from conda.common.compat import on_linux, on_win
from conda.common.io import env_var
from conda.core.prefix_data import PrefixData, get_python_version_for_prefix
from conda.testing.integration import Commands, make_temp_env, run_command
from conda.exceptions import DryRunExit
from conda.testing.integration import (
Commands,
make_temp_env,
package_is_installed,
run_command,
)
from conda.testing.solver_helpers import SolverTests

from conda_libmamba_solver import LibMambaSolver
from conda_libmamba_solver.exceptions import LibMambaUnsatisfiableError
from conda_libmamba_solver.mamba_utils import mamba_version

from .utils import conda_subprocess
Expand Down Expand Up @@ -417,3 +424,37 @@ def test_ca_certificates_pins():
break
else:
raise AssertionError("ca-certificates not found in LINK actions")


def test_python_update_should_not_uninstall_history():
"""
https://github.com/conda/conda-libmamba-solver/issues/341
Original report complained about an upgrade to Python 3.12 removing numpy from the
(originally) py311 environment because at that point in time numpy for py312 was not yet
available in defaults. Since at some point it will be, we will test for similar behavior
here, but in a way that we know will never be reverted: typing_extensions being available for
Python 2.7.
Given a Python 3.8 + typing-extensions environment, the solver should not allow us to
change to Python 2.7 because typing-extensions is in history, and the only solution to get
Python 2.7 is to remove it. Hence, we expect a conflict that mentions both.
"""
channels = "--override-channels", "-c", "conda-forge"
solver = "--solver", "libmamba"
with make_temp_env("python=3.8", "typing_extensions>=4.8", *channels, *solver) as prefix:
assert package_is_installed(prefix, "python=3.8")
assert package_is_installed(prefix, "typing_extensions>=4.8")
with pytest.raises(
LibMambaUnsatisfiableError,
match=r"python 2\.7.|\n*typing_extensions",
):
run_command(
Commands.INSTALL,
prefix,
"python=2.7",
*channels,
*solver,
"--dry-run",
no_capture=True,
)

0 comments on commit 27d164c

Please sign in to comment.