mirror of https://github.com/pypa/pip
Merge remote-tracking branch 'pypa/develop' into refactor_req_file
Conflicts: pip/req/req_file.py
This commit is contained in:
commit
b911339625
|
@ -453,6 +453,7 @@ the project path. This is one advantage over just using ``setup.py develop``,
|
|||
which creates the "egg-info" directly relative the current working directory.
|
||||
|
||||
|
||||
.. _`controlling-setup-requires`:
|
||||
|
||||
Controlling setup_requires
|
||||
++++++++++++++++++++++++++
|
||||
|
|
|
@ -535,7 +535,7 @@ From within a real python, where ``SomePackage`` *is* installed globally, and is
|
|||
Ensuring Repeatability
|
||||
**********************
|
||||
|
||||
Three things are required to fully guarantee a repeatable installation using requirements files.
|
||||
Four things are required to fully guarantee a repeatable installation using requirements files.
|
||||
|
||||
1. The requirements file was generated by ``pip freeze`` or you're sure it only
|
||||
contains requirements that specify a specific version.
|
||||
|
@ -544,15 +544,14 @@ Three things are required to fully guarantee a repeatable installation using req
|
|||
This guarantees that only what is explicitly listed in the requirements file is
|
||||
installed.
|
||||
|
||||
3. The installation is performed against an index or find-links location that is
|
||||
3. None of the packages to be installed utilize the setup_requires keyword. See
|
||||
:ref:`Controlling setup_requires<controlling-setup-requires>`.
|
||||
|
||||
4. The installation is performed against an index or find-links location that is
|
||||
guaranteed to *not* allow archives to be changed and updated without a
|
||||
version increase. Unfortunately, this is *not* true on PyPI. It is possible
|
||||
for the same pypi distribution to have a different hash over time. Project
|
||||
authors are allowed to delete a distribution, and then upload a new one with
|
||||
the same name and version, but a different hash. See `Issue #1175
|
||||
<https://github.com/pypa/pip/issues/1175>`_ for plans to add hash
|
||||
confirmation to pip, or a new "lock file" notion, but for now, know that the `peep
|
||||
project <https://pypi.python.org/pypi/peep>`_ offers this feature on top of pip
|
||||
version increase. While this is safe on PyPI, it may not be safe for other
|
||||
indices. If you are working with an unsafe index, consider the `peep project
|
||||
<https://pypi.python.org/pypi/peep>`_ which offers this feature on top of pip
|
||||
using requirements file comments.
|
||||
|
||||
|
||||
|
@ -576,4 +575,4 @@ Once you have a bundle, you can then install it using::
|
|||
|
||||
$ tempdir=$(mktemp -d /tmp/wheelhouse-XXXXX)
|
||||
$ (cd $tempdir; tar -xvf /path/to/bundled.tar.bz2)
|
||||
$ pip install --force-reinstall --ignore-installed --upgrade --no-index --use-wheel --no-deps $tempdir/*
|
||||
$ pip install --force-reinstall --ignore-installed --upgrade --no-index --no-deps $tempdir/*
|
||||
|
|
|
@ -109,7 +109,12 @@ class Command(object):
|
|||
options, args = self.parse_args(args)
|
||||
|
||||
if options.quiet:
|
||||
level = "WARNING"
|
||||
if options.quiet == 1:
|
||||
level = "WARNING"
|
||||
if options.quiet == 2:
|
||||
level = "ERROR"
|
||||
else:
|
||||
level = "CRITICAL"
|
||||
elif options.verbose:
|
||||
level = "DEBUG"
|
||||
else:
|
||||
|
@ -281,7 +286,7 @@ class RequirementCommand(Command):
|
|||
|
||||
@staticmethod
|
||||
def populate_requirement_set(requirement_set, args, options, finder,
|
||||
session, name):
|
||||
session, name, wheel_cache):
|
||||
"""
|
||||
Marshal cmd line args into a requirement set.
|
||||
"""
|
||||
|
@ -289,7 +294,7 @@ class RequirementCommand(Command):
|
|||
requirement_set.add_requirement(
|
||||
InstallRequirement.from_line(
|
||||
name, None, isolated=options.isolated_mode,
|
||||
cache_root=options.cache_dir
|
||||
wheel_cache=wheel_cache
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -299,14 +304,15 @@ class RequirementCommand(Command):
|
|||
name,
|
||||
default_vcs=options.default_vcs,
|
||||
isolated=options.isolated_mode,
|
||||
cache_root=options.cache_dir
|
||||
wheel_cache=wheel_cache
|
||||
)
|
||||
)
|
||||
|
||||
for filename in options.requirements:
|
||||
for req in parse_requirements(
|
||||
filename,
|
||||
finder=finder, options=options, session=session):
|
||||
finder=finder, options=options, session=session,
|
||||
wheel_cache=wheel_cache):
|
||||
requirement_set.add_requirement(req)
|
||||
|
||||
if not requirement_set.has_requirements:
|
||||
|
|
|
@ -4,6 +4,7 @@ import sys
|
|||
|
||||
from pip.basecommand import Command
|
||||
from pip.operations.freeze import freeze
|
||||
from pip.wheel import WheelCache
|
||||
|
||||
|
||||
class FreezeCommand(Command):
|
||||
|
@ -54,6 +55,7 @@ class FreezeCommand(Command):
|
|||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
def run(self, options, args):
|
||||
wheel_cache = WheelCache(options.cache_dir)
|
||||
freeze_kwargs = dict(
|
||||
requirement=options.requirement,
|
||||
find_links=options.find_links,
|
||||
|
@ -61,7 +63,7 @@ class FreezeCommand(Command):
|
|||
user_only=options.user,
|
||||
skip_regex=options.skip_requirements_regex,
|
||||
isolated=options.isolated_mode,
|
||||
cache_root=options.cache_dir)
|
||||
wheel_cache=wheel_cache)
|
||||
|
||||
for line in freeze(**freeze_kwargs):
|
||||
sys.stdout.write(line + '\n')
|
||||
|
|
|
@ -22,7 +22,7 @@ from pip import cmdoptions
|
|||
from pip.utils import ensure_dir
|
||||
from pip.utils.build import BuildDirectory
|
||||
from pip.utils.deprecation import RemovedInPip8Warning
|
||||
from pip.wheel import WheelBuilder
|
||||
from pip.wheel import WheelCache, WheelBuilder
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -239,11 +239,11 @@ class InstallCommand(RequirementCommand):
|
|||
|
||||
finder = self._build_package_finder(options, index_urls, session)
|
||||
build_delete = (not (options.no_clean or options.build_dir))
|
||||
wheel_cache = WheelCache(options.cache_dir)
|
||||
with BuildDirectory(options.build_dir,
|
||||
delete=build_delete) as build_dir:
|
||||
requirement_set = RequirementSet(
|
||||
build_dir=build_dir,
|
||||
cache_root=options.cache_dir,
|
||||
src_dir=options.src_dir,
|
||||
download_dir=options.download_dir,
|
||||
upgrade=options.upgrade,
|
||||
|
@ -256,10 +256,12 @@ class InstallCommand(RequirementCommand):
|
|||
session=session,
|
||||
pycompile=options.compile,
|
||||
isolated=options.isolated_mode,
|
||||
wheel_cache=wheel_cache,
|
||||
)
|
||||
|
||||
self.populate_requirement_set(
|
||||
requirement_set, args, options, finder, session, self.name,
|
||||
wheel_cache
|
||||
)
|
||||
|
||||
if not requirement_set.has_requirements:
|
||||
|
|
|
@ -2,11 +2,14 @@ from __future__ import absolute_import
|
|||
|
||||
import logging
|
||||
|
||||
from pip._vendor import pkg_resources
|
||||
|
||||
from pip.basecommand import Command
|
||||
from pip.exceptions import DistributionNotFound
|
||||
from pip.index import PackageFinder
|
||||
from pip.index import PackageFinder, Search
|
||||
from pip.req import InstallRequirement
|
||||
from pip.utils import get_installed_distributions, dist_is_editable
|
||||
from pip.wheel import WheelCache
|
||||
from pip.cmdoptions import make_option_group, index_group
|
||||
|
||||
|
||||
|
@ -128,10 +131,11 @@ class ListCommand(Command):
|
|||
user_only=options.user,
|
||||
include_editables=False,
|
||||
)
|
||||
wheel_cache = WheelCache(options.cache_dir)
|
||||
for dist in installed_packages:
|
||||
req = InstallRequirement.from_line(
|
||||
dist.key, None, isolated=options.isolated_mode,
|
||||
cache_root=options.cache_dir,
|
||||
wheel_cache=wheel_cache
|
||||
)
|
||||
typ = 'unknown'
|
||||
try:
|
||||
|
@ -144,9 +148,12 @@ class ListCommand(Command):
|
|||
except DistributionNotFound:
|
||||
continue
|
||||
else:
|
||||
search = Search(
|
||||
req.name,
|
||||
pkg_resources.safe_name(req.name).lower(),
|
||||
["source", "binary"])
|
||||
remote_version = finder._link_package_versions(
|
||||
link, req.name
|
||||
).version
|
||||
link, search).version
|
||||
if link.is_wheel:
|
||||
typ = 'wheel'
|
||||
else:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from pip.wheel import WheelCache
|
||||
from pip.req import InstallRequirement, RequirementSet, parse_requirements
|
||||
from pip.basecommand import Command
|
||||
from pip.exceptions import InstallationError
|
||||
|
@ -42,20 +43,20 @@ class UninstallCommand(Command):
|
|||
|
||||
def run(self, options, args):
|
||||
with self._build_session(options) as session:
|
||||
|
||||
wheel_cache = WheelCache(options.cache_dir)
|
||||
requirement_set = RequirementSet(
|
||||
build_dir=None,
|
||||
cache_root=options.cache_dir,
|
||||
src_dir=None,
|
||||
download_dir=None,
|
||||
isolated=options.isolated_mode,
|
||||
session=session,
|
||||
wheel_cache=wheel_cache,
|
||||
)
|
||||
for name in args:
|
||||
requirement_set.add_requirement(
|
||||
InstallRequirement.from_line(
|
||||
name, isolated=options.isolated_mode,
|
||||
cache_root=options.cache_dir,
|
||||
wheel_cache=wheel_cache
|
||||
)
|
||||
)
|
||||
for filename in options.requirements:
|
||||
|
@ -63,7 +64,7 @@ class UninstallCommand(Command):
|
|||
filename,
|
||||
options=options,
|
||||
session=session,
|
||||
cache_root=options.cache_dir):
|
||||
wheel_cache=wheel_cache):
|
||||
requirement_set.add_requirement(req)
|
||||
if not requirement_set.has_requirements:
|
||||
raise InstallationError(
|
||||
|
|
|
@ -12,7 +12,7 @@ from pip.req import RequirementSet
|
|||
from pip.utils import import_or_raise, normalize_path
|
||||
from pip.utils.build import BuildDirectory
|
||||
from pip.utils.deprecation import RemovedInPip8Warning
|
||||
from pip.wheel import WheelBuilder
|
||||
from pip.wheel import WheelCache, WheelBuilder
|
||||
from pip import cmdoptions
|
||||
|
||||
DEFAULT_WHEEL_DIR = os.path.join(normalize_path(os.curdir), 'wheelhouse')
|
||||
|
@ -155,22 +155,24 @@ class WheelCommand(RequirementCommand):
|
|||
)
|
||||
|
||||
build_delete = (not (options.no_clean or options.build_dir))
|
||||
wheel_cache = WheelCache(options.cache_dir)
|
||||
with BuildDirectory(options.build_dir,
|
||||
delete=build_delete) as build_dir:
|
||||
requirement_set = RequirementSet(
|
||||
build_dir=build_dir,
|
||||
cache_root=options.cache_dir,
|
||||
src_dir=options.src_dir,
|
||||
download_dir=None,
|
||||
ignore_dependencies=options.ignore_dependencies,
|
||||
ignore_installed=True,
|
||||
isolated=options.isolated_mode,
|
||||
session=session,
|
||||
wheel_cache=wheel_cache,
|
||||
wheel_download_dir=options.wheel_dir
|
||||
)
|
||||
|
||||
self.populate_requirement_set(
|
||||
requirement_set, args, options, finder, session, self.name,
|
||||
wheel_cache
|
||||
)
|
||||
|
||||
if not requirement_set.has_requirements:
|
||||
|
|
101
pip/index.py
101
pip/index.py
|
@ -3,6 +3,7 @@ from __future__ import absolute_import
|
|||
|
||||
import logging
|
||||
import cgi
|
||||
from collections import namedtuple
|
||||
import itertools
|
||||
import sys
|
||||
import os
|
||||
|
@ -235,24 +236,21 @@ class PackageFinder(object):
|
|||
comparison operators, but then different sdist links
|
||||
with the same version, would have to be considered equal
|
||||
"""
|
||||
if self.use_wheel:
|
||||
support_num = len(supported_tags)
|
||||
if candidate.location == INSTALLED_VERSION:
|
||||
pri = 1
|
||||
elif candidate.location.is_wheel:
|
||||
# can raise InvalidWheelFilename
|
||||
wheel = Wheel(candidate.location.filename)
|
||||
if not wheel.supported():
|
||||
raise UnsupportedWheel(
|
||||
"%s is not a supported wheel for this platform. It "
|
||||
"can't be sorted." % wheel.filename
|
||||
)
|
||||
pri = -(wheel.support_index_min())
|
||||
else: # sdist
|
||||
pri = -(support_num)
|
||||
return (candidate.version, pri)
|
||||
else:
|
||||
return candidate.version
|
||||
support_num = len(supported_tags)
|
||||
if candidate.location == INSTALLED_VERSION:
|
||||
pri = 1
|
||||
elif candidate.location.is_wheel:
|
||||
# can raise InvalidWheelFilename
|
||||
wheel = Wheel(candidate.location.filename)
|
||||
if not wheel.supported():
|
||||
raise UnsupportedWheel(
|
||||
"%s is not a supported wheel for this platform. It "
|
||||
"can't be sorted." % wheel.filename
|
||||
)
|
||||
pri = -(wheel.support_index_min())
|
||||
else: # sdist
|
||||
pri = -(support_num)
|
||||
return (candidate.version, pri)
|
||||
|
||||
def _sort_versions(self, applicable_versions):
|
||||
"""
|
||||
|
@ -415,23 +413,30 @@ class PackageFinder(object):
|
|||
for location in url_locations:
|
||||
logger.debug('* %s', location)
|
||||
|
||||
find_links_versions = list(self._package_versions(
|
||||
formats = set(["source"])
|
||||
if self.use_wheel:
|
||||
formats.add("binary")
|
||||
search = Search(
|
||||
project_name.lower(),
|
||||
pkg_resources.safe_name(project_name).lower(),
|
||||
frozenset(formats))
|
||||
find_links_versions = self._package_versions(
|
||||
# We trust every directly linked archive in find_links
|
||||
(Link(url, '-f', trusted=True) for url in self.find_links),
|
||||
project_name.lower()
|
||||
))
|
||||
search
|
||||
)
|
||||
|
||||
page_versions = []
|
||||
for page in self._get_pages(url_locations, project_name):
|
||||
logger.debug('Analyzing links from page %s', page.url)
|
||||
with indent_log():
|
||||
page_versions.extend(
|
||||
self._package_versions(page.links, project_name.lower())
|
||||
self._package_versions(page.links, search)
|
||||
)
|
||||
|
||||
dependency_versions = list(self._package_versions(
|
||||
(Link(url) for url in self.dependency_links), project_name.lower()
|
||||
))
|
||||
dependency_versions = self._package_versions(
|
||||
(Link(url) for url in self.dependency_links), search
|
||||
)
|
||||
if dependency_versions:
|
||||
logger.debug(
|
||||
'dependency_links found: %s',
|
||||
|
@ -440,12 +445,7 @@ class PackageFinder(object):
|
|||
])
|
||||
)
|
||||
|
||||
file_versions = list(
|
||||
self._package_versions(
|
||||
file_locations,
|
||||
project_name.lower()
|
||||
)
|
||||
)
|
||||
file_versions = self._package_versions(file_locations, search)
|
||||
if file_versions:
|
||||
file_versions.sort(reverse=True)
|
||||
logger.debug(
|
||||
|
@ -666,18 +666,20 @@ class PackageFinder(object):
|
|||
no_eggs.append(link)
|
||||
return no_eggs + eggs
|
||||
|
||||
def _package_versions(self, links, search_name):
|
||||
def _package_versions(self, links, search):
|
||||
result = []
|
||||
for link in self._sort_links(links):
|
||||
v = self._link_package_versions(link, search_name)
|
||||
v = self._link_package_versions(link, search)
|
||||
if v is not None:
|
||||
yield v
|
||||
result.append(v)
|
||||
return result
|
||||
|
||||
def _log_skipped_link(self, link, reason):
|
||||
if link not in self.logged_links:
|
||||
logger.debug('Skipping link %s; %s', link, reason)
|
||||
self.logged_links.add(link)
|
||||
|
||||
def _link_package_versions(self, link, search_name):
|
||||
def _link_package_versions(self, link, search):
|
||||
"""Return an InstallationCandidate or None"""
|
||||
platform = get_platform()
|
||||
|
||||
|
@ -693,8 +695,9 @@ class PackageFinder(object):
|
|||
self._log_skipped_link(
|
||||
link, 'unsupported archive format: %s' % ext)
|
||||
return
|
||||
if not self.use_wheel and ext == wheel_ext:
|
||||
self._log_skipped_link(link, '--no-use-wheel used')
|
||||
if "binary" not in search.formats and ext == wheel_ext:
|
||||
self._log_skipped_link(
|
||||
link, 'No binaries permitted for %s' % search.supplied)
|
||||
return
|
||||
if "macosx10" in link.path and ext == '.zip':
|
||||
self._log_skipped_link(link, 'macosx10 one')
|
||||
|
@ -706,9 +709,9 @@ class PackageFinder(object):
|
|||
self._log_skipped_link(link, 'invalid wheel filename')
|
||||
return
|
||||
if (pkg_resources.safe_name(wheel.name).lower() !=
|
||||
pkg_resources.safe_name(search_name).lower()):
|
||||
search.canonical):
|
||||
self._log_skipped_link(
|
||||
link, 'wrong project name (not %s)' % search_name)
|
||||
link, 'wrong project name (not %s)' % search.supplied)
|
||||
return
|
||||
if not wheel.supported():
|
||||
self._log_skipped_link(
|
||||
|
@ -741,15 +744,15 @@ class PackageFinder(object):
|
|||
version = wheel.version
|
||||
|
||||
if not version:
|
||||
version = egg_info_matches(egg_info, search_name, link)
|
||||
version = egg_info_matches(egg_info, search.supplied, link)
|
||||
if version is None:
|
||||
self._log_skipped_link(
|
||||
link, 'wrong project name (not %s)' % search_name)
|
||||
link, 'wrong project name (not %s)' % search.supplied)
|
||||
return
|
||||
|
||||
if (link.internal is not None and not
|
||||
link.internal and not
|
||||
normalize_name(search_name).lower()
|
||||
normalize_name(search.supplied).lower()
|
||||
in self.allow_external and not
|
||||
self.allow_all_external):
|
||||
# We have a link that we are sure is external, so we should skip
|
||||
|
@ -760,7 +763,7 @@ class PackageFinder(object):
|
|||
|
||||
if (link.verifiable is not None and not
|
||||
link.verifiable and not
|
||||
(normalize_name(search_name).lower()
|
||||
(normalize_name(search.supplied).lower()
|
||||
in self.allow_unverified)):
|
||||
# We have a link that we are sure we cannot verify its integrity,
|
||||
# so we should skip it unless we are allowing unsafe installs
|
||||
|
@ -780,7 +783,7 @@ class PackageFinder(object):
|
|||
return
|
||||
logger.debug('Found link %s, version: %s', link, version)
|
||||
|
||||
return InstallationCandidate(search_name, version, link)
|
||||
return InstallationCandidate(search.supplied, version, link)
|
||||
|
||||
def _get_page(self, link):
|
||||
return HTMLPage.get_page(link, session=self.session)
|
||||
|
@ -1187,3 +1190,13 @@ class Link(object):
|
|||
# An object to represent the "link" for the installed version of a requirement.
|
||||
# Using Inf as the url makes it sort higher.
|
||||
INSTALLED_VERSION = Link(Inf)
|
||||
|
||||
|
||||
Search = namedtuple('Search', 'supplied canonical formats')
|
||||
"""Capture key aspects of a search.
|
||||
|
||||
:attribute user: The user supplied package.
|
||||
:attribute canonical: The canonical package name.
|
||||
:attribute formats: The formats allowed for this package. Should be a set
|
||||
with 'binary' or 'source' or both in it.
|
||||
"""
|
||||
|
|
|
@ -22,7 +22,7 @@ def freeze(
|
|||
find_tags=False,
|
||||
default_vcs=None,
|
||||
isolated=False,
|
||||
cache_root=None):
|
||||
wheel_cache=None):
|
||||
find_links = find_links or []
|
||||
skip_match = None
|
||||
|
||||
|
@ -76,13 +76,13 @@ def freeze(
|
|||
line,
|
||||
default_vcs=default_vcs,
|
||||
isolated=isolated,
|
||||
cache_root=cache_root,
|
||||
wheel_cache=wheel_cache,
|
||||
)
|
||||
else:
|
||||
line_req = InstallRequirement.from_line(
|
||||
line,
|
||||
isolated=isolated,
|
||||
cache_root=cache_root,
|
||||
wheel_cache=wheel_cache,
|
||||
)
|
||||
|
||||
if not line_req.name:
|
||||
|
|
|
@ -52,15 +52,16 @@ SUPPORTED_OPTIONS_REQ_DEST = [o().dest for o in SUPPORTED_OPTIONS_REQ]
|
|||
|
||||
|
||||
def parse_requirements(filename, finder=None, comes_from=None, options=None,
|
||||
session=None, cache_root=None):
|
||||
session=None, wheel_cache=None):
|
||||
"""
|
||||
Parse a requirements file and yield InstallRequirement instances.
|
||||
|
||||
:param filename: Path or url of requirements file.
|
||||
:param finder: Instance of pip.index.PackageFinder.
|
||||
:param comes_from: Origin description of requirements.
|
||||
:param options: Global options.
|
||||
:param session: Instance of pip.download.PipSession.
|
||||
:param filename: Path or url of requirements file.
|
||||
:param finder: Instance of pip.index.PackageFinder.
|
||||
:param comes_from: Origin description of requirements.
|
||||
:param options: Global options.
|
||||
:param session: Instance of pip.download.PipSession.
|
||||
:param wheel_cache: Instance of pip.wheel.WheelCache
|
||||
"""
|
||||
if session is None:
|
||||
raise TypeError(
|
||||
|
@ -79,13 +80,13 @@ def parse_requirements(filename, finder=None, comes_from=None, options=None,
|
|||
|
||||
for line_number, line in enumerate(lines, 1):
|
||||
req_iter = process_line(line, filename, line_number, finder,
|
||||
comes_from, options, session)
|
||||
comes_from, options, session, wheel_cache)
|
||||
for req in req_iter:
|
||||
yield req
|
||||
|
||||
|
||||
def process_line(line, filename, line_number, finder=None, comes_from=None,
|
||||
options=None, session=None, cache_root=None):
|
||||
options=None, session=None, wheel_cache=None):
|
||||
"""
|
||||
Process a single requirements line; This can result in creating/yielding
|
||||
requirements, or updating the finder.
|
||||
|
@ -126,7 +127,8 @@ def process_line(line, filename, line_number, finder=None, comes_from=None,
|
|||
for key in keys:
|
||||
delattr(opts, key)
|
||||
yield InstallRequirement.from_line(
|
||||
args_line, comes_from, isolated=isolated, options=opts.__dict__
|
||||
args_line, comes_from, isolated=isolated, options=opts.__dict__,
|
||||
wheel_cache=wheel_cache
|
||||
)
|
||||
|
||||
# yield an editable requirement
|
||||
|
@ -136,7 +138,8 @@ def process_line(line, filename, line_number, finder=None, comes_from=None,
|
|||
default_vcs = options.default_vcs if options else None
|
||||
yield InstallRequirement.from_editable(
|
||||
opts.editables[0], comes_from=comes_from,
|
||||
default_vcs=default_vcs, isolated=isolated
|
||||
default_vcs=default_vcs, isolated=isolated,
|
||||
wheel_cache=wheel_cache
|
||||
)
|
||||
|
||||
# parse a nested requirements file
|
||||
|
@ -150,7 +153,8 @@ def process_line(line, filename, line_number, finder=None, comes_from=None,
|
|||
req_url = os.path.join(os.path.dirname(filename), req_file)
|
||||
# TODO: Why not use `comes_from='-r {} (line {})'` here as well?
|
||||
parser = parse_requirements(
|
||||
req_url, finder, comes_from, options, session, cache_root
|
||||
req_url, finder, comes_from, options, session,
|
||||
wheel_cache=wheel_cache
|
||||
)
|
||||
for req in parser:
|
||||
yield req
|
||||
|
|
|
@ -74,7 +74,7 @@ class InstallRequirement(object):
|
|||
def __init__(self, req, comes_from, source_dir=None, editable=False,
|
||||
link=None, as_egg=False, update=True, editable_options=None,
|
||||
pycompile=True, markers=None, isolated=False, options=None,
|
||||
cache_root=None):
|
||||
wheel_cache=None):
|
||||
self.extras = ()
|
||||
if isinstance(req, six.string_types):
|
||||
req = pkg_resources.Requirement.parse(req)
|
||||
|
@ -89,7 +89,7 @@ class InstallRequirement(object):
|
|||
editable_options = {}
|
||||
|
||||
self.editable_options = editable_options
|
||||
self._cache_root = cache_root
|
||||
self._wheel_cache = wheel_cache
|
||||
self.link = link
|
||||
self.as_egg = as_egg
|
||||
self.markers = markers
|
||||
|
@ -120,7 +120,7 @@ class InstallRequirement(object):
|
|||
|
||||
@classmethod
|
||||
def from_editable(cls, editable_req, comes_from=None, default_vcs=None,
|
||||
isolated=False, options=None, cache_root=None):
|
||||
isolated=False, options=None, wheel_cache=None):
|
||||
from pip.index import Link
|
||||
|
||||
name, url, extras_override, editable_options = parse_editable(
|
||||
|
@ -136,7 +136,7 @@ class InstallRequirement(object):
|
|||
editable_options=editable_options,
|
||||
isolated=isolated,
|
||||
options=options if options else {},
|
||||
cache_root=cache_root)
|
||||
wheel_cache=wheel_cache)
|
||||
|
||||
if extras_override is not None:
|
||||
res.extras = extras_override
|
||||
|
@ -146,7 +146,7 @@ class InstallRequirement(object):
|
|||
@classmethod
|
||||
def from_line(
|
||||
cls, name, comes_from=None, isolated=False, options=None,
|
||||
cache_root=None):
|
||||
wheel_cache=None):
|
||||
"""Creates an InstallRequirement from a name, which might be a
|
||||
requirement, directory containing 'setup.py', filename, or URL.
|
||||
"""
|
||||
|
@ -213,7 +213,8 @@ class InstallRequirement(object):
|
|||
|
||||
options = options if options else {}
|
||||
return cls(req, comes_from, link=link, markers=markers,
|
||||
isolated=isolated, options=options, cache_root=cache_root)
|
||||
isolated=isolated, options=options,
|
||||
wheel_cache=wheel_cache)
|
||||
|
||||
def __str__(self):
|
||||
if self.req:
|
||||
|
@ -253,8 +254,10 @@ class InstallRequirement(object):
|
|||
@link.setter
|
||||
def link(self, link):
|
||||
# Lookup a cached wheel, if possible.
|
||||
link = pip.wheel.cached_wheel(self._cache_root, link)
|
||||
self._link = link
|
||||
if self._wheel_cache is None:
|
||||
self._link = link
|
||||
else:
|
||||
self._link = self._wheel_cache.cached_wheel(link)
|
||||
|
||||
@property
|
||||
def specifier(self):
|
||||
|
|
|
@ -140,7 +140,7 @@ class RequirementSet(object):
|
|||
ignore_dependencies=False, force_reinstall=False,
|
||||
use_user_site=False, session=None, pycompile=True,
|
||||
isolated=False, wheel_download_dir=None,
|
||||
cache_root=None):
|
||||
wheel_cache=None):
|
||||
"""Create a RequirementSet.
|
||||
|
||||
:param wheel_download_dir: Where still-packed .whl files should be
|
||||
|
@ -150,7 +150,7 @@ class RequirementSet(object):
|
|||
:param download_dir: Where still packed archives should be written to.
|
||||
If None they are not saved, and are deleted immediately after
|
||||
unpacking.
|
||||
:param cache_root: The root of the pip cache, for passing to
|
||||
:param wheel_cache: The pip wheel cache, for passing to
|
||||
InstallRequirement.
|
||||
"""
|
||||
if session is None:
|
||||
|
@ -185,7 +185,7 @@ class RequirementSet(object):
|
|||
if wheel_download_dir:
|
||||
wheel_download_dir = normalize_path(wheel_download_dir)
|
||||
self.wheel_download_dir = wheel_download_dir
|
||||
self._cache_root = cache_root
|
||||
self._wheel_cache = wheel_cache
|
||||
# Maps from install_req -> dependencies_of_install_req
|
||||
self._dependencies = defaultdict(list)
|
||||
|
||||
|
@ -517,7 +517,7 @@ class RequirementSet(object):
|
|||
str(subreq),
|
||||
req_to_install,
|
||||
isolated=self.isolated,
|
||||
cache_root=self._cache_root,
|
||||
wheel_cache=self._wheel_cache,
|
||||
)
|
||||
more_reqs.extend(self.add_requirement(
|
||||
sub_install_req, req_to_install.name))
|
||||
|
|
18
pip/wheel.py
18
pip/wheel.py
|
@ -44,6 +44,20 @@ VERSION_COMPATIBLE = (1, 0)
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WheelCache(object):
|
||||
"""A cache of wheels for future installs."""
|
||||
|
||||
def __init__(self, cache_dir):
|
||||
"""Create a wheel cache.
|
||||
|
||||
:param cache_dir: The root of the cache.
|
||||
"""
|
||||
self._cache_dir = cache_dir
|
||||
|
||||
def cached_wheel(self, link):
|
||||
return cached_wheel(self._cache_dir, link)
|
||||
|
||||
|
||||
def _cache_for_filename(cache_dir, sdistfilename):
|
||||
"""Return a directory to store cached wheels in for sdistfilename.
|
||||
|
||||
|
@ -598,10 +612,10 @@ class WheelBuilder(object):
|
|||
"""Build wheels from a RequirementSet."""
|
||||
|
||||
def __init__(self, requirement_set, finder, build_options=None,
|
||||
global_options=None, cache_root=None):
|
||||
global_options=None):
|
||||
self.requirement_set = requirement_set
|
||||
self.finder = finder
|
||||
self._cache_root = requirement_set._cache_root
|
||||
self._cache_root = requirement_set._wheel_cache._cache_dir
|
||||
self._wheel_dir = requirement_set.wheel_download_dir
|
||||
self.build_options = build_options or []
|
||||
self.global_options = global_options or []
|
||||
|
|
|
@ -25,7 +25,7 @@ def test_download_wheel(script):
|
|||
--find-links has a bug https://github.com/pypa/pip/issues/1111
|
||||
"""
|
||||
result = script.pip(
|
||||
'install', '--use-wheel',
|
||||
'install',
|
||||
'-f', 'https://bitbucket.org/pypa/pip-test-package/downloads',
|
||||
'-d', '.', 'pip-test-package'
|
||||
)
|
||||
|
|
|
@ -79,7 +79,7 @@ def test_nonexistent_extra_warns_user_with_wheel(script, data):
|
|||
This exercises wheel installs.
|
||||
"""
|
||||
result = script.pip(
|
||||
'install', '--use-wheel', '--no-index',
|
||||
'install', '--no-index',
|
||||
'--find-links=' + data.find_links,
|
||||
'simplewheel[nonexistent]', expect_stderr=True,
|
||||
)
|
||||
|
@ -94,7 +94,7 @@ def test_nonexistent_options_listed_in_order(script, data):
|
|||
Warn the user for each extra that doesn't exist.
|
||||
"""
|
||||
result = script.pip(
|
||||
'install', '--use-wheel', '--no-index',
|
||||
'install', '--no-index',
|
||||
'--find-links=' + data.find_links,
|
||||
'simplewheel[nonexistent, nope]', expect_stderr=True,
|
||||
)
|
||||
|
|
|
@ -372,7 +372,7 @@ class TestUpgradeSetuptools(object):
|
|||
self, script, data, virtualenv):
|
||||
self.prep_ve(script, '1.10', virtualenv.pip_source_dir)
|
||||
result = self.script.run(
|
||||
self.ve_bin / 'pip', 'install', '--use-wheel', '--no-index',
|
||||
self.ve_bin / 'pip', 'install', '--no-index',
|
||||
'--find-links=%s' % data.find_links, '-U', 'setuptools'
|
||||
)
|
||||
assert "Found existing installation: setuptools 0.9.7" in result.stdout
|
||||
|
|
|
@ -41,7 +41,7 @@ def test_install_from_wheel(script, data):
|
|||
Test installing from a wheel (that has a script)
|
||||
"""
|
||||
result = script.pip(
|
||||
'install', 'has.script==1.0', '--use-wheel', '--no-index',
|
||||
'install', 'has.script==1.0', '--no-index',
|
||||
'--find-links=' + data.find_links,
|
||||
expect_error=False,
|
||||
)
|
||||
|
@ -58,7 +58,7 @@ def test_install_from_wheel_with_extras(script, data):
|
|||
Test installing from a wheel with extras.
|
||||
"""
|
||||
result = script.pip(
|
||||
'install', 'complex-dist[simple]', '--use-wheel', '--no-index',
|
||||
'install', 'complex-dist[simple]', '--no-index',
|
||||
'--find-links=' + data.find_links,
|
||||
expect_error=False,
|
||||
)
|
||||
|
@ -107,7 +107,7 @@ def test_install_wheel_with_target(script, data):
|
|||
script.pip('install', 'wheel')
|
||||
target_dir = script.scratch_path / 'target'
|
||||
result = script.pip(
|
||||
'install', 'simple.dist==0.1', '-t', target_dir, '--use-wheel',
|
||||
'install', 'simple.dist==0.1', '-t', target_dir,
|
||||
'--no-index', '--find-links=' + data.find_links,
|
||||
)
|
||||
assert Path('scratch') / 'target' / 'simpledist' in result.files_created, (
|
||||
|
@ -121,7 +121,7 @@ def test_install_wheel_with_root(script, data):
|
|||
"""
|
||||
root_dir = script.scratch_path / 'root'
|
||||
result = script.pip(
|
||||
'install', 'simple.dist==0.1', '--root', root_dir, '--use-wheel',
|
||||
'install', 'simple.dist==0.1', '--root', root_dir,
|
||||
'--no-index', '--find-links=' + data.find_links,
|
||||
)
|
||||
assert Path('scratch') / 'root' in result.files_created
|
||||
|
@ -161,7 +161,7 @@ def test_install_user_wheel(script, virtualenv, data):
|
|||
virtualenv.system_site_packages = True
|
||||
script.pip('install', 'wheel')
|
||||
result = script.pip(
|
||||
'install', 'has.script==1.0', '--user', '--use-wheel', '--no-index',
|
||||
'install', 'has.script==1.0', '--user', '--no-index',
|
||||
'--find-links=' + data.find_links,
|
||||
)
|
||||
egg_info_folder = script.user_site / 'has.script-1.0.dist-info'
|
||||
|
@ -175,7 +175,7 @@ def test_install_from_wheel_gen_entrypoint(script, data):
|
|||
Test installing scripts (entry points are generated)
|
||||
"""
|
||||
result = script.pip(
|
||||
'install', 'script.wheel1a==0.1', '--use-wheel', '--no-index',
|
||||
'install', 'script.wheel1a==0.1', '--no-index',
|
||||
'--find-links=' + data.find_links,
|
||||
expect_error=False,
|
||||
)
|
||||
|
@ -194,7 +194,7 @@ def test_install_from_wheel_with_legacy(script, data):
|
|||
Test installing scripts (legacy scripts are preserved)
|
||||
"""
|
||||
result = script.pip(
|
||||
'install', 'script.wheel2a==0.1', '--use-wheel', '--no-index',
|
||||
'install', 'script.wheel2a==0.1', '--no-index',
|
||||
'--find-links=' + data.find_links,
|
||||
expect_error=False,
|
||||
)
|
||||
|
@ -212,7 +212,7 @@ def test_install_from_wheel_no_setuptools_entrypoint(script, data):
|
|||
the wheel are skipped.
|
||||
"""
|
||||
result = script.pip(
|
||||
'install', 'script.wheel1==0.1', '--use-wheel', '--no-index',
|
||||
'install', 'script.wheel1==0.1', '--no-index',
|
||||
'--find-links=' + data.find_links,
|
||||
expect_error=False,
|
||||
)
|
||||
|
@ -237,7 +237,7 @@ def test_skipping_setuptools_doesnt_skip_legacy(script, data):
|
|||
setuptools wrappers)
|
||||
"""
|
||||
result = script.pip(
|
||||
'install', 'script.wheel2==0.1', '--use-wheel', '--no-index',
|
||||
'install', 'script.wheel2==0.1', '--no-index',
|
||||
'--find-links=' + data.find_links,
|
||||
expect_error=False,
|
||||
)
|
||||
|
@ -256,7 +256,7 @@ def test_install_from_wheel_gui_entrypoint(script, data):
|
|||
Test installing scripts (gui entry points are generated)
|
||||
"""
|
||||
result = script.pip(
|
||||
'install', 'script.wheel3==0.1', '--use-wheel', '--no-index',
|
||||
'install', 'script.wheel3==0.1', '--no-index',
|
||||
'--find-links=' + data.find_links,
|
||||
expect_error=False,
|
||||
)
|
||||
|
|
|
@ -104,14 +104,13 @@ def test_no_clean_option_blocks_cleaning_after_wheel(script, data):
|
|||
@pytest.mark.network
|
||||
def test_pip_wheel_source_deps(script, data):
|
||||
"""
|
||||
Test 'pip wheel --use-wheel' finds and builds source archive dependencies
|
||||
Test 'pip wheel' finds and builds source archive dependencies
|
||||
of wheels
|
||||
"""
|
||||
# 'requires_source' is a wheel that depends on the 'source' project
|
||||
script.pip('install', 'wheel')
|
||||
result = script.pip(
|
||||
'wheel', '--use-wheel', '--no-index', '-f', data.find_links,
|
||||
'requires_source',
|
||||
'wheel', '--no-index', '-f', data.find_links, 'requires_source',
|
||||
)
|
||||
wheel_file_name = 'source-1.0-py%s-none-any.whl' % pyversion[0]
|
||||
wheel_file_path = script.scratch / 'wheelhouse' / wheel_file_name
|
||||
|
|
|
@ -126,7 +126,6 @@ class TestWheel:
|
|||
finder = PackageFinder(
|
||||
[data.find_links],
|
||||
[],
|
||||
use_wheel=True,
|
||||
session=PipSession(),
|
||||
)
|
||||
with pytest.raises(DistributionNotFound):
|
||||
|
@ -151,7 +150,6 @@ class TestWheel:
|
|||
finder = PackageFinder(
|
||||
[data.find_links],
|
||||
[],
|
||||
use_wheel=True,
|
||||
session=PipSession(),
|
||||
)
|
||||
|
||||
|
@ -172,7 +170,6 @@ class TestWheel:
|
|||
finder = PackageFinder(
|
||||
[data.find_links],
|
||||
[],
|
||||
use_wheel=True,
|
||||
session=PipSession(),
|
||||
)
|
||||
found = finder.find_requirement(req, True)
|
||||
|
@ -189,7 +186,6 @@ class TestWheel:
|
|||
finder = PackageFinder(
|
||||
[data.find_links],
|
||||
[],
|
||||
use_wheel=True,
|
||||
session=PipSession(),
|
||||
)
|
||||
found = finder.find_requirement(req, True)
|
||||
|
@ -211,7 +207,6 @@ class TestWheel:
|
|||
finder = PackageFinder(
|
||||
[data.find_links],
|
||||
[],
|
||||
use_wheel=True,
|
||||
session=PipSession(),
|
||||
)
|
||||
|
||||
|
@ -253,7 +248,6 @@ class TestWheel:
|
|||
]
|
||||
|
||||
finder = PackageFinder([], [], session=PipSession())
|
||||
finder.use_wheel = True
|
||||
|
||||
results = finder._sort_versions(links)
|
||||
results2 = finder._sort_versions(reversed(links))
|
||||
|
@ -269,7 +263,7 @@ class TestWheel:
|
|||
Link('simple-1.0-py2.py3-none-TEST.whl'),
|
||||
),
|
||||
]
|
||||
finder = PackageFinder([], [], use_wheel=True, session=PipSession())
|
||||
finder = PackageFinder([], [], session=PipSession())
|
||||
with pytest.raises(InstallationError):
|
||||
finder._sort_versions(links)
|
||||
|
||||
|
@ -698,7 +692,6 @@ class test_link_package_versions(object):
|
|||
self.finder = PackageFinder(
|
||||
[],
|
||||
[],
|
||||
use_wheel=True,
|
||||
session=PipSession(),
|
||||
)
|
||||
|
||||
|
|
|
@ -196,6 +196,14 @@ class TestGeneralOptions(object):
|
|||
options2, args2 = main(['fake', '--quiet'])
|
||||
assert options1.quiet == options2.quiet == 1
|
||||
|
||||
options3, args3 = main(['--quiet', '--quiet', 'fake'])
|
||||
options4, args4 = main(['fake', '--quiet', '--quiet'])
|
||||
assert options3.quiet == options4.quiet == 2
|
||||
|
||||
options5, args5 = main(['--quiet', '--quiet', '--quiet', 'fake'])
|
||||
options6, args6 = main(['fake', '--quiet', '--quiet', '--quiet'])
|
||||
assert options5.quiet == options6.quiet == 3
|
||||
|
||||
def test_log(self):
|
||||
options1, args1 = main(['--log', 'path', 'fake'])
|
||||
options2, args2 = main(['fake', '--log', 'path'])
|
||||
|
|
|
@ -116,7 +116,7 @@ class TestProcessLine(object):
|
|||
import pip.req.req_file
|
||||
|
||||
def stub_parse_requirements(req_url, finder, comes_from, options,
|
||||
session, cache_root):
|
||||
session, wheel_cache):
|
||||
return [req]
|
||||
parse_requirements_stub = stub(call=stub_parse_requirements)
|
||||
monkeypatch.setattr(pip.req.req_file, 'parse_requirements',
|
||||
|
|
Loading…
Reference in New Issue