summaryrefslogtreecommitdiff
path: root/pip/req.py
diff options
context:
space:
mode:
Diffstat (limited to 'pip/req.py')
-rw-r--r--pip/req.py132
1 files changed, 91 insertions, 41 deletions
diff --git a/pip/req.py b/pip/req.py
index ff423dfa2..d8ad1d737 100644
--- a/pip/req.py
+++ b/pip/req.py
@@ -1,29 +1,31 @@
-import sys
import os
-import shutil
import re
+import shutil
+import socket
+import sys
+import tempfile
+
import zipfile
import pkg_resources
-import tempfile
-from pip.locations import bin_py, running_under_virtualenv
+
+import requests
+
+from pip import call_subprocess
+from pip.index import Link
+from pip.log import logger
+from pip.locations import bin_py, running_under_virtualenv, build_prefix
from pip.exceptions import (InstallationError, UninstallationError,
BestVersionAlreadyInstalled)
from pip.vcs import vcs
-from pip.log import logger
-from pip.util import display_path, rmtree
-from pip.util import ask, ask_path_exists, backup_dir
-from pip.util import is_installable_dir, is_local, dist_is_local
-from pip.util import renames, normalize_path, egg_link_path
-from pip.util import make_path_relative
-from pip import call_subprocess
from pip.backwardcompat import (any, copytree, urlparse, urllib,
ConfigParser, string_types, HTTPError,
- FeedParser, get_python_version,
- b)
-from pip.index import Link
-from pip.locations import build_prefix
+ FeedParser, get_python_version, b,
+ WindowsError, URLError)
+from pip.util import (display_path, rmtree, ask, ask_path_exists, backup_dir,
+ is_installable_dir, is_local, dist_is_local, renames,
+ normalize_path, egg_link_path, make_path_relative, Inf)
from pip.download import (get_file_content, is_url, url_to_path,
- path_to_url, is_archive_file,
+ path_to_url, is_archive_file, urlopen,
unpack_vcs_link, is_vcs_url, is_file_url,
unpack_file_url, unpack_http_url)
@@ -44,6 +46,7 @@ class InstallRequirement(object):
self.source_dir = source_dir
self.editable = editable
self.url = url
+ self.urls = []
self._egg_info_path = None
# This holds the pkg_resources.Distribution object if this requirement
# is already available:
@@ -59,6 +62,8 @@ class InstallRequirement(object):
self.install_succeeded = None
# UninstallPathSet of uninstalled distribution (for possible rollback)
self.uninstalled = None
+ # The server signature from PyPI
+ self._serversigs = {}
@classmethod
def from_editable(cls, editable_req, comes_from=None, default_vcs=None):
@@ -71,7 +76,8 @@ class InstallRequirement(object):
@classmethod
def from_line(cls, name, comes_from=None):
- """Creates an InstallRequirement from a name, which might be a
+ """
+ Creates an InstallRequirement from a name, which might be a
requirement, directory containing 'setup.py', filename, or URL.
"""
url = None
@@ -84,7 +90,8 @@ class InstallRequirement(object):
link = Link(name)
elif os.path.isdir(path) and (os.path.sep in name or name.startswith('.')):
if not is_installable_dir(path):
- raise InstallationError("Directory %r is not installable. File 'setup.py' not found.", name)
+ raise InstallationError("Directory %r is not installable. "
+ "File 'setup.py' not found.", name)
link = Link(path_to_url(name))
elif is_archive_file(path):
if not os.path.isfile(path):
@@ -198,6 +205,21 @@ class InstallRequirement(object):
def setup_py(self):
return os.path.join(self.source_dir, 'setup.py')
+ def serversig(self, base_url):
+ if base_url not in self._serversigs:
+ if self.req is not None:
+ sig_url = '%s/serversig/%s' % (base_url, self.url_name)
+ try:
+ response = urlopen(sig_url)
+ self._serversigs[base_url] = response.content
+ except (HTTPError, URLError, socket.timeout,
+ socket.error, OSError, WindowsError,
+ requests.RequestException):
+ # return empty string in case this was just a
+ # temporary connection failure
+ return ''
+ return self._serversigs.get(base_url, '')
+
def run_egg_info(self, force_root_egg_info=False):
assert self.source_dir
if self.name:
@@ -477,11 +499,12 @@ exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))
config.readfp(FakeFile(dist.get_metadata_lines('entry_points.txt')))
if config.has_section('console_scripts'):
for name, value in config.items('console_scripts'):
- paths_to_remove.add(os.path.join(bin_py, name))
+ this_bin = os.path.join(bin_py, name)
+ paths_to_remove.add(this_bin)
if sys.platform == 'win32':
- paths_to_remove.add(os.path.join(bin_py, name) + '.exe')
- paths_to_remove.add(os.path.join(bin_py, name) + '.exe.manifest')
- paths_to_remove.add(os.path.join(bin_py, name) + '-script.py')
+ paths_to_remove.add(this_bin + '.exe')
+ paths_to_remove.add(this_bin + '.exe.manifest')
+ paths_to_remove.add(this_bin + '-script.py')
paths_to_remove.remove(auto_confirm)
self.uninstalled = paths_to_remove
@@ -785,6 +808,8 @@ class RequirementSet(object):
self.build_dir = build_dir
self.src_dir = src_dir
self.download_dir = download_dir
+ if download_cache is not None:
+ download_cache = os.path.expanduser(download_cache)
self.download_cache = download_cache
self.upgrade = upgrade
self.ignore_installed = ignore_installed
@@ -900,7 +925,10 @@ class RequirementSet(object):
% (req_to_install, req_to_install.source_dir))
def prepare_files(self, finder, force_root_egg_info=False, bundle=False):
- """Prepare process. Create temp directories, download and/or unpack files."""
+ """
+ Prepare process. Create temp directories, download
+ and/or unpack files.
+ """
unnamed = list(self.unnamed_requirements)
reqs = list(self.requirements.values())
while reqs or unnamed:
@@ -923,7 +951,7 @@ class RequirementSet(object):
install = False
else:
# Avoid the need to call find_requirement again
- req_to_install.url = url.url
+ req_to_install.urls = url
if not best_installed:
req_to_install.conflicts_with = req_to_install.satisfied_by
@@ -975,21 +1003,39 @@ class RequirementSet(object):
if not os.path.exists(os.path.join(location, 'setup.py')):
## FIXME: this won't upgrade when there's an existing package unpacked in `location`
if req_to_install.url is None:
- url = finder.find_requirement(req_to_install, upgrade=self.upgrade)
- else:
+ urls = finder.find_requirement(req_to_install, upgrade=self.upgrade)
+ elif req_to_install.urls:
## FIXME: should req_to_install.url already be a link?
- url = Link(req_to_install.url)
- assert url
- if url:
- try:
- self.unpack_url(url, location, self.is_download)
- except HTTPError:
- e = sys.exc_info()[1]
- logger.fatal('Could not install requirement %s because of error %s'
- % (req_to_install, e))
- raise InstallationError(
- 'Could not install requirement %s because of HTTP error %s for URL %s'
- % (req_to_install, e, url))
+ # print req_to_install.url
+ urls = [Link(url.url, mirror_urls=finder.mirror_urls)
+ for url in req_to_install.urls]
+ if urls:
+ # Trying each of the returned URLs one by one
+ for url in urls:
+ if url.is_mirror:
+ if finder.verify(req_to_install, url):
+ logger.warn('Verifying %s: successful' % url)
+ else:
+ logger.warn('Verifying %s: failed' % url)
+ continue
+ try:
+ self.unpack_url(url, location, self.is_download)
+ except HTTPError:
+ e = sys.exc_info()[1]
+ logger.fatal('Could not install '
+ 'requirement %s because of error %s' %
+ (req_to_install, e))
+ raise InstallationError('Could not '
+ 'install requirement %s because of '
+ 'HTTP error %s for URL %s' %
+ (req_to_install, e, url))
+ else:
+ # stop trying after successful retrieval
+ break
+ else:
+ raise InstallationError('Could not install '
+ 'requirement %s because no valid URLs '
+ 'were found.' % req_to_install)
else:
unpack = False
if unpack:
@@ -1012,7 +1058,7 @@ class RequirementSet(object):
# directory is created for packing in the bundle
req_to_install.run_egg_info(force_root_egg_info=True)
req_to_install.assert_source_matches_version()
- #@@ sketchy way of identifying packages not grabbed from an index
+ # @@ sketchy way of identifying packages not grabbed from an index
if bundle and req_to_install.url:
self.copy_to_build_dir(req_to_install)
install = False
@@ -1029,7 +1075,8 @@ class RequirementSet(object):
## FIXME: shouldn't be globally added:
finder.add_dependency_links(req_to_install.dependency_links)
if (req_to_install.extras):
- logger.notify("Installing extra requirements: %r" % ','.join(req_to_install.extras))
+ logger.notify("Installing extra requirements: %r" %
+ ','.join(req_to_install.extras))
if not self.ignore_dependencies:
for req in req_to_install.requirements(req_to_install.extras):
try:
@@ -1112,7 +1159,10 @@ class RequirementSet(object):
return retval
def install(self, install_options, global_options=()):
- """Install everything in this set (after having downloaded and unpacked the packages)"""
+ """
+ Install everything in this set
+ (after having downloaded and unpacked the packages)
+ """
to_install = [r for r in self.requirements.values()
if not r.satisfied_by]