Skip to content

Commit

Permalink
Package.satisfies() considers sources more carefully (#497)
Browse files Browse the repository at this point in the history
  • Loading branch information
dimbleby authored Oct 15, 2022
1 parent 0759db6 commit a0b2fa5
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 7 deletions.
45 changes: 38 additions & 7 deletions src/poetry/core/packages/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,16 +556,47 @@ def satisfies(
"""
Helper method to check if this package satisfies a given dependency.
This is determined by assessing if this instance provides the package and
features specified by the given dependency. Further, version and source
types are checked.
This is determined by assessing if this instance provides the package specified
by the given dependency. Further, version and source types are checked.
"""
if not self.provides(dependency) or not dependency.constraint.allows(
self.version
):
if self.name != dependency.name:
return False

if not dependency.constraint.allows(self.version):
return False

return ignore_source_type or self.is_same_source_as(dependency)
if not ignore_source_type and not self.source_satisfies(dependency):
return False

return True

def source_satisfies(self, dependency: Dependency) -> bool:
"""Determine whether this package's source satisfies the given dependency."""
if dependency.source_type is None:
if dependency.source_name is None:
# The dependency doesn't care about the source, so this package
# certainly satisfies it.
return True

# The dependency specifies a source_name but not a type: it wants either
# pypi or a legacy repository.
#
# - If this package has no source type then it's from pypi, so it
# matches if and only if that's what the dependency wants
# - Else this package is a match if and only if it is from the desired
# repository
if self.source_type is None:
return dependency.source_name.lower() == "pypi"

return (
self.source_type == "legacy"
and self.source_reference is not None
and self.source_reference.lower() == dependency.source_name.lower()
)

# The dependency specifies a source: this package matches if and only if it is
# from that source.
return dependency.is_same_source_as(self)

def __eq__(self, other: object) -> bool:
if not isinstance(other, Package):
Expand Down
28 changes: 28 additions & 0 deletions tests/packages/test_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,34 @@ def test_package_satisfies(
assert package.satisfies(dependency, ignore_source_type) == result


@pytest.mark.parametrize(
("package_repo", "dependency_repo", "result"),
[
("pypi", None, True),
("private", None, True),
("pypi", "pypi", True),
("private", "private", True),
("pypi", "private", False),
("private", "pypi", False),
],
)
def test_package_satisfies_on_repositories(
package_repo: str,
dependency_repo: str | None,
result: bool,
) -> None:
source_type = None if package_repo == "pypi" else "legacy"
source_reference = None if package_repo == "pypi" else package_repo
package = Package(
"foo", "0.1.0", source_type=source_type, source_reference=source_reference
)

dependency = Dependency("foo", ">=0.1.0")
dependency.source_name = dependency_repo

assert package.satisfies(dependency) == result


def test_package_pep592_default_not_yanked() -> None:
package = Package("foo", "1.0")

Expand Down

0 comments on commit a0b2fa5

Please sign in to comment.