From 4e440723cdf904a590e5f12e6d00c9da3f2ab54a Mon Sep 17 00:00:00 2001 From: Micah Denbraver Date: Mon, 6 May 2024 22:48:39 -0700 Subject: [PATCH 01/10] hack to prevent editable transformation --- piptools/_compat/pip_compat.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/piptools/_compat/pip_compat.py b/piptools/_compat/pip_compat.py index 6409fbc2a..27005bda0 100644 --- a/piptools/_compat/pip_compat.py +++ b/piptools/_compat/pip_compat.py @@ -10,6 +10,7 @@ from pip._internal.metadata import BaseDistribution from pip._internal.metadata.pkg_resources import Distribution as _PkgResourcesDist from pip._internal.models.direct_url import DirectUrl +from pip._internal.models.link import Link from pip._internal.network.session import PipSession from pip._internal.req import InstallRequirement from pip._internal.req import parse_requirements as _parse_requirements @@ -62,6 +63,12 @@ def _from_importlib(cls, dist: _ImportLibDist) -> Distribution: ] return cls(dist._dist.name, dist._dist.version, requires, dist.direct_url) +class FileLink(Link): + + @property + def file_path(self) -> str: + # overriding the actual property to bypass some validation + return self._url def parse_requirements( filename: str, @@ -74,7 +81,14 @@ def parse_requirements( for parsed_req in _parse_requirements( filename, session, finder=finder, options=options, constraint=constraint ): - yield install_req_from_parsed_requirement(parsed_req, isolated=isolated) + install_req = install_req_from_parsed_requirement(parsed_req, isolated=isolated) + if install_req.editable: + # link.url is what is saved to the output file + # we set the url directly to undo the transformation in pip's Link class + file_link = FileLink(install_req.link.url) + file_link._url = parsed_req.requirement + install_req.link = file_link + yield install_req def create_wheel_cache(cache_dir: str, format_control: str | None = None) -> WheelCache: From 0215a8432761153047b7c8ddf4f1c7d4c529adb5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 05:51:09 +0000 Subject: [PATCH 02/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- piptools/_compat/pip_compat.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/piptools/_compat/pip_compat.py b/piptools/_compat/pip_compat.py index 27005bda0..5af1d69d6 100644 --- a/piptools/_compat/pip_compat.py +++ b/piptools/_compat/pip_compat.py @@ -63,6 +63,7 @@ def _from_importlib(cls, dist: _ImportLibDist) -> Distribution: ] return cls(dist._dist.name, dist._dist.version, requires, dist.direct_url) + class FileLink(Link): @property @@ -70,6 +71,7 @@ def file_path(self) -> str: # overriding the actual property to bypass some validation return self._url + def parse_requirements( filename: str, session: PipSession, From 16a4a600a7ccfea278a4806e26abacf7fae7764b Mon Sep 17 00:00:00 2001 From: Micah Denbraver Date: Mon, 6 May 2024 23:21:43 -0700 Subject: [PATCH 03/10] leave originally url-based dependencies alone --- piptools/_compat/pip_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/piptools/_compat/pip_compat.py b/piptools/_compat/pip_compat.py index 5af1d69d6..357346881 100644 --- a/piptools/_compat/pip_compat.py +++ b/piptools/_compat/pip_compat.py @@ -84,7 +84,7 @@ def parse_requirements( filename, session, finder=finder, options=options, constraint=constraint ): install_req = install_req_from_parsed_requirement(parsed_req, isolated=isolated) - if install_req.editable: + if install_req.editable and not parsed_req.requirement.startswith('file://'): # link.url is what is saved to the output file # we set the url directly to undo the transformation in pip's Link class file_link = FileLink(install_req.link.url) From f83bd91b18ceb68d7af5f69d03d058a16268763e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 06:22:50 +0000 Subject: [PATCH 04/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- piptools/_compat/pip_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/piptools/_compat/pip_compat.py b/piptools/_compat/pip_compat.py index 357346881..6b4479e10 100644 --- a/piptools/_compat/pip_compat.py +++ b/piptools/_compat/pip_compat.py @@ -84,7 +84,7 @@ def parse_requirements( filename, session, finder=finder, options=options, constraint=constraint ): install_req = install_req_from_parsed_requirement(parsed_req, isolated=isolated) - if install_req.editable and not parsed_req.requirement.startswith('file://'): + if install_req.editable and not parsed_req.requirement.startswith("file://"): # link.url is what is saved to the output file # we set the url directly to undo the transformation in pip's Link class file_link = FileLink(install_req.link.url) From 84fda5b21d97b9227c16f8f2eec6714dd2911188 Mon Sep 17 00:00:00 2001 From: Micah Denbraver Date: Tue, 7 May 2024 09:44:05 -0700 Subject: [PATCH 05/10] add a test --- tests/constants.py | 3 +++ tests/test_pip_compat.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/test_pip_compat.py diff --git a/tests/constants.py b/tests/constants.py index 0a33a278a..3bbfa0bf8 100644 --- a/tests/constants.py +++ b/tests/constants.py @@ -5,3 +5,6 @@ TEST_DATA_PATH = os.path.join(os.path.dirname(__file__), "test_data") MINIMAL_WHEELS_PATH = os.path.join(TEST_DATA_PATH, "minimal_wheels") PACKAGES_PATH = os.path.join(TEST_DATA_PATH, "packages") +PACKAGES_RELATIVE_PATH = os.path.relpath( + PACKAGES_PATH, os.path.commonpath([os.getcwd(), PACKAGES_PATH]) +) diff --git a/tests/test_pip_compat.py b/tests/test_pip_compat.py new file mode 100644 index 000000000..caa36499c --- /dev/null +++ b/tests/test_pip_compat.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +import os +import tempfile + +import pytest + +from piptools._compat.pip_compat import parse_requirements +from piptools.repositories import PyPIRepository + +from .constants import PACKAGES_RELATIVE_PATH + + +@pytest.fixture +def repository(): + with tempfile.TemporaryDirectory() as cache_dir: + yield PyPIRepository([], cache_dir=cache_dir) + + +def test_parse_requirements_preserve_editable_relative(repository): + test_package_path = os.path.join(PACKAGES_RELATIVE_PATH, "small_fake_a") + + with tempfile.NamedTemporaryFile("w") as infile: + infile.write(f"-e {test_package_path}") + infile.flush() + [install_requirement] = parse_requirements( + infile.name, session=repository.session + ) + + assert install_requirement.link.url == test_package_path + assert install_requirement.link.file_path == test_package_path From 8a2a9e6f6d1edef0f640de415b4601ceb52b7bc8 Mon Sep 17 00:00:00 2001 From: Micah Denbraver Date: Tue, 7 May 2024 10:36:50 -0700 Subject: [PATCH 06/10] fix test for windows --- tests/test_pip_compat.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/test_pip_compat.py b/tests/test_pip_compat.py index caa36499c..da08151a5 100644 --- a/tests/test_pip_compat.py +++ b/tests/test_pip_compat.py @@ -2,6 +2,7 @@ import os import tempfile +from pathlib import Path, PurePosixPath import pytest @@ -11,21 +12,21 @@ from .constants import PACKAGES_RELATIVE_PATH -@pytest.fixture -def repository(): - with tempfile.TemporaryDirectory() as cache_dir: - yield PyPIRepository([], cache_dir=cache_dir) - - def test_parse_requirements_preserve_editable_relative(repository): - test_package_path = os.path.join(PACKAGES_RELATIVE_PATH, "small_fake_a") + test_package_path = str( + PurePosixPath(Path(PACKAGES_RELATIVE_PATH)) / "small_fake_a" + ) - with tempfile.NamedTemporaryFile("w") as infile: + infile = tempfile.NamedTemporaryFile("w", delete=False) + try: infile.write(f"-e {test_package_path}") - infile.flush() + infile.close() + [install_requirement] = parse_requirements( infile.name, session=repository.session ) + finally: + os.unlink(infile.name) assert install_requirement.link.url == test_package_path assert install_requirement.link.file_path == test_package_path From 7dbd5273f24d764ff43942b2045a612cec65bf1e Mon Sep 17 00:00:00 2001 From: Micah Denbraver Date: Wed, 8 May 2024 12:28:50 -0700 Subject: [PATCH 07/10] Update comment per review Co-authored-by: chrysle <96722107+chrysle@users.noreply.github.com> --- piptools/_compat/pip_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/piptools/_compat/pip_compat.py b/piptools/_compat/pip_compat.py index 6b4479e10..a5f843ad9 100644 --- a/piptools/_compat/pip_compat.py +++ b/piptools/_compat/pip_compat.py @@ -85,7 +85,7 @@ def parse_requirements( ): install_req = install_req_from_parsed_requirement(parsed_req, isolated=isolated) if install_req.editable and not parsed_req.requirement.startswith("file://"): - # link.url is what is saved to the output file + # ``Link.url`` is what is saved to the output file # we set the url directly to undo the transformation in pip's Link class file_link = FileLink(install_req.link.url) file_link._url = parsed_req.requirement From 7a8972e8c0779f548c06a39711a2e0f98883ba3f Mon Sep 17 00:00:00 2001 From: Micah Denbraver Date: Wed, 8 May 2024 12:29:16 -0700 Subject: [PATCH 08/10] update test name for clarity Co-authored-by: chrysle <96722107+chrysle@users.noreply.github.com> --- tests/test_pip_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_pip_compat.py b/tests/test_pip_compat.py index da08151a5..451ba9b3b 100644 --- a/tests/test_pip_compat.py +++ b/tests/test_pip_compat.py @@ -12,7 +12,7 @@ from .constants import PACKAGES_RELATIVE_PATH -def test_parse_requirements_preserve_editable_relative(repository): +def test_parse_requirements_preserve_editable_relative_path(repository): test_package_path = str( PurePosixPath(Path(PACKAGES_RELATIVE_PATH)) / "small_fake_a" ) From 3a9302ed977be9d55ef588a5797596e9b04e19cf Mon Sep 17 00:00:00 2001 From: Micah Denbraver Date: Wed, 8 May 2024 12:36:43 -0700 Subject: [PATCH 09/10] use pytest's `tmp_path` for more information, see https://pre-commit.ci --- tests/test_pip_compat.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/tests/test_pip_compat.py b/tests/test_pip_compat.py index 451ba9b3b..edc008395 100644 --- a/tests/test_pip_compat.py +++ b/tests/test_pip_compat.py @@ -12,21 +12,18 @@ from .constants import PACKAGES_RELATIVE_PATH -def test_parse_requirements_preserve_editable_relative_path(repository): +def test_parse_requirements_preserve_editable_relative_path(tmp_path, repository): test_package_path = str( PurePosixPath(Path(PACKAGES_RELATIVE_PATH)) / "small_fake_a" ) + requirements_in_path = str(tmp_path / "requirements.in") - infile = tempfile.NamedTemporaryFile("w", delete=False) - try: - infile.write(f"-e {test_package_path}") - infile.close() + with open(requirements_in_path, 'w') as requirements_in_file: + requirements_in_file.write(f"-e {test_package_path}") - [install_requirement] = parse_requirements( - infile.name, session=repository.session - ) - finally: - os.unlink(infile.name) + [install_requirement] = parse_requirements( + requirements_in_path, session=repository.session + ) assert install_requirement.link.url == test_package_path assert install_requirement.link.file_path == test_package_path From 0bb0082156a7cbc22b55e7b2f6aa6916b89e4f2b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 8 May 2024 19:40:35 +0000 Subject: [PATCH 10/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_pip_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_pip_compat.py b/tests/test_pip_compat.py index edc008395..583addfb9 100644 --- a/tests/test_pip_compat.py +++ b/tests/test_pip_compat.py @@ -18,7 +18,7 @@ def test_parse_requirements_preserve_editable_relative_path(tmp_path, repository ) requirements_in_path = str(tmp_path / "requirements.in") - with open(requirements_in_path, 'w') as requirements_in_file: + with open(requirements_in_path, "w") as requirements_in_file: requirements_in_file.write(f"-e {test_package_path}") [install_requirement] = parse_requirements(