Skip to content

Commit a0b2fa5

Browse files
authored
Package.satisfies() considers sources more carefully (#497)
1 parent 0759db6 commit a0b2fa5

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
@@ -556,16 +556,47 @@ def satisfies(
556556
"""
557557
Helper method to check if this package satisfies a given dependency.
558558
559-
This is determined by assessing if this instance provides the package and
560-
features specified by the given dependency. Further, version and source
561-
types are checked.
559+
This is determined by assessing if this instance provides the package specified
560+
by the given dependency. Further, version and source types are checked.
562561
"""
563-
if not self.provides(dependency) or not dependency.constraint.allows(
564-
self.version
565-
):
562+
if self.name != dependency.name:
563+
return False
564+
565+
if not dependency.constraint.allows(self.version):
566566
return False
567567

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

570601
def __eq__(self, other: object) -> bool:
571602
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)