Skip to content

Commit

Permalink
Add a MinimalUpgradeRepository class to implement the --no-upgrade flag.
Browse files Browse the repository at this point in the history
If we have an existing pin that would satisfy a requirement, return
that as a best match; otherwise, ask the proxied repository for the
best match.
  • Loading branch information
ejames committed Jan 19, 2016
1 parent 1fec534 commit 1a1ec83
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 0 deletions.
1 change: 1 addition & 0 deletions piptools/repositories/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# flake8: noqa
from .pypi import PyPIRepository
from .minimal_upgrade import MinimalUpgradeRepository
33 changes: 33 additions & 0 deletions piptools/repositories/minimal_upgrade.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# coding: utf-8
from __future__ import (absolute_import, division, print_function,
unicode_literals)

from .base import BaseRepository


class MinimalUpgradeRepository(BaseRepository):
"""
The MinimalUpgradeRepository uses a provided requirements file as a proxy
in front of a repository. If a requirement can be satisfied with
a version pinned in the requirements file, we use that version as the best
match. In all other cases, the proxied repository is used instead.
"""
def __init__(self, existing_pins, proxied_repository):
self.repository = proxied_repository
self.existing_pins = existing_pins

def clear_caches(self):
self.repository.clear_caches()

def freshen_build_caches(self):
self.repository.freshen_build_caches()

def find_best_match(self, ireq, prereleases=None):
existing_pin = self.existing_pins.get(ireq.req.project_name.lower())
if existing_pin and existing_pin.req.specs[0][1] in ireq.req:
return existing_pin
else:
return self.repository.find_best_match(ireq, prereleases)

def get_dependencies(self, ireq):
return self.repository.get_dependencies(ireq)
5 changes: 5 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ def resolver(depcache, repository):
return partial(Resolver, repository=repository, cache=depcache)


@fixture
def minimal_resolver(depcache):
return partial(Resolver, cache=depcache)


@fixture
def from_line():
return InstallRequirement.from_line
Expand Down
1 change: 1 addition & 0 deletions tests/fixtures/fake-index.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"3.2.2": {"": []}
},
"werkzeug": {
"0.6": {"": []},
"0.10": {"": []},
"0.10.4": {"": []}
}
Expand Down
38 changes: 38 additions & 0 deletions tests/test_minimal_upgrade.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pytest

from piptools.repositories import MinimalUpgradeRepository


@pytest.mark.parametrize(
('input', 'pins', 'expected'),
((tup) for tup in [
# Add Flask to an existing requirements.in, using --no-upgrade
(['flask', 'jinja2', 'werkzeug'],
[
# The requirements.txt from a previous round
'jinja2==2.7.3',
'markupsafe==0.23',
'werkzeug==0.6'],
[
# Add flask and upgrade werkzeug from incompatible 0.6
'flask==0.10.1',
'itsdangerous==0.24',
'werkzeug==0.10.4',
# Other requirements are unchanged from the original requirements.txt
'jinja2==2.7.3',
'markupsafe==0.23']
),
])
)
def test_minimal_upgrade(minimal_resolver, repository, from_line, input, pins, expected):
input = [from_line(line) for line in input]
existing_pins = dict()
for line in pins:
ireq = from_line(line)
existing_pins[ireq.req.project_name] = ireq
minimal_repository = MinimalUpgradeRepository(existing_pins, repository)
output = minimal_resolver(input, prereleases=False, repository=minimal_repository).resolve()
output = {str(line) for line in output}
assert output == {str(line) for line in expected}

0 comments on commit 1a1ec83

Please sign in to comment.