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

locker: do not assign unrelated filenames/hashes to direct origin dependencies #6389

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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/poetry/packages/locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,18 @@ def locked_repository(self) -> Repository:
# Old lock so we create dummy files from the hashes
hashes = cast("dict[str, Any]", metadata["hashes"])
package.files = [{"name": h, "hash": h} for h in hashes[name]]
elif source_type in {"git", "directory", "url"}:
package.files = []
else:
files = metadata["files"][name]
package.files = files
if source_type == "file":
filename = Path(url).name
package.files = [item for item in files if item["file"] == filename]
else:
# Strictly speaking, this is not correct, but we have no chance
# to always determine which are the correct files because the
# lockfile doesn't keep track which files belong to which package.
package.files = files

package.python_versions = info["python-versions"]
extras = info.get("extras", {})
Expand Down
114 changes: 114 additions & 0 deletions tests/packages/test_locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,120 @@ def test_locker_properly_loads_subdir(locker: Locker) -> None:
assert package.source_subdirectory == "subdir"


def test_locker_properly_assigns_metadata_files(locker: Locker) -> None:
"""
For multiple constraints dependencies, there is only one common entry in
metadata.files. However, we must not assign all the files to each of the packages
because this can result in duplicated and outdated entries when running
`poetry lock --no-update` and hash check failures when running `poetry install`.
"""
content = """\
[[package]]
name = "demo"
version = "1.0"
description = ""
category = "main"
optional = false
python-versions = "*"
develop = false
[[package]]
name = "demo"
version = "1.0"
description = ""
category = "main"
optional = false
python-versions = "*"
develop = false
[package.source]
type = "git"
url = "https://github.com/demo/demo.git"
reference = "main"
resolved_reference = "123456"
[[package]]
name = "demo"
version = "1.0"
description = ""
category = "main"
optional = false
python-versions = "*"
develop = false
[package.source]
type = "directory"
url = "./folder"
[[package]]
name = "demo"
version = "1.0"
description = ""
category = "main"
optional = false
python-versions = "*"
develop = false
[package.source]
type = "file"
url = "./demo-1.0-cp39-win_amd64.whl"
[[package]]
name = "demo"
version = "1.0"
description = ""
category = "main"
optional = false
python-versions = "*"
develop = false
[package.source]
type = "url"
url = "https://example.com/demo-1.0-cp38-win_amd64.whl"
[metadata]
lock-version = "1.1"
python-versions = "*"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files]
# metadata.files are only tracked for non-direct origin and file dependencies
demo = [
{file = "demo-1.0-cp39-win_amd64.whl", hash = "sha256"},
{file = "demo-1.0.tar.gz", hash = "sha256"},
{file = "demo-1.0-py3-none-any.whl", hash = "sha256"},
]
"""
locker.lock.write(tomlkit.parse(content))

repository = locker.locked_repository()
assert len(repository.packages) == 5
assert {package.source_type for package in repository.packages} == {
None,
"git",
"directory",
"file",
"url",
}
for package in repository.packages:
if package.source_type is None:
# non-direct origin package contains all files
# with the current lockfile format we have no chance to determine
# which files are correct, so we keep all for hash check
# correct files are set later in Provider.complete_package()
assert package.files == [
{"file": "demo-1.0-cp39-win_amd64.whl", "hash": "sha256"},
{"file": "demo-1.0.tar.gz", "hash": "sha256"},
{"file": "demo-1.0-py3-none-any.whl", "hash": "sha256"},
]
elif package.source_type == "file":
assert package.files == [
{"file": "demo-1.0-cp39-win_amd64.whl", "hash": "sha256"}
]
else:
package.files = []


def test_lock_packages_with_null_description(locker: Locker, root: ProjectPackage):
package_a = get_package("A", "1.0.0")
package_a.description = None
Expand Down