Skip to content

Commit ab97244

Browse files
committed
handle poetry 1.1 lock content hash
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.
1 parent 819d6d4 commit ab97244

File tree

3 files changed

+62
-14
lines changed

3 files changed

+62
-14
lines changed

src/poetry/packages/locker.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ class Locker:
4646

4747
_VERSION = "1.1"
4848

49-
_relevant_keys = ["dependencies", "group", "source", "extras"]
49+
_legacy_keys = ["dependencies", "source", "extras", "dev-dependencies"]
50+
_relevant_keys = [*_legacy_keys, "group"]
5051

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

429430
relevant_content = {}
430431
for key in self._relevant_keys:
431-
relevant_content[key] = content.get(key)
432+
data = content.get(key)
432433

433-
content_hash = sha256(
434-
json.dumps(relevant_content, sort_keys=True).encode()
435-
).hexdigest()
434+
if data is None and key not in self._legacy_keys:
435+
continue
436+
437+
relevant_content[key] = data
436438

437-
return content_hash
439+
return sha256(json.dumps(relevant_content, sort_keys=True).encode()).hexdigest()
438440

439441
def _get_lock_data(self) -> TOMLDocument:
440442
if not self._lock.exists():

tests/fixtures/up_to_date_lock/poetry.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/packages/test_locker.py

+53-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
from __future__ import annotations
22

3+
import json
34
import logging
45
import tempfile
6+
import uuid
57

8+
from hashlib import sha256
69
from pathlib import Path
710
from typing import TYPE_CHECKING
811

@@ -94,7 +97,7 @@ def test_lock_file_data_is_ordered(locker: Locker, root: ProjectPackage):
9497
[metadata]
9598
lock-version = "1.1"
9699
python-versions = "*"
97-
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
100+
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
98101
99102
[metadata.files]
100103
A = [
@@ -303,7 +306,7 @@ def test_lock_packages_with_null_description(locker: Locker, root: ProjectPackag
303306
[metadata]
304307
lock-version = "1.1"
305308
python-versions = "*"
306-
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
309+
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
307310
308311
[metadata.files]
309312
A = []
@@ -343,7 +346,7 @@ def test_lock_file_should_not_have_mixed_types(locker: Locker, root: ProjectPack
343346
[metadata]
344347
lock-version = "1.1"
345348
python-versions = "*"
346-
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
349+
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
347350
348351
[metadata.files]
349352
A = []
@@ -373,7 +376,7 @@ def test_reading_lock_file_should_raise_an_error_on_invalid_data(locker: Locker)
373376
[metadata]
374377
lock-version = "1.1"
375378
python-versions = "*"
376-
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
379+
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
377380
378381
[metadata.files]
379382
A = []
@@ -420,7 +423,7 @@ def test_locking_legacy_repository_package_should_include_source_section(
420423
[metadata]
421424
lock-version = "1.1"
422425
python-versions = "*"
423-
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
426+
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
424427
425428
[metadata.files]
426429
A = []
@@ -504,7 +507,7 @@ def test_extras_dependencies_are_ordered(locker: Locker, root: ProjectPackage):
504507
[metadata]
505508
lock-version = "1.1"
506509
python-versions = "*"
507-
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
510+
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
508511
509512
[metadata.files]
510513
A = []
@@ -598,7 +601,7 @@ def test_locker_dumps_dependency_information_correctly(
598601
[metadata]
599602
lock-version = "1.1"
600603
python-versions = "*"
601-
content-hash = "178f2cd01dc40e96be23a4a0ae1094816626346346618335e5ff4f0b2c0c5831"
604+
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
602605
603606
[metadata.files]
604607
A = []
@@ -651,3 +654,46 @@ def test_locked_repository_uses_root_dir_of_package(
651654
assert root_dir.match("*/lib/libA")
652655
# relative_to raises an exception if not relative - is_relative_to comes in py3.9
653656
assert root_dir.relative_to(locker.lock.path.parent.resolve()) is not None
657+
658+
659+
@pytest.mark.parametrize(
660+
("local_config", "fresh"),
661+
[
662+
({}, True),
663+
({"dependencies": [uuid.uuid4().hex]}, True),
664+
(
665+
{
666+
"dependencies": [uuid.uuid4().hex],
667+
"dev-dependencies": [uuid.uuid4().hex],
668+
},
669+
True,
670+
),
671+
(
672+
{
673+
"dependencies": [uuid.uuid4().hex],
674+
"dev-dependencies": None,
675+
},
676+
True,
677+
),
678+
({"dependencies": [uuid.uuid4().hex], "groups": [uuid.uuid4().hex]}, False),
679+
],
680+
)
681+
def test_content_hash_with_legacy_is_compatible(
682+
local_config: dict[str, list[str]], fresh: bool, locker: Locker
683+
) -> None:
684+
# old hash generation
685+
relevant_content = {}
686+
for key in locker._legacy_keys:
687+
relevant_content[key] = local_config.get(key)
688+
689+
locker = locker.__class__(
690+
lock=locker.lock.path,
691+
local_config=local_config,
692+
)
693+
694+
old_content_hash = sha256(
695+
json.dumps(relevant_content, sort_keys=True).encode()
696+
).hexdigest()
697+
content_hash = locker._get_content_hash()
698+
699+
assert (content_hash == old_content_hash) or fresh

0 commit comments

Comments
 (0)