From 733736cd1c2ea6189a77e34ab640059dbff2be23 Mon Sep 17 00:00:00 2001 From: Arun Babu Neelicattu Date: Tue, 13 Oct 2020 20:01:18 +0200 Subject: [PATCH] locker: unify duplicate dependencies on export --- poetry/packages/locker.py | 19 +++++++++++++------ tests/utils/test_exporter.py | 18 +++++++----------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/poetry/packages/locker.py b/poetry/packages/locker.py index 50074a4417a..9113a303673 100644 --- a/poetry/packages/locker.py +++ b/poetry/packages/locker.py @@ -1,4 +1,3 @@ -import itertools import json import logging import os @@ -6,6 +5,7 @@ from copy import deepcopy from hashlib import sha256 +from typing import Iterable from typing import Iterator from typing import List from typing import Optional @@ -188,7 +188,7 @@ def locked_repository( @classmethod def get_project_dependencies( cls, project_requires, locked_packages, pinned_versions=False, with_nested=False - ): # type: (List[Dependency], List[Package], bool, bool) -> List[Dependency] + ): # type: (List[Dependency], List[Package], bool, bool) -> Iterable[Dependency] # group packages entries by name, this is required because requirement might use # different constraints packages_by_name = {} @@ -296,10 +296,17 @@ def __walk_level( __walk_level(dependencies, 0) - return sorted( - itertools.chain(dependencies, nested_dependencies.values()), - key=lambda x: x.name.lower(), - ) + # Merge same dependencies using marker union + for requirement in dependencies: + key = (requirement.name, requirement.pretty_constraint) + if key not in nested_dependencies: + nested_dependencies[key] = requirement + else: + nested_dependencies[key].marker = nested_dependencies[key].marker.union( + requirement.marker + ) + + return sorted(nested_dependencies.values(), key=lambda x: x.name.lower()) def get_project_dependency_packages( self, project_requires, dev=False, extras=None diff --git a/tests/utils/test_exporter.py b/tests/utils/test_exporter.py index 0cf6f9a202e..d810bb8b08b 100644 --- a/tests/utils/test_exporter.py +++ b/tests/utils/test_exporter.py @@ -256,8 +256,12 @@ def test_exporter_can_export_requirements_txt_with_nested_packages_and_markers( assert expected == {} +@pytest.mark.parametrize( + "dev,lines", + [(False, ['a==1.2.3; python_version < "3.8"']), (True, ["a==1.2.3", "b==4.5.6"])], +) def test_exporter_can_export_requirements_txt_with_nested_packages_and_markers_any( - tmp_dir, poetry + tmp_dir, poetry, dev, lines ): poetry.locker.mock_lock_data( { @@ -295,24 +299,16 @@ def test_exporter_can_export_requirements_txt_with_nested_packages_and_markers_a Factory.create_dependency( name="b", constraint=dict(version="^4.5.6"), category="dev" ), - Factory.create_dependency(name="a", constraint=dict(version="^1.2.3")), ] exporter = Exporter(poetry) - exporter.export("requirements.txt", Path(tmp_dir), "requirements.txt", dev=True) + exporter.export("requirements.txt", Path(tmp_dir), "requirements.txt", dev=dev) with (Path(tmp_dir) / "requirements.txt").open(encoding="utf-8") as f: content = f.read() - assert ( - content - == """\ -a==1.2.3 -a==1.2.3; python_version < "3.8" -b==4.5.6 -""" - ) + assert content.strip() == "\n".join(lines) def test_exporter_can_export_requirements_txt_with_standard_packages_and_hashes(