mirror of
https://github.com/pypa/pip
synced 2023-12-13 21:30:23 +01:00
Merge branch 'develop'
This commit is contained in:
commit
0001b1b6ef
|
@ -13,7 +13,7 @@ matrix:
|
|||
env: TOXENV=py33
|
||||
- python: 3.4
|
||||
env: TOXENV=py34
|
||||
- python: nightly
|
||||
- python: 3.5-dev
|
||||
env: TOXENV=py35
|
||||
- python: pypy
|
||||
env: TOXENV=pypy
|
||||
|
|
|
@ -46,7 +46,7 @@ if [[ $VENDOR = "no" ]]; then
|
|||
fi
|
||||
|
||||
# Run the unit tests
|
||||
tox -- -m unit --cov pip/ --cov-report xml $TOXARGS
|
||||
tox -- -m unit $TOXARGS
|
||||
|
||||
# Run our integration tests
|
||||
# Note: There is an issue with Python 3.2 where concurrent imports will corrupt
|
||||
|
|
|
@ -88,7 +88,7 @@ Ionel Cristian Mărieș <contact@ionelmc.ro>
|
|||
Ionel Maries Cristian <ionel.mc@gmail.com>
|
||||
Jakub Stasiak <kuba.stasiak@gmail.com>
|
||||
Jakub Vysoky <jakub@borka.cz>
|
||||
James Cleveland <jamescleveland@gmail.com>
|
||||
James Cleveland <jc@blit.cc>
|
||||
James Polley <jp@jamezpolley.com>
|
||||
Jan Pokorný <jpokorny@redhat.com>
|
||||
Jannis Leidel <jannis@leidel.info>
|
||||
|
|
30
CHANGES.txt
30
CHANGES.txt
|
@ -1,9 +1,37 @@
|
|||
**7.1.1 (unreleased)**
|
||||
|
||||
* Check that the wheel cache directory is writable before we attempt to write
|
||||
cached files to them.
|
||||
|
||||
* Move the pip version check until *after* any installs have been performed,
|
||||
thus removing the extraenous warning when upgrading pip.
|
||||
|
||||
* Added debug logging when using a cached wheel.
|
||||
|
||||
* Respect platlib by default on platforms that have it separated from purlib.
|
||||
|
||||
* Upgrade packaging to 15.3.
|
||||
|
||||
* Normalize post-release spellings for rev/r prefixes.
|
||||
|
||||
* Upgrade distlib to 0.2.1.
|
||||
|
||||
* Updated launchers to decode shebangs using UTF-8. This allows non-ASCII
|
||||
pathnames to be correctly handled.
|
||||
|
||||
* Ensured that the executable written to shebangs is normcased.
|
||||
|
||||
* Changed ScriptMaker to work better under Jython.
|
||||
|
||||
* Upgrade ipaddress to 1.0.13.
|
||||
|
||||
|
||||
**7.1.0 (2015-06-30)**
|
||||
|
||||
* Allow constraining versions globally without having to know exactly what will
|
||||
be installed by the pip command. :issue:`2731`.
|
||||
|
||||
* Accept --no-binary and --only-binary via pip.conf. :issue`2867`.
|
||||
* Accept --no-binary and --only-binary via pip.conf. :issue:`2867`.
|
||||
|
||||
* Allow ``--allow-all-external`` within a requirements file.
|
||||
|
||||
|
|
|
@ -2,9 +2,8 @@ https://github.com/spulec/freezegun/archive/master.zip#egg=freezegun
|
|||
pretend
|
||||
pytest
|
||||
pytest-capturelog
|
||||
pytest-cov
|
||||
pytest-timeout
|
||||
pytest-xdist
|
||||
mock
|
||||
mock<1.1
|
||||
scripttest>=1.3
|
||||
https://github.com/pypa/virtualenv/archive/develop.zip#egg=virtualenv
|
||||
|
|
|
@ -124,7 +124,7 @@ If you wish, you can refer to other requirements files, like this::
|
|||
|
||||
-r more_requirements.txt
|
||||
|
||||
You can also refer to constraints files, like this::
|
||||
You can also refer to :ref:`constraints files <Constraints Files>`, like this::
|
||||
|
||||
-c some_constraints.txt
|
||||
|
||||
|
@ -386,7 +386,7 @@ similarly to that of a web browser. While the cache is on by default and is
|
|||
designed do the right thing by default you can disable the cache and always
|
||||
access PyPI by utilizing the ``--no-cache-dir`` option.
|
||||
|
||||
When making any HTTP request pip will first check it's local cache to determine
|
||||
When making any HTTP request pip will first check its local cache to determine
|
||||
if it has a suitable response stored for that request which has not expired. If
|
||||
it does then it simply returns that response and doesn't make the request.
|
||||
|
||||
|
@ -396,13 +396,13 @@ response telling pip to simply use the cached item (and refresh the expiration
|
|||
timer) or it will return a whole new response which pip can then store in the
|
||||
cache.
|
||||
|
||||
When storing items in the cache pip will respect the ``CacheControl`` header
|
||||
When storing items in the cache, pip will respect the ``CacheControl`` header
|
||||
if it exists, or it will fall back to the ``Expires`` header if that exists.
|
||||
This allows pip to function as a browser would, and allows the index server
|
||||
to communicate to pip how long it is reasonable to cache any particular item.
|
||||
|
||||
While this cache attempts to minimize network activity, it does not prevent
|
||||
network access all together. If you want a fast/local install solution that
|
||||
network access altogether. If you want a fast/local install solution that
|
||||
circumvents accessing PyPI, see :ref:`Fast & Local Installs`.
|
||||
|
||||
The default location for the cache directory depends on the Operating System:
|
||||
|
@ -421,15 +421,15 @@ Wheel cache
|
|||
Pip will read from the subdirectory ``wheels`` within the pip cache dir and use
|
||||
any packages found there. This is disabled via the same ``no-cache-dir`` option
|
||||
that disables the HTTP cache. The internal structure of that cache is not part
|
||||
of the Pip API. As of 7.0 pip uses a subdirectory per sdist that wheels were
|
||||
of the pip API. As of 7.0 pip uses a subdirectory per sdist that wheels were
|
||||
built from, and wheels within that subdirectory.
|
||||
|
||||
Pip attempts to choose the best wheels from those built in preference to
|
||||
building a new wheel. Note that this means when a package has both optional
|
||||
C extensions and builds `py` tagged wheels when the C extension can't be built
|
||||
that pip will not attempt to build a better wheel for Python's that would have
|
||||
that pip will not attempt to build a better wheel for Pythons that would have
|
||||
supported it, once any generic wheel is built. To correct this, make sure that
|
||||
the wheel's are built with Python specific tags - e.g. pp on Pypy.
|
||||
the wheels are built with Python specific tags - e.g. pp on Pypy.
|
||||
|
||||
When no wheels are found for an sdist, pip will attempt to build a wheel
|
||||
automatically and insert it into the wheel cache.
|
||||
|
|
|
@ -30,7 +30,7 @@ import pip.cmdoptions
|
|||
cmdoptions = pip.cmdoptions
|
||||
|
||||
# The version as used in the setup.py and the docs conf.py
|
||||
__version__ = "7.1.0"
|
||||
__version__ = "7.1.1.dev0"
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
|
@ -18,7 +18,7 @@ Modifications
|
|||
_markerlib and pkg_resources
|
||||
============================
|
||||
|
||||
_markerlib and pkg_resources has been pulled in from setuptools 18.0
|
||||
_markerlib and pkg_resources has been pulled in from setuptools 18.2
|
||||
|
||||
|
||||
Note to Downstream Distributors
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#
|
||||
import logging
|
||||
|
||||
__version__ = '0.2.0'
|
||||
__version__ = '0.2.1'
|
||||
|
||||
class DistlibException(Exception):
|
||||
pass
|
||||
|
|
|
@ -10,7 +10,7 @@ import os
|
|||
import re
|
||||
import sys
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
if sys.version_info[0] < 3: # pragma: no cover
|
||||
from StringIO import StringIO
|
||||
string_types = basestring,
|
||||
text_type = unicode
|
||||
|
@ -53,7 +53,7 @@ if sys.version_info[0] < 3:
|
|||
if match: return match.group(1, 2)
|
||||
return None, host
|
||||
|
||||
else:
|
||||
else: # pragma: no cover
|
||||
from io import StringIO
|
||||
string_types = str,
|
||||
text_type = str
|
||||
|
@ -81,7 +81,7 @@ else:
|
|||
|
||||
try:
|
||||
from ssl import match_hostname, CertificateError
|
||||
except ImportError:
|
||||
except ImportError: # pragma: no cover
|
||||
class CertificateError(ValueError):
|
||||
pass
|
||||
|
||||
|
@ -181,7 +181,7 @@ except ImportError:
|
|||
|
||||
try:
|
||||
from types import SimpleNamespace as Container
|
||||
except ImportError:
|
||||
except ImportError: # pragma: no cover
|
||||
class Container(object):
|
||||
"""
|
||||
A generic container for when multiple values need to be returned
|
||||
|
@ -192,7 +192,7 @@ except ImportError:
|
|||
|
||||
try:
|
||||
from shutil import which
|
||||
except ImportError:
|
||||
except ImportError: # pragma: no cover
|
||||
# Implementation from Python 3.3
|
||||
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
|
||||
"""Given a command, mode, and a PATH string, return the path which
|
||||
|
@ -261,7 +261,7 @@ except ImportError:
|
|||
|
||||
from zipfile import ZipFile as BaseZipFile
|
||||
|
||||
if hasattr(BaseZipFile, '__enter__'):
|
||||
if hasattr(BaseZipFile, '__enter__'): # pragma: no cover
|
||||
ZipFile = BaseZipFile
|
||||
else:
|
||||
from zipfile import ZipExtFile as BaseZipExtFile
|
||||
|
|
|
@ -366,9 +366,11 @@ class Distribution(object):
|
|||
return plist
|
||||
|
||||
def _get_requirements(self, req_attr):
|
||||
reqts = getattr(self.metadata, req_attr)
|
||||
return set(self.metadata.get_requirements(reqts, extras=self.extras,
|
||||
env=self.context))
|
||||
md = self.metadata
|
||||
logger.debug('Getting requirements from metadata %r', md.todict())
|
||||
reqts = getattr(md, req_attr)
|
||||
return set(md.get_requirements(reqts, extras=self.extras,
|
||||
env=self.context))
|
||||
|
||||
@property
|
||||
def run_requires(self):
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2012-2014 Vinay Sajip.
|
||||
# Copyright (C) 2012-2015 Vinay Sajip.
|
||||
# Licensed to the Python Software Foundation under a contributor agreement.
|
||||
# See LICENSE.txt and CONTRIBUTORS.txt.
|
||||
#
|
||||
|
@ -165,8 +165,13 @@ class Locator(object):
|
|||
for a given project release.
|
||||
"""
|
||||
t = urlparse(url)
|
||||
basename = posixpath.basename(t.path)
|
||||
compatible = True
|
||||
is_wheel = basename.endswith('.whl')
|
||||
if is_wheel:
|
||||
compatible = is_compatible(Wheel(basename), self.wheel_tags)
|
||||
return (t.scheme != 'https', 'pypi.python.org' in t.netloc,
|
||||
posixpath.basename(t.path))
|
||||
is_wheel, compatible, basename)
|
||||
|
||||
def prefer_url(self, url1, url2):
|
||||
"""
|
||||
|
@ -174,8 +179,9 @@ class Locator(object):
|
|||
archives for the same version of a distribution (for example,
|
||||
.tar.gz vs. zip).
|
||||
|
||||
The current implement favours http:// URLs over https://, archives
|
||||
from PyPI over those from other locations and then the archive name.
|
||||
The current implementation favours https:// URLs over http://, archives
|
||||
from PyPI over those from other locations, wheel compatibility (if a
|
||||
wheel) and then the archive name.
|
||||
"""
|
||||
result = url2
|
||||
if url1:
|
||||
|
@ -332,11 +338,13 @@ class Locator(object):
|
|||
self.matcher = matcher = scheme.matcher(r.requirement)
|
||||
logger.debug('matcher: %s (%s)', matcher, type(matcher).__name__)
|
||||
versions = self.get_project(r.name)
|
||||
if versions:
|
||||
if len(versions) > 2: # urls and digests keys are present
|
||||
# sometimes, versions are invalid
|
||||
slist = []
|
||||
vcls = matcher.version_class
|
||||
for k in versions:
|
||||
if k in ('urls', 'digests'):
|
||||
continue
|
||||
try:
|
||||
if not matcher.match(k):
|
||||
logger.debug('%s did not match %r', matcher, k)
|
||||
|
@ -447,17 +455,39 @@ class PyPIJSONLocator(Locator):
|
|||
md.keywords = data.get('keywords', [])
|
||||
md.summary = data.get('summary')
|
||||
dist = Distribution(md)
|
||||
dist.locator = self
|
||||
urls = d['urls']
|
||||
if urls:
|
||||
info = urls[0]
|
||||
md.source_url = info['url']
|
||||
dist.digest = self._get_digest(info)
|
||||
dist.locator = self
|
||||
result[md.version] = dist
|
||||
for info in urls:
|
||||
result[md.version] = dist
|
||||
for info in d['urls']:
|
||||
url = info['url']
|
||||
dist.download_urls.add(url)
|
||||
dist.digests[url] = self._get_digest(info)
|
||||
result['urls'].setdefault(md.version, set()).add(url)
|
||||
result['digests'][url] = self._get_digest(info)
|
||||
# Now get other releases
|
||||
for version, infos in d['releases'].items():
|
||||
if version == md.version:
|
||||
continue # already done
|
||||
omd = Metadata(scheme=self.scheme)
|
||||
omd.name = md.name
|
||||
omd.version = version
|
||||
odist = Distribution(omd)
|
||||
odist.locator = self
|
||||
result[version] = odist
|
||||
for info in infos:
|
||||
url = info['url']
|
||||
result['urls'].setdefault(md.version, set()).add(url)
|
||||
result['digests'][url] = digest
|
||||
odist.download_urls.add(url)
|
||||
odist.digests[url] = self._get_digest(info)
|
||||
result['urls'].setdefault(version, set()).add(url)
|
||||
result['digests'][url] = self._get_digest(info)
|
||||
# for info in urls:
|
||||
# md.source_url = info['url']
|
||||
# dist.digest = self._get_digest(info)
|
||||
# dist.locator = self
|
||||
# for info in urls:
|
||||
# url = info['url']
|
||||
# result['urls'].setdefault(md.version, set()).add(url)
|
||||
# result['digests'][url] = self._get_digest(info)
|
||||
except Exception as e:
|
||||
logger.exception('JSON fetch failed: %s', e)
|
||||
return result
|
||||
|
@ -885,11 +915,12 @@ class DistPathLocator(Locator):
|
|||
def _get_project(self, name):
|
||||
dist = self.distpath.get_distribution(name)
|
||||
if dist is None:
|
||||
result = {}
|
||||
result = {'urls': {}, 'digests': {}}
|
||||
else:
|
||||
result = {
|
||||
dist.version: dist,
|
||||
'urls': {dist.version: set([dist.source_url])}
|
||||
'urls': {dist.version: set([dist.source_url])},
|
||||
'digests': {dist.version: set([None])}
|
||||
}
|
||||
return result
|
||||
|
||||
|
|
|
@ -120,6 +120,12 @@ class ResourceFinder(object):
|
|||
"""
|
||||
Resource finder for file system resources.
|
||||
"""
|
||||
|
||||
if sys.platform.startswith('java'):
|
||||
skipped_extensions = ('.pyc', '.pyo', '.class')
|
||||
else:
|
||||
skipped_extensions = ('.pyc', '.pyo')
|
||||
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.loader = getattr(module, '__loader__', None)
|
||||
|
@ -170,7 +176,8 @@ class ResourceFinder(object):
|
|||
|
||||
def get_resources(self, resource):
|
||||
def allowed(f):
|
||||
return f != '__pycache__' and not f.endswith(('.pyc', '.pyo'))
|
||||
return (f != '__pycache__' and not
|
||||
f.endswith(self.skipped_extensions))
|
||||
return set([f for f in os.listdir(resource.path) if allowed(f)])
|
||||
|
||||
def is_container(self, resource):
|
||||
|
@ -178,6 +185,26 @@ class ResourceFinder(object):
|
|||
|
||||
_is_directory = staticmethod(os.path.isdir)
|
||||
|
||||
def iterator(self, resource_name):
|
||||
resource = self.find(resource_name)
|
||||
if resource is not None:
|
||||
todo = [resource]
|
||||
while todo:
|
||||
resource = todo.pop(0)
|
||||
yield resource
|
||||
if resource.is_container:
|
||||
rname = resource.name
|
||||
for name in resource.resources:
|
||||
if not rname:
|
||||
new_name = name
|
||||
else:
|
||||
new_name = '/'.join([rname, name])
|
||||
child = self.find(new_name)
|
||||
if child.is_container:
|
||||
todo.append(child)
|
||||
else:
|
||||
yield child
|
||||
|
||||
|
||||
class ZipResourceFinder(ResourceFinder):
|
||||
"""
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2013-2014 Vinay Sajip.
|
||||
# Copyright (C) 2013-2015 Vinay Sajip.
|
||||
# Licensed to the Python Software Foundation under a contributor agreement.
|
||||
# See LICENSE.txt and CONTRIBUTORS.txt.
|
||||
#
|
||||
|
@ -80,7 +80,8 @@ class ScriptMaker(object):
|
|||
self.force = False
|
||||
self.clobber = False
|
||||
# It only makes sense to set mode bits on POSIX.
|
||||
self.set_mode = (os.name == 'posix')
|
||||
self.set_mode = (os.name == 'posix') or (os.name == 'java' and
|
||||
os._name == 'posix')
|
||||
self.variants = set(('', 'X.Y'))
|
||||
self._fileop = fileop or FileOperator(dry_run)
|
||||
|
||||
|
@ -91,6 +92,31 @@ class ScriptMaker(object):
|
|||
executable = os.path.join(dn, fn)
|
||||
return executable
|
||||
|
||||
if sys.platform.startswith('java'): # pragma: no cover
|
||||
def _is_shell(self, executable):
|
||||
"""
|
||||
Determine if the specified executable is a script
|
||||
(contains a #! line)
|
||||
"""
|
||||
try:
|
||||
with open(executable) as fp:
|
||||
return fp.read(2) == '#!'
|
||||
except (OSError, IOError):
|
||||
logger.warning('Failed to open %s', executable)
|
||||
return False
|
||||
|
||||
def _fix_jython_executable(self, executable):
|
||||
if self._is_shell(executable):
|
||||
# Workaround for Jython is not needed on Linux systems.
|
||||
import java
|
||||
|
||||
if java.lang.System.getProperty('os.name') == 'Linux':
|
||||
return executable
|
||||
elif executable.lower().endswith('jython.exe'):
|
||||
# Use wrapper exe for Jython on Windows
|
||||
return executable
|
||||
return '/usr/bin/env %s' % executable
|
||||
|
||||
def _get_shebang(self, encoding, post_interp=b'', options=None):
|
||||
enquote = True
|
||||
if self.executable:
|
||||
|
@ -109,6 +135,10 @@ class ScriptMaker(object):
|
|||
if options:
|
||||
executable = self._get_alternate_executable(executable, options)
|
||||
|
||||
if sys.platform.startswith('java'): # pragma: no cover
|
||||
executable = self._fix_jython_executable(executable)
|
||||
# Normalise case for Windows
|
||||
executable = os.path.normcase(executable)
|
||||
# If the user didn't specify an executable, it may be necessary to
|
||||
# cater for executable paths with spaces (not uncommon on Windows)
|
||||
if enquote and ' ' in executable:
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -163,7 +163,7 @@ def get_executable():
|
|||
# else:
|
||||
# result = sys.executable
|
||||
# return result
|
||||
return sys.executable
|
||||
return os.path.normcase(sys.executable)
|
||||
|
||||
|
||||
def proceed(prompt, allowed_chars, error_prompt=None, default=None):
|
||||
|
@ -397,7 +397,7 @@ class FileOperator(object):
|
|||
self.record_as_written(path)
|
||||
|
||||
def set_mode(self, bits, mask, files):
|
||||
if os.name == 'posix':
|
||||
if os.name == 'posix' or (os.name == 'java' and os._name == 'posix'):
|
||||
# Set the executable bits (owner, group, and world) on
|
||||
# all the files specified.
|
||||
for f in files:
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -74,7 +74,7 @@ FILENAME_RE = re.compile(r'''
|
|||
(-(?P<bn>\d+[^-]*))?
|
||||
-(?P<py>\w+\d+(\.\w+\d+)*)
|
||||
-(?P<bi>\w+)
|
||||
-(?P<ar>\w+)
|
||||
-(?P<ar>\w+(\.\w+)*)
|
||||
\.whl$
|
||||
''', re.IGNORECASE | re.VERBOSE)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -22,7 +22,7 @@ __title__ = "packaging"
|
|||
__summary__ = "Core utilities for Python packages"
|
||||
__uri__ = "https://github.com/pypa/packaging"
|
||||
|
||||
__version__ = "15.2"
|
||||
__version__ = "15.3"
|
||||
|
||||
__author__ = "Donald Stufft"
|
||||
__email__ = "donald@stufft.io"
|
||||
|
|
|
@ -324,6 +324,8 @@ def _parse_letter_version(letter, number):
|
|||
letter = "b"
|
||||
elif letter in ["c", "pre", "preview"]:
|
||||
letter = "rc"
|
||||
elif letter in ["rev", "r"]:
|
||||
letter = "post"
|
||||
|
||||
return letter, int(number)
|
||||
if not letter and number:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
distlib==0.2.0
|
||||
distlib==0.2.1
|
||||
html5lib==1.0b5
|
||||
six==1.9.0
|
||||
colorama==0.3.3
|
||||
|
@ -6,6 +6,6 @@ requests==2.7.0
|
|||
CacheControl==0.11.5
|
||||
lockfile==0.10.2
|
||||
progress==1.2
|
||||
ipaddress==1.0.7 # Only needed on 2.6, 2.7, and 3.2
|
||||
packaging==15.2
|
||||
ipaddress==1.0.14 # Only needed on 2.6, 2.7, and 3.2
|
||||
packaging==15.3
|
||||
retrying==1.3.3
|
||||
|
|
|
@ -4,12 +4,9 @@ from __future__ import absolute_import
|
|||
import logging
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
import optparse
|
||||
import warnings
|
||||
|
||||
from pip._vendor.six import StringIO
|
||||
|
||||
from pip import cmdoptions
|
||||
from pip.locations import running_under_virtualenv
|
||||
from pip.download import PipSession
|
||||
|
@ -210,15 +207,6 @@ class Command(object):
|
|||
)
|
||||
sys.exit(VIRTUALENV_NOT_FOUND)
|
||||
|
||||
# Check if we're using the latest version of pip available
|
||||
if (not options.disable_pip_version_check and not
|
||||
getattr(options, "no_index", False)):
|
||||
with self._build_session(
|
||||
options,
|
||||
retries=0,
|
||||
timeout=min(5, options.timeout)) as session:
|
||||
pip_version_check(session)
|
||||
|
||||
try:
|
||||
status = self.run(options, args)
|
||||
# FIXME: all commands should return an exit status
|
||||
|
@ -227,28 +215,37 @@ class Command(object):
|
|||
return status
|
||||
except PreviousBuildDirError as exc:
|
||||
logger.critical(str(exc))
|
||||
logger.debug('Exception information:\n%s', format_exc())
|
||||
logger.debug('Exception information:', exc_info=True)
|
||||
|
||||
return PREVIOUS_BUILD_DIR_ERROR
|
||||
except (InstallationError, UninstallationError, BadCommand) as exc:
|
||||
logger.critical(str(exc))
|
||||
logger.debug('Exception information:\n%s', format_exc())
|
||||
logger.debug('Exception information:', exc_info=True)
|
||||
|
||||
return ERROR
|
||||
except CommandError as exc:
|
||||
logger.critical('ERROR: %s', exc)
|
||||
logger.debug('Exception information:\n%s', format_exc())
|
||||
logger.debug('Exception information:', exc_info=True)
|
||||
|
||||
return ERROR
|
||||
except KeyboardInterrupt:
|
||||
logger.critical('Operation cancelled by user')
|
||||
logger.debug('Exception information:\n%s', format_exc())
|
||||
logger.debug('Exception information:', exc_info=True)
|
||||
|
||||
return ERROR
|
||||
except:
|
||||
logger.critical('Exception:\n%s', format_exc())
|
||||
logger.critical('Exception:', exc_info=True)
|
||||
|
||||
return UNKNOWN_ERROR
|
||||
finally:
|
||||
# Check if we're using the latest version of pip available
|
||||
if (not options.disable_pip_version_check and not
|
||||
getattr(options, "no_index", False)):
|
||||
with self._build_session(
|
||||
options,
|
||||
retries=0,
|
||||
timeout=min(5, options.timeout)) as session:
|
||||
pip_version_check(session)
|
||||
|
||||
return SUCCESS
|
||||
|
||||
|
@ -306,11 +303,3 @@ class RequirementCommand(Command):
|
|||
msg = ('You must give at least one requirement '
|
||||
'to %(name)s (see "pip help %(name)s")' % opts)
|
||||
logger.warning(msg)
|
||||
|
||||
|
||||
def format_exc(exc_info=None):
|
||||
if exc_info is None:
|
||||
exc_info = sys.exc_info()
|
||||
out = StringIO()
|
||||
traceback.print_exception(*exc_info, **dict(file=out))
|
||||
return out.getvalue()
|
||||
|
|
|
@ -22,6 +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.utils.filesystem import check_path_owner
|
||||
from pip.wheel import WheelCache, WheelBuilder
|
||||
|
||||
|
||||
|
@ -246,6 +247,17 @@ 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, options.format_control)
|
||||
if options.cache_dir and not check_path_owner(options.cache_dir):
|
||||
logger.warning(
|
||||
"The directory '%s' or its parent directory is not owned "
|
||||
"by the current user and caching wheels has been "
|
||||
"disabled. check the permissions and owner of that "
|
||||
"directory. If executing pip with sudo, you may want "
|
||||
"sudo's -H flag.",
|
||||
options.cache_dir,
|
||||
)
|
||||
options.cache_dir = None
|
||||
|
||||
with BuildDirectory(options.build_dir,
|
||||
delete=build_delete) as build_dir:
|
||||
requirement_set = RequirementSet(
|
||||
|
|
|
@ -193,8 +193,12 @@ def distutils_scheme(dist_name, user=False, home=None, root=None,
|
|||
for key in SCHEME_KEYS:
|
||||
scheme[key] = getattr(i, 'install_' + key)
|
||||
|
||||
if i.install_lib is not None:
|
||||
# install_lib takes precedence over purelib and platlib
|
||||
# install_lib specified in setup.cfg should install *everything*
|
||||
# into there (i.e. it takes precedence over both purelib and
|
||||
# platlib). Note, i.install_lib is *always* set after
|
||||
# finalize_options(); we only want to override here if the user
|
||||
# has explicitly requested it hence going back to the config
|
||||
if 'install_lib' in d.get_option_dict('install'):
|
||||
scheme.update(dict(purelib=i.install_lib, platlib=i.install_lib))
|
||||
|
||||
if running_under_virtualenv():
|
||||
|
|
|
@ -31,6 +31,7 @@ from pip.utils import (
|
|||
display_path, rmtree, ask_path_exists, backup_dir, is_installable_dir,
|
||||
dist_in_usersite, dist_in_site_packages, egg_link_path, make_path_relative,
|
||||
call_subprocess, read_text_file, FakeFile, _make_build_dir, ensure_dir,
|
||||
get_installed_version
|
||||
)
|
||||
from pip.utils.deprecation import RemovedInPip8Warning
|
||||
from pip.utils.logging import indent_log
|
||||
|
@ -259,6 +260,8 @@ class InstallRequirement(object):
|
|||
self._link = link
|
||||
else:
|
||||
self._link = self._wheel_cache.cached_wheel(link, self.name)
|
||||
if self._link != link:
|
||||
logger.debug('Using cached wheel link: %s', self._link)
|
||||
|
||||
@property
|
||||
def specifier(self):
|
||||
|
@ -527,20 +530,7 @@ exec(compile(
|
|||
|
||||
@property
|
||||
def installed_version(self):
|
||||
# Create a requirement that we'll look for inside of setuptools.
|
||||
req = pkg_resources.Requirement.parse(self.name)
|
||||
|
||||
# We want to avoid having this cached, so we need to construct a new
|
||||
# working set each time.
|
||||
working_set = pkg_resources.WorkingSet()
|
||||
|
||||
# Get the installed distribution from our working set
|
||||
dist = working_set.find(req)
|
||||
|
||||
# Check to see if we got an installed distribution or not, if we did
|
||||
# we want to return it's version.
|
||||
if dist:
|
||||
return dist.version
|
||||
return get_installed_version(self.name)
|
||||
|
||||
def assert_source_matches_version(self):
|
||||
assert self.source_dir
|
||||
|
|
|
@ -39,7 +39,8 @@ __all__ = ['rmtree', 'display_path', 'backup_dir',
|
|||
'renames', 'get_terminal_size', 'get_prog',
|
||||
'unzip_file', 'untar_file', 'unpack_file', 'call_subprocess',
|
||||
'captured_stdout', 'remove_tracebacks', 'ensure_dir',
|
||||
'ARCHIVE_EXTENSIONS', 'SUPPORTED_EXTENSIONS']
|
||||
'ARCHIVE_EXTENSIONS', 'SUPPORTED_EXTENSIONS',
|
||||
'get_installed_version']
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -845,3 +846,20 @@ class cached_property(object):
|
|||
return self
|
||||
value = obj.__dict__[self.func.__name__] = self.func(obj)
|
||||
return value
|
||||
|
||||
|
||||
def get_installed_version(dist_name):
|
||||
"""Get the installed version of dist_name avoiding pkg_resources cache"""
|
||||
# Create a requirement that we'll look for inside of setuptools.
|
||||
req = pkg_resources.Requirement.parse(dist_name)
|
||||
|
||||
# We want to avoid having this cached, so we need to construct a new
|
||||
# working set each time.
|
||||
working_set = pkg_resources.WorkingSet()
|
||||
|
||||
# Get the installed distribution from our working set
|
||||
dist = working_set.find(req)
|
||||
|
||||
# Check to see if we got an installed distribution or not, if we did
|
||||
# we want to return it's version.
|
||||
return dist.version if dist else None
|
||||
|
|
|
@ -39,7 +39,7 @@ def indent_log(num=2):
|
|||
|
||||
|
||||
def get_indentation():
|
||||
return _log_state.indentation
|
||||
return getattr(_log_state, 'indentation', 0)
|
||||
|
||||
|
||||
class IndentingFormatter(logging.Formatter):
|
||||
|
|
|
@ -12,7 +12,7 @@ from pip._vendor.packaging import version as packaging_version
|
|||
from pip.compat import total_seconds, WINDOWS
|
||||
from pip.index import PyPI
|
||||
from pip.locations import USER_CACHE_DIR, running_under_virtualenv
|
||||
from pip.utils import ensure_dir
|
||||
from pip.utils import ensure_dir, get_installed_version
|
||||
from pip.utils.filesystem import check_path_owner
|
||||
|
||||
|
||||
|
@ -99,7 +99,7 @@ def pip_version_check(session):
|
|||
the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix
|
||||
of the pip script path.
|
||||
"""
|
||||
import pip # imported here to prevent circular imports
|
||||
pip_version = packaging_version.parse(get_installed_version('pip'))
|
||||
pypi_version = None
|
||||
|
||||
try:
|
||||
|
@ -133,7 +133,6 @@ def pip_version_check(session):
|
|||
# save that we've performed a check
|
||||
state.save(pypi_version, current_time)
|
||||
|
||||
pip_version = packaging_version.parse(pip.__version__)
|
||||
remote_version = packaging_version.parse(pypi_version)
|
||||
|
||||
# Determine if our pypi_version is older
|
||||
|
@ -148,7 +147,7 @@ def pip_version_check(session):
|
|||
logger.warning(
|
||||
"You are using pip version %s, however version %s is "
|
||||
"available.\nYou should consider upgrading via the "
|
||||
"'%s install --upgrade pip' command." % (pip.__version__,
|
||||
"'%s install --upgrade pip' command." % (pip_version,
|
||||
pypi_version,
|
||||
pip_cmd)
|
||||
)
|
||||
|
|
|
@ -753,7 +753,13 @@ class WheelBuilder(object):
|
|||
for req in buildset:
|
||||
if autobuilding:
|
||||
output_dir = _cache_for_link(self._cache_root, req.link)
|
||||
ensure_dir(output_dir)
|
||||
try:
|
||||
ensure_dir(output_dir)
|
||||
except OSError as e:
|
||||
logger.warn("Building wheel for %s failed: %s",
|
||||
req.name, e)
|
||||
build_failure.append(req)
|
||||
continue
|
||||
else:
|
||||
output_dir = self._wheel_dir
|
||||
wheel_file = self._build_one(req, output_dir)
|
||||
|
|
|
@ -98,6 +98,9 @@ class TestDisutilsScheme:
|
|||
scheme = distutils_scheme('example')
|
||||
assert scheme['scripts'] == '/somewhere/else'
|
||||
|
||||
# when we request install-lib, we should install everything (.py &
|
||||
# .so) into that path; i.e. ensure platlib & purelib are set to
|
||||
# this path
|
||||
def test_install_lib_takes_precedence(self, tmpdir, monkeypatch):
|
||||
f = tmpdir.mkdir("config").join("setup.cfg")
|
||||
f.write("[install]\ninstall-lib=/somewhere/else/")
|
||||
|
|
|
@ -7,7 +7,6 @@ import freezegun
|
|||
import pytest
|
||||
import pretend
|
||||
|
||||
import pip
|
||||
from pip._vendor import lockfile
|
||||
from pip.utils import outdated
|
||||
|
||||
|
@ -22,7 +21,7 @@ from pip.utils import outdated
|
|||
]
|
||||
)
|
||||
def test_pip_version_check(monkeypatch, stored_time, newver, check, warn):
|
||||
monkeypatch.setattr(pip, '__version__', '1.0')
|
||||
monkeypatch.setattr(outdated, 'get_installed_version', lambda name: '1.0')
|
||||
|
||||
resp = pretend.stub(
|
||||
raise_for_status=pretend.call_recorder(lambda: None),
|
||||
|
|
Loading…
Reference in a new issue