diff --git a/src/poetry/mixology/version_solver.py b/src/poetry/mixology/version_solver.py index 0923fdead6f..dfd31fde73a 100644 --- a/src/poetry/mixology/version_solver.py +++ b/src/poetry/mixology/version_solver.py @@ -374,10 +374,22 @@ def _get_min(dependency: Dependency) -> Tuple[bool, int]: ) return dependency.complete_name + version = None + if dependency.name not in self._use_latest: + # prefer locked version of compatible (not exact same) dependency; + # required in order to not unnecessarily update dependencies with + # extras, e.g. "coverage" vs. "coverage[toml]" + locked = self._locked.get(dependency.name, None) + if locked is not None: + for version in packages: + if version.version <= locked.version: + if version.version != locked.version: + version = None + break try: - version = packages[0] + version = version or packages[0] except IndexError: - version = None + pass if version is None: # If there are no versions that satisfy the constraint, diff --git a/tests/mixology/version_solver/test_with_lock.py b/tests/mixology/version_solver/test_with_lock.py index ffea081bebd..fe3a801bd74 100644 --- a/tests/mixology/version_solver/test_with_lock.py +++ b/tests/mixology/version_solver/test_with_lock.py @@ -118,3 +118,33 @@ def test_with_compatible_locked_dependencies_use_latest(root, provider, repo): }, use_latest=["foo"], ) + + +def test_with_compatible_locked_dependencies_with_extras(root, provider, repo): + root.add_dependency(Factory.create_dependency("foo", "^1.0")) + + package_foo_0 = get_package("foo", "1.0.0") + package_foo_1 = get_package("foo", "1.0.1") + bar_extra_dep = Factory.create_dependency( + "bar", {"version": "^1.0", "extras": "extra"} + ) + for package_foo in (package_foo_0, package_foo_1): + package_foo.add_dependency(bar_extra_dep) + repo.add_package(package_foo) + + bar_deps = {"baz": {"version": "^1.0", "extras": ["extra"]}} + add_to_repo(repo, "bar", "1.0.0", bar_deps) + add_to_repo(repo, "bar", "1.0.1", bar_deps) + add_to_repo(repo, "baz", "1.0.0") + add_to_repo(repo, "baz", "1.0.1") + + check_solver_result( + root, + provider, + result={"foo": "1.0.0", "bar": "1.0.0", "baz": "1.0.0"}, + locked={ + "foo": get_package("foo", "1.0.0"), + "bar": get_package("bar", "1.0.0"), + "baz": get_package("baz", "1.0.0"), + }, + )