Skip to content

Commit c820cad

Browse files
committed
Package.satisfies() considers sources more carefully
1 parent 4e413e0 commit c820cad

File tree

2 files changed

+66
-7
lines changed

2 files changed

+66
-7
lines changed

src/poetry/core/packages/package.py

+38-7
Original file line numberDiff line numberDiff line change
@@ -553,16 +553,47 @@ def satisfies(
553553
"""
554554
Helper method to check if this package satisfies a given dependency.
555555
556-
This is determined by assessing if this instance provides the package and
557-
features specified by the given dependency. Further, version and source
558-
types are checked.
556+
This is determined by assessing if this instance provides the package specified
557+
by the given dependency. Further, version and source types are checked.
559558
"""
560-
if not self.provides(dependency) or not dependency.constraint.allows(
561-
self.version
562-
):
559+
if self.name != dependency.name:
560+
return False
561+
562+
if not dependency.constraint.allows(self.version):
563563
return False
564564

565-
return ignore_source_type or self.is_same_source_as(dependency)
565+
if not ignore_source_type and not self.source_satisfies(dependency):
566+
return False
567+
568+
return True
569+
570+
def source_satisfies(self, dependency: Dependency) -> bool:
571+
"""Determine whether this package's source satisfies the given dependency."""
572+
if dependency.source_type is None:
573+
if dependency.source_name is None:
574+
# The dependency doesn't care about the source, so this package
575+
# certainly satisfies it.
576+
return True
577+
578+
# The dependency specifies a source_name but not a type: it wants either
579+
# pypi or a legacy repository.
580+
#
581+
# - If this package has no source type then it's from pypi, so it
582+
# matches if and only if that's what the dependency wants
583+
# - Else this package is a match if and only if it is from the desired
584+
# repository
585+
if self.source_type is None:
586+
return dependency.source_name.lower() == "pypi"
587+
588+
return (
589+
self.source_type == "legacy"
590+
and self.source_reference is not None
591+
and self.source_reference.lower() == dependency.source_name.lower()
592+
)
593+
594+
# The dependency specifies a source: this package matches if and only if it is
595+
# from that source.
596+
return dependency.is_same_source_as(self)
566597

567598
def __eq__(self, other: object) -> bool:
568599
if not isinstance(other, Package):

tests/packages/test_package.py

+28
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,34 @@ def test_package_satisfies(
562562
assert package.satisfies(dependency, ignore_source_type) == result
563563

564564

565+
@pytest.mark.parametrize(
566+
("package_repo", "dependency_repo", "result"),
567+
[
568+
("pypi", None, True),
569+
("private", None, True),
570+
("pypi", "pypi", True),
571+
("private", "private", True),
572+
("pypi", "private", False),
573+
("private", "pypi", False),
574+
],
575+
)
576+
def test_package_satisfies_on_repositories(
577+
package_repo: str,
578+
dependency_repo: str | None,
579+
result: bool,
580+
) -> None:
581+
source_type = None if package_repo == "pypi" else "legacy"
582+
source_reference = None if package_repo == "pypi" else package_repo
583+
package = Package(
584+
"foo", "0.1.0", source_type=source_type, source_reference=source_reference
585+
)
586+
587+
dependency = Dependency("foo", ">=0.1.0")
588+
dependency.source_name = dependency_repo
589+
590+
assert package.satisfies(dependency) == result
591+
592+
565593
def test_package_pep592_default_not_yanked() -> None:
566594
package = Package("foo", "1.0")
567595

0 commit comments

Comments
 (0)