Skip to content

Commit

Permalink
provider: do not merge deps from different sources
Browse files Browse the repository at this point in the history
This change ensures that the provider is less eager when merging
duplicate dependencies for a package. In particular, takes into
consideration source type, url and reference if available.
  • Loading branch information
abn committed May 18, 2022
1 parent 0b68704 commit 3efb4e0
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 6 deletions.
24 changes: 18 additions & 6 deletions src/poetry/puzzle/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,19 +550,31 @@ def complete_package(self, package: DependencyPackage) -> DependencyPackage:
# An example of this is:
# - pypiwin32 (220); sys_platform == "win32" and python_version >= "3.6"
# - pypiwin32 (219); sys_platform == "win32" and python_version < "3.6"
duplicates: dict[str, list[Dependency]] = {}
#
# Additional care has to be taken to ensure that hidden constraints like that
# of source type, reference etc. are taking into consideration when duplicates
# are identified.
duplicates: dict[tuple[str, str, str, str], list[Dependency]] = {}
for dep in dependencies:
if dep.complete_name not in duplicates:
duplicates[dep.complete_name] = []

duplicates[dep.complete_name].append(dep)
key = (
dep.complete_name,
dep.source_type,
dep.source_url,
dep.source_reference,
)
if key not in duplicates:
duplicates[key] = []
duplicates[key].append(dep)

dependencies = []
for dep_name, deps in duplicates.items():
for key, deps in duplicates.items():
if len(deps) == 1:
dependencies.append(deps[0])
continue

extra_keys = ", ".join(k for k in key[1:] if k is not None)
dep_name = f"{key[0]} ({extra_keys})" if extra_keys else key[0]

self.debug(f"<debug>Duplicate dependencies for {dep_name}</debug>")

deps = self._merge_dependencies_by_marker(deps)
Expand Down
62 changes: 62 additions & 0 deletions tests/puzzle/test_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from poetry.core.version.markers import parse_marker

from poetry.factory import Factory
from poetry.packages import DependencyPackage
from poetry.puzzle import Solver
from poetry.puzzle.exceptions import SolverProblemError
from poetry.puzzle.provider import Provider as BaseProvider
Expand Down Expand Up @@ -1337,6 +1338,67 @@ def test_solver_duplicate_dependencies_different_constraints_merge_by_marker(
)


def test_solver_duplicate_dependencies_different_sources_types_are_preserved(
solver: Solver, repo: Repository, package: Package
):
pendulum = get_package("pendulum", "2.0.3")
repo.add_package(pendulum)
repo.add_package(get_package("cleo", "1.0.0"))
repo.add_package(get_package("demo", "0.1.0"))

dependency_pypi = Factory.create_dependency("demo", ">=0.1.0")
dependency_git = Factory.create_dependency(
"demo", {"git": "https://github.com/demo/demo.git"}, groups=["dev"]
)
package.add_dependency(dependency_git)
package.add_dependency(dependency_pypi)

demo = Package(
"demo",
"0.1.2",
source_type="git",
source_url="https://github.com/demo/demo.git",
source_reference=DEFAULT_SOURCE_REF,
source_resolved_reference="9cf87a285a2d3fbb0b9fa621997b3acc3631ed24",
)

transaction = solver.solve()

ops = check_solver_result(
transaction,
[{"job": "install", "package": pendulum}, {"job": "install", "package": demo}],
)

op = ops[1]

assert op.package.source_type == demo.source_type
assert op.package.source_reference == DEFAULT_SOURCE_REF
assert op.package.source_resolved_reference.startswith(
demo.source_resolved_reference
)

complete_package = solver.provider.complete_package(
DependencyPackage(package.to_dependency(), package)
)

assert len(complete_package.all_requires) == 2

pypi, git = complete_package.all_requires

assert isinstance(pypi, Dependency)
assert pypi == dependency_pypi

assert isinstance(git, VCSDependency)
assert git.constraint
assert git.constraint != dependency_git.constraint
assert (git.name, git.source_type, git.source_url, git.source_reference) == (
dependency_git.name,
dependency_git.source_type,
dependency_git.source_url,
DEFAULT_SOURCE_REF,
)


def test_solver_duplicate_dependencies_different_constraints_merge_no_markers(
solver: Solver, repo: Repository, package: Package
):
Expand Down

0 comments on commit 3efb4e0

Please sign in to comment.