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

Fix resolver when toplevel requirements are also in pinned subdependency #450

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion piptools/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
unicode_literals)

import os
import copy
from functools import partial
from itertools import chain, count

Expand Down Expand Up @@ -154,7 +155,8 @@ def _group_constraints(self, constraints):
continue

ireqs = iter(ireqs)
combined_ireq = next(ireqs)
# deepcopy the accumulator so as to not modify the self.our_constraints invariant
combined_ireq = copy.deepcopy(next(ireqs))
combined_ireq.comes_from = None
for ireq in ireqs:
# NOTE we may be losing some info on dropped reqs here
Expand Down
6 changes: 5 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from piptools.repositories.base import BaseRepository
from piptools.resolver import Resolver
from piptools.utils import as_tuple, key_from_req, make_install_requirement
from piptools.exceptions import NoCandidateFound


class FakeRepository(BaseRepository):
Expand All @@ -31,7 +32,10 @@ def find_best_match(self, ireq, prereleases=False):
if ireq.editable:
return ireq

versions = ireq.specifier.filter(self.index[key_from_req(ireq.req)], prereleases=prereleases)
versions = list(ireq.specifier.filter(self.index[key_from_req(ireq.req)],
prereleases=prereleases))
if not versions:
raise NoCandidateFound(ireq, self.index[key_from_req(ireq.req)])
best_version = max(versions, key=Version)
return make_install_requirement(key_from_req(ireq.req), best_version, ireq.extras)

Expand Down
29 changes: 25 additions & 4 deletions tests/fixtures/fake-index.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,32 @@
},
"amqp": {
"1.4.9": {"": []},
"2.0.2": {"": ["vine>=1.1.1"]}
"2.0.2": {"": ["vine>=1.1.1"]},
"2.1.4": {"": ["vine>=1.1.3"]}
},
"arrow": {
"0.5.0": {"": ["python-dateutil"]},
"0.5.4": {"": ["python-dateutil"]}
},
"billiard": {
"3.3.0.23": {"": []}
"3.3.0.23": {"": []},
"3.5.0.2": {"": []}
},
"celery": {
"3.1.18": {"": [
"kombu<3.1,>=3.0.25",
"pytz>dev",
"billiard<3.4,>=3.3.0.20"
]},
"3.1.23": {"": [
"kombu>=3.0.34",
"kombu>=3.0.34,<4",
"pytz>dev",
"billiard>=3.3.0.23"
]},
"4.0.2": {"": [
"kombu<5.0,>=4.0.2",
"pytz>dev",
"billiard<3.6.0,>=3.5.0.2"
]}
},
"click": {
Expand All @@ -29,6 +41,11 @@
"1.7.7": {"": []},
"1.8": {"": []}
},
"fake-piptools-test-with-pinned-deps": {
"0.1": {"": [
"celery==3.1.18"
]}
},
"flask": {
"0.10.1": {"": [
"Jinja2>=2.4",
Expand Down Expand Up @@ -76,6 +93,9 @@
"3.0.35": {"": [
"anyjson>=0.3.3",
"amqp>=1.4.9,<2.0"
]},
"4.0.2": {"": [
"amqp<3.0,>=2.1.4"
]}
},
"librabbitmq": {
Expand Down Expand Up @@ -113,7 +133,8 @@
"3.2.2": {"": []}
},
"vine": {
"1.1.1": {"": []}
"1.1.1": {"": []},
"1.1.3": {"": []}
},
"werkzeug": {
"0.6": {"": []},
Expand Down
32 changes: 24 additions & 8 deletions tests/test_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,31 @@

# We must remove child dependencies from result if parent is removed (e.g. vine from amqp>=2.0)
# See: GH-370
(['celery', 'librabbitmq'],
# because of upated dependencies in the test index, we need to pin celery
# in order to reproduce vine removal (because it was readded in later releases)
(['celery<=3.1.23', 'librabbitmq'],
[
'amqp==1.4.9',
'anyjson==0.3.3',
'billiard==3.3.0.23',
'celery==3.1.23',
'kombu==3.0.35',
'librabbitmq==1.6.1',
'pytz==2016.4']
'amqp==1.4.9',
'anyjson==0.3.3',
'billiard==3.5.0.2',
'celery==3.1.23',
'kombu==3.0.35',
'librabbitmq==1.6.1',
'pytz==2016.4']
),

# Support specifying loose top-level requirements that could also appear as
# pinned subdependencies.
(['billiard', 'celery',
'fake-piptools-test-with-pinned-deps'],
[
'amqp==1.4.9',
'anyjson==0.3.3',
'billiard==3.3.0.23',
'celery==3.1.18', # this is pinned from test subdependency
'fake-piptools-test-with-pinned-deps==0.1',
'kombu==3.0.35',
'pytz==2016.4']
),
])
)
Expand Down