Skip to content

Commit

Permalink
handle poetry 1.1 lock content hash (#5458)
Browse files Browse the repository at this point in the history
This change ensures that content-hash generated by poetry < 1.2 does
not trigger unnecessary warnings and operations. We do this by using a
backwards compatible hashing logic.
  • Loading branch information
abn authored Apr 16, 2022
1 parent 819d6d4 commit fb52c98
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 14 deletions.
14 changes: 8 additions & 6 deletions src/poetry/packages/locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ class Locker:

_VERSION = "1.1"

_relevant_keys = ["dependencies", "group", "source", "extras"]
_legacy_keys = ["dependencies", "source", "extras", "dev-dependencies"]
_relevant_keys = [*_legacy_keys, "group"]

def __init__(self, lock: str | Path, local_config: dict) -> None:
self._lock = TOMLFile(lock)
Expand Down Expand Up @@ -428,13 +429,14 @@ def _get_content_hash(self) -> str:

relevant_content = {}
for key in self._relevant_keys:
relevant_content[key] = content.get(key)
data = content.get(key)

content_hash = sha256(
json.dumps(relevant_content, sort_keys=True).encode()
).hexdigest()
if data is None and key not in self._legacy_keys:
continue

relevant_content[key] = data

return content_hash
return sha256(json.dumps(relevant_content, sort_keys=True).encode()).hexdigest()

def _get_lock_data(self) -> TOMLDocument:
if not self._lock.exists():
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/up_to_date_lock/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 53 additions & 7 deletions tests/packages/test_locker.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from __future__ import annotations

import json
import logging
import tempfile
import uuid

from hashlib import sha256
from pathlib import Path
from typing import TYPE_CHECKING

Expand Down Expand Up @@ -94,7 +97,7 @@ def test_lock_file_data_is_ordered(locker: Locker, root: ProjectPackage):
[metadata]
lock-version = "1.1"
python-versions = "*"
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files]
A = [
Expand Down Expand Up @@ -303,7 +306,7 @@ def test_lock_packages_with_null_description(locker: Locker, root: ProjectPackag
[metadata]
lock-version = "1.1"
python-versions = "*"
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files]
A = []
Expand Down Expand Up @@ -343,7 +346,7 @@ def test_lock_file_should_not_have_mixed_types(locker: Locker, root: ProjectPack
[metadata]
lock-version = "1.1"
python-versions = "*"
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files]
A = []
Expand Down Expand Up @@ -373,7 +376,7 @@ def test_reading_lock_file_should_raise_an_error_on_invalid_data(locker: Locker)
[metadata]
lock-version = "1.1"
python-versions = "*"
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files]
A = []
Expand Down Expand Up @@ -420,7 +423,7 @@ def test_locking_legacy_repository_package_should_include_source_section(
[metadata]
lock-version = "1.1"
python-versions = "*"
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files]
A = []
Expand Down Expand Up @@ -504,7 +507,7 @@ def test_extras_dependencies_are_ordered(locker: Locker, root: ProjectPackage):
[metadata]
lock-version = "1.1"
python-versions = "*"
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files]
A = []
Expand Down Expand Up @@ -598,7 +601,7 @@ def test_locker_dumps_dependency_information_correctly(
[metadata]
lock-version = "1.1"
python-versions = "*"
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files]
A = []
Expand Down Expand Up @@ -651,3 +654,46 @@ def test_locked_repository_uses_root_dir_of_package(
assert root_dir.match("*/lib/libA")
# relative_to raises an exception if not relative - is_relative_to comes in py3.9
assert root_dir.relative_to(locker.lock.path.parent.resolve()) is not None


@pytest.mark.parametrize(
("local_config", "fresh"),
[
({}, True),
({"dependencies": [uuid.uuid4().hex]}, True),
(
{
"dependencies": [uuid.uuid4().hex],
"dev-dependencies": [uuid.uuid4().hex],
},
True,
),
(
{
"dependencies": [uuid.uuid4().hex],
"dev-dependencies": None,
},
True,
),
({"dependencies": [uuid.uuid4().hex], "groups": [uuid.uuid4().hex]}, False),
],
)
def test_content_hash_with_legacy_is_compatible(
local_config: dict[str, list[str]], fresh: bool, locker: Locker
) -> None:
# old hash generation
relevant_content = {}
for key in locker._legacy_keys:
relevant_content[key] = local_config.get(key)

locker = locker.__class__(
lock=locker.lock.path,
local_config=local_config,
)

old_content_hash = sha256(
json.dumps(relevant_content, sort_keys=True).encode()
).hexdigest()
content_hash = locker._get_content_hash()

assert (content_hash == old_content_hash) or fresh

0 comments on commit fb52c98

Please sign in to comment.