Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/allow-pip-sync-to-resolve-to-bra…
Browse files Browse the repository at this point in the history
…nch-versions-when-pinned'
  • Loading branch information
Stephen Collinson committed Jun 26, 2018
2 parents 68fb70b + 4b00760 commit 697249f
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 13 deletions.
45 changes: 33 additions & 12 deletions piptools/repositories/pypi.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@
from contextlib import contextmanager
from shutil import rmtree

# packaging is in a different place in some pkg_resources
try:
from pkg_resources.extern import packaging
except ImportError:
from pkg_resources._vendor import packaging

from pip.download import is_file_url, url_to_path
from pip.index import PackageFinder
Expand All @@ -27,6 +22,24 @@
from .base import BaseRepository


def remove_dev_local(candidate, prefer_local):
"""
We utilise .dev and
:param versions:
:return:
"""
version = candidate.version
if prefer_local and version.local == prefer_local:
public = version.public
devN = public.find('.dev')
if devN > 0:
public = public[:devN]
else:
public = str(version)

return public


class PyPIRepository(BaseRepository):
DEFAULT_INDEX_URL = 'https://pypi.python.org/simple'

Expand Down Expand Up @@ -103,12 +116,23 @@ def find_best_match(self, ireq, prereleases=None, prefer_local=""):
return ireq # return itself as the best match

all_candidates = self.find_all_candidates(ireq.name)
candidates_by_version = lookup_table(all_candidates, key=lambda c: c.version, unique=True)
matching_versions = ireq.specifier.filter((candidate.version for candidate in all_candidates),

matching_versions = ireq.specifier.filter((remove_dev_local(x, prefer_local) for x in all_candidates),
prereleases=prereleases)

# It's possible we will have multiple matching versions that appear equivalent, so we can't use a simple
# dictionary lookup. We need to iterate both lists and, assuming matching_versions is ordered the same as
# it's input, we can find our original candidates
matching_candidates = []
i = 0
for matched_version in matching_versions:
for candidate in list(all_candidates[i:]):
i += 1
if remove_dev_local(candidate, prefer_local) == matched_version:
matching_candidates.append(candidate)
break

# Reuses pip's internal candidate sort key to sort
matching_candidates = [candidates_by_version[ver] for ver in matching_versions]
if not matching_candidates:
raise NoCandidateFound(ireq, all_candidates, self.finder)

Expand All @@ -123,14 +147,11 @@ def find_best_match(self, ireq, prereleases=None, prefer_local=""):
sorted_candidates = sorted(matching_candidates, key=self.finder._candidate_sort_key, reverse=True)
best_candidate = None
if prefer_local:
# PIP normalises wheel names so we do the same to prefer_local such tha it will match
fake_version = packaging.version.Version("0+{}".format(prefer_local))
normalised_prefer_local = str(fake_version).split("+")[-1]
for install_candidate in sorted_candidates:
candidate_version = str(install_candidate.version)
if "+" in candidate_version:
version, candidate_local_suffix = candidate_version.split("+")
if normalised_prefer_local == candidate_local_suffix:
if prefer_local == candidate_local_suffix:
best_candidate = install_candidate
break # We're done

Expand Down
2 changes: 1 addition & 1 deletion piptools/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def get_best_match(self, ireq):
# NOTE: it's much quicker to immediately return instead of
# hitting the index server
best_match = ireq
elif is_pinned_requirement(ireq):
elif is_pinned_requirement(ireq) and not self.prefer_local:
# NOTE: it's much quicker to immediately return instead of
# hitting the index server
best_match = ireq
Expand Down
10 changes: 10 additions & 0 deletions piptools/scripts/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
import sys
import tempfile

# packaging is in a different place in some pkg_resources
try:
from pkg_resources.extern import packaging
except ImportError:
from pkg_resources._vendor import packaging

import pip
from pip.req import InstallRequirement, parse_requirements

Expand Down Expand Up @@ -187,6 +193,10 @@ def cli(verbose, dry_run, pre, rebuild, find_links, index_url, extra_index_url,
# Check the given base set of constraints first
Resolver.check_constraints(constraints)

if prefer_local:
# Normalise local version to python wheel format
prefer_local = packaging.version.Version("0+{}".format(prefer_local)).local

try:
resolver = Resolver(constraints, repository, prereleases=pre,
clear_caches=rebuild, allow_unsafe=allow_unsafe, prefer_local=prefer_local)
Expand Down

0 comments on commit 697249f

Please sign in to comment.