Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Package.satisfies() considers sources more carefully #497

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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