Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing issue with losing data about local files #1385

9 changes: 9 additions & 0 deletions piptools/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ def combine_install_requirements(
# Return a sorted, de-duped tuple of extras
combined_ireq.extras = tuple(sorted({*combined_ireq.extras, *ireq.extras}))

if ireq.link and combined_ireq.link is None:
combined_ireq.link = ireq.link

if ireq.local_file_path and combined_ireq.local_file_path is None:
combined_ireq.local_file_path = ireq.local_file_path

if ireq.original_link and combined_ireq.original_link is None:
combined_ireq.original_link = ireq.original_link

# InstallRequirements objects are assumed to come from only one source, and
# so they support only a single comes_from entry. This function breaks this
# model. As a workaround, we deterministically choose a single source for
Expand Down
7 changes: 6 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
make_install_requirement,
)

from .constants import MINIMAL_WHEELS_PATH
from .constants import MINIMAL_WHEELS_PATH, PACKAGES_PATH
from .utils import looks_like_ci


Expand All @@ -43,6 +43,11 @@ def __init__(self):

with open("tests/test_data/fake-editables.json") as f:
self.editables = json.load(f)
self.editables[
self.editables["fake_with_local_files"].format(
os.path.join(PACKAGES_PATH)
)
] = []

def get_hashes(self, ireq):
# Some fake hashes
Expand Down
1 change: 1 addition & 0 deletions tests/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
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")
NON_LINKED_PACKAGES_PATH = os.path.join(TEST_DATA_PATH, "non_linked_wheel_file")
3 changes: 2 additions & 1 deletion tests/test_data/fake-editables.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"git+git://example.org/django.git#egg=django": [],
"git+https://github.com/celery/billiard#egg=billiard==3.5.9999": []
"git+https://github.com/celery/billiard#egg=billiard==3.5.9999": [],
"fake_with_local_files": "file://localhost/{}/fake_with_local_files/setup.py"
}
Binary file not shown.
15 changes: 15 additions & 0 deletions tests/test_data/packages/fake_with_local_files/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import os

from setuptools import setup

from .constants import NON_LINKED_PACKAGES_PATH

setup(
name="fake with local files as dependencies",
version=0.1,
install_requires=[
"fake_package_a @ file://localhost/{}/fake_package_a-0.1-py2.py3-none-any.whl".format(
os.path.join(NON_LINKED_PACKAGES_PATH)
)
],
)
23 changes: 23 additions & 0 deletions tests/test_resolver.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import os

import pytest

from piptools.exceptions import NoCandidateFound
from piptools.resolver import RequirementSummary, combine_install_requirements

from .constants import PACKAGES_PATH


@pytest.mark.parametrize(
("input", "expected", "prereleases", "unsafe_constraints"),
Expand Down Expand Up @@ -299,6 +303,25 @@ def test_combine_install_requirements(repository, from_line):
assert str(combined_all.req.specifier) == "<3.2,==3.1.1,>3.0"


def test_combine_install_requirements_with_local_files(repository, from_line):
fake_package = from_line(
"fake_package_a @ file://localhost/"
+ os.path.join(PACKAGES_PATH, "fake_with_local_files", "setup.py"),
comes_from="-r requirements.in",
)
fake_package_name = from_line(
"fake_package_a==1.0.0", comes_from=from_line("fake_package_a")
)

combined_all = combine_install_requirements(
repository, [fake_package, fake_package_name]
)
assert str(combined_all.req.specifier) == "==1.0.0"
assert str(combined_all.link) == str(fake_package.link)
assert str(combined_all.local_file_path) == str(fake_package.local_file_path)
assert str(combined_all.original_link) == str(fake_package.original_link)


def test_compile_failure_shows_provenance(resolver, from_line):
"""
Provenance of conflicting dependencies should be printed on failure.
Expand Down