Skip to content

Commit

Permalink
locker: do not assign unrelated filenames/hashes to direct origin dep…
Browse files Browse the repository at this point in the history
…endencies when used in multiple constraints dependencies
  • Loading branch information
radoering committed Sep 4, 2022
1 parent 58d2b99 commit b183e83
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 1 deletion.
14 changes: 13 additions & 1 deletion src/poetry/packages/locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,21 @@ 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":
if len(files) > 1:
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

0 comments on commit b183e83

Please sign in to comment.