Skip to content
This repository has been archived by the owner on Mar 19, 2024. It is now read-only.

Commit

Permalink
Merge pip 7 support. Close #111. Close #97. Close #94.
Browse files Browse the repository at this point in the history
As part of the merge, had to move kouk's clever new stuff into a top-level function, which is where the `peep port` work moved hashes_above().
  • Loading branch information
erikrose committed Dec 3, 2015
2 parents fba02cd + ddb4c4f commit 4215691
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 19 deletions.
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ Version History
===============

2.5
* Support pip 7.x, through the currently latest 7.1.2, working around its
buggy line counting. (kouk)
* Add ``peep port`` command to facilitate the transition to `pip 8's hashing
<https://pip.pypa.io/en/latest/reference/pip_install/#hash-checking-mode>`_.
* Fix bug in which the right way to call ``parse_requirements()`` would not
Expand Down
58 changes: 40 additions & 18 deletions peep.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@
from collections import defaultdict
from functools import wraps
from hashlib import sha256
from itertools import chain
from linecache import getline
from itertools import chain, islice
import mimetypes
from optparse import OptionParser
from os.path import join, basename, splitext, isdir
Expand Down Expand Up @@ -105,9 +104,19 @@ def iter(self, ret, *args, **kwargs):

DownloadProgressBar = DownloadProgressSpinner = NullProgressBar


__version__ = 2, 5, 0

try:
from pip.index import FormatControl # noqa
FORMAT_CONTROL_ARG = 'format_control'

# The line-numbering bug will be fixed in pip 8. All 7.x releases had it.
PIP_MAJOR_VERSION = int(pip.__version__.split('.')[0])
PIP_COUNTS_COMMENTS = PIP_MAJOR_VERSION >= 8
except ImportError:
FORMAT_CONTROL_ARG = 'use_wheel' # pre-7
PIP_COUNTS_COMMENTS = True


ITS_FINE_ITS_FINE = 0
SOMETHING_WENT_WRONG = 1
Expand Down Expand Up @@ -161,18 +170,32 @@ def path_and_line(req):


def hashes_above(path, line_number):
"""Yield hashes from contiguous comment lines before line
``line_number``.
"""Yield hashes from contiguous comment lines before line ``line_number``.
"""
for line_number in xrange(line_number - 1, 0, -1):
line = getline(path, line_number)
match = HASH_COMMENT_RE.match(line)
if match:
yield match.groupdict()['hash']
elif not line.lstrip().startswith('#'):
# If we hit a non-comment line, abort
break
def hash_lists(path):
"""Yield lists of hashes appearing between non-comment lines.
The lists will be in order of appearance and, for each non-empty
list, their place in the results will coincide with that of the
line number of the corresponding result from `parse_requirements`
(which changed in pip 7.0 to not count comments).
"""
hashes = []
with open(path) as file:
for lineno, line in enumerate(file, 1):
match = HASH_COMMENT_RE.match(line)
if match: # Accumulate this hash.
hashes.append(match.groupdict()['hash'])
if not IGNORED_LINE_RE.match(line):
yield hashes # Report hashes seen so far.
hashes = []
elif PIP_COUNTS_COMMENTS:
# Comment: count as normal req but have no hashes.
yield []

return next(islice(hash_lists(path), line_number - 1, None))


def run_pip(initial_args):
Expand Down Expand Up @@ -243,6 +266,8 @@ def requirement_args(argv, want_paths=False, want_other=False):
if want_other:
yield arg

# any line that is a comment or just whitespace
IGNORED_LINE_RE = re.compile(r'^(\s*#.*)?\s*$')

HASH_COMMENT_RE = re.compile(
r"""
Expand Down Expand Up @@ -337,7 +362,7 @@ def package_finder(argv):
# Carry over PackageFinder kwargs that have [about] the same names as
# options attr names:
possible_options = [
'find_links', 'use_wheel', 'allow_external', 'allow_unverified',
'find_links', FORMAT_CONTROL_ARG, 'allow_external', 'allow_unverified',
'allow_all_external', ('allow_all_prereleases', 'pre'),
'process_dependency_links']
kwargs = {}
Expand Down Expand Up @@ -463,9 +488,7 @@ def _is_always_unsatisfied(self):
@memoize # Avoid hitting the file[cache] over and over.
def _expected_hashes(self):
"""Return a list of known-good hashes for this package."""
hashes = list(hashes_above(*path_and_line(self._req)))
hashes.reverse() # because we read them backwards
return hashes
return hashes_above(*path_and_line(self._req))

def _download(self, link):
"""Download a file, and return its name within my temp dir.
Expand Down Expand Up @@ -883,7 +906,6 @@ def peep_port(paths):
_parse_requirements(path, package_finder(argv)) for path in paths):
hashes = [hexlify(urlsafe_b64decode((hash + '=').encode('ascii'))).decode('ascii')
for hash in hashes_above(*path_and_line(req))]
hashes.reverse()
if not hashes:
print(req.req)
elif len(hashes) == 1:
Expand Down
9 changes: 8 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ max-line-length = 140
# Test pip 1.0 through 1.5.6 with Python 3.1 except pip 1.4-1.5.5 since they're
# incompatible with py31 (https://github.com/pypa/pip/issues/1105).
# Test pip >= 1.0 with Python 2.6, 2.7, 3.2, 3.3, and 3.4.
envlist = py{26,27}-pip{062,063,070,071,072,080,081,082,083}, py31-pip{100,101,102,110,120,121,130,131,156}, py{26,27,32,33,34}-pip{100,101,102,110,120,121,130,131,140,141,150,151,152,153,154,155,156,600,601,602,603,604,605,606,607,608,610,611}
envlist = py{26,27}-pip{062,063,070,071,072,080,081,082,083}, py31-pip{100,101,102,110,120,121,130,131,156}, py{26,27,32,33,34}-pip{100,101,102,110,120,121,130,131,140,141,150,151,152,153,154,155,156,600,601,602,603,604,605,606,607,608,610,611,700,701,702,703,710,711,712}

[testenv]
commands = nosetests
Expand Down Expand Up @@ -53,3 +53,10 @@ deps =
pip608: pip==6.0.8
pip610: pip==6.1.0
pip611: pip==6.1.1
pip700: pip==7.0.0
pip701: pip==7.0.1
pip702: pip==7.0.2
pip703: pip==7.0.3
pip710: pip==7.1.0
pip711: pip==7.1.1
pip712: pip==7.1.2

0 comments on commit 4215691

Please sign in to comment.