mirror of
https://github.com/pypa/pip
synced 2023-12-13 21:30:23 +01:00
Merge branch 'release/7.0.2'
This commit is contained in:
commit
dfb177fa64
16 changed files with 153 additions and 39 deletions
|
@ -10,6 +10,7 @@ env:
|
|||
- TOXENV=py32
|
||||
- TOXENV=py33
|
||||
- TOXENV=py34
|
||||
- TOXENV=py35
|
||||
- TOXENV=pypy
|
||||
- TOXENV=py27 VENDOR=no
|
||||
- TOXENV=py34 VENDOR=no
|
||||
|
|
|
@ -7,3 +7,9 @@ git config --global user.name "pip"
|
|||
|
||||
pip install --upgrade setuptools
|
||||
pip install coverage diff_cover tox
|
||||
|
||||
# If we're running under Python 3.5, then we need to actually go and install
|
||||
# Python 3.5.
|
||||
if [[ $TOXENV = "py35" ]]; then
|
||||
sudo python-build 3.5-dev /opt/python/3.5-dev
|
||||
fi
|
||||
|
|
|
@ -2,6 +2,13 @@
|
|||
set -e
|
||||
set -x
|
||||
|
||||
# If we're running under Python 3.5 make sure our Python 3.5 bin directory is
|
||||
# added to the $PATH
|
||||
if [[ $TOXENV = "py35" ]]; then
|
||||
export PATH="/opt/python/3.5-dev/bin:$PATH"
|
||||
export TOXARGS="--assert=plain"
|
||||
fi
|
||||
|
||||
# We want to create the virtual environment here, but not actually run anything
|
||||
tox --notest
|
||||
|
||||
|
@ -32,14 +39,14 @@ if [[ $VENDOR = "no" ]]; then
|
|||
fi
|
||||
|
||||
# Run the unit tests
|
||||
tox -- -m unit --cov pip/ --cov-report xml
|
||||
tox -- -m unit --cov pip/ --cov-report xml $TOXARGS
|
||||
|
||||
# Run our integration tests
|
||||
# Note: There is an issue with Python 3.2 where concurrent imports will corrupt
|
||||
# the generated .pyc files and we'll get very strange errors. However as
|
||||
# long as we continue to run the unit tests first and in a seperate step
|
||||
# then this should work fine.
|
||||
tox -- -m integration -n 8
|
||||
tox -- -m integration -n 8 $TOXARGS
|
||||
|
||||
if [[ $TRAVIS_PULL_REQUEST != "false" ]]
|
||||
then
|
||||
|
|
16
CHANGES.txt
16
CHANGES.txt
|
@ -1,3 +1,19 @@
|
|||
**7.0.2 (unreleased)**
|
||||
|
||||
* **BACKWARD INCOMPATIBLE** Revert the change (released in v7.0.0) that
|
||||
required quoting in requirements files around specifiers containing
|
||||
environment markers. (:pull:`2841`)
|
||||
|
||||
* **BACKWARD INCOMPATIBLE** Revert the accidental introduction of support for
|
||||
options interleaved with requirements, version specifiers etc in
|
||||
``requirements`` files. (:pull:`2841`)
|
||||
|
||||
* Expand ``~`` in the cache directory when caching wheels, fixes :issue:`2816`.
|
||||
|
||||
* Use ``python -m pip`` instead of ``pip`` when recommending an upgrade command
|
||||
to Windows users.
|
||||
|
||||
|
||||
**7.0.1 (2015-05-22)**
|
||||
|
||||
* Don't build and cache wheels for non-editable installations from VCSs.
|
||||
|
|
10
docs/conf.py
10
docs/conf.py
|
@ -27,7 +27,15 @@ sys.path.insert(0, os.path.abspath(os.pardir))
|
|||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
# extensions = ['sphinx.ext.autodoc']
|
||||
extensions = ['sphinx.ext.extlinks', 'docs.pipext']
|
||||
extensions = ['sphinx.ext.extlinks', 'docs.pipext', 'sphinx.ext.intersphinx']
|
||||
|
||||
# intersphinx
|
||||
intersphinx_cache_limit = 0
|
||||
intersphinx_mapping = {
|
||||
'pypug': ('https://packaging.python.org/en/latest/', None),
|
||||
'pypa': ('https://pypa.io/en/latest/', None),
|
||||
}
|
||||
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = []
|
||||
|
|
|
@ -82,20 +82,13 @@ Requirements File Format
|
|||
Each line of the requirements file indicates something to be installed,
|
||||
and like arguments to :ref:`pip install`, the following forms are supported::
|
||||
|
||||
<requirement specifier>
|
||||
<requirement specifier> [--install-option="..."] [--global-option="..."]
|
||||
[[--option]...]
|
||||
<requirement specifier> [; markers] [[--option]...]
|
||||
<archive url/path>
|
||||
[-e] <local project path>
|
||||
[-e] <vcs project url>
|
||||
|
||||
Since version 6.0, pip also supports markers using the "; " separator.
|
||||
Examples::
|
||||
|
||||
"futures; python_version < '2.7'"
|
||||
"http://my.package.repo/SomePackage-1.0.4.zip; python_version >= '3.4'"
|
||||
|
||||
Requirements with markers must be quoted. For example, use ``"SomeProject;
|
||||
python_version < '2.7'"``, not simply ``SomeProject; python_version < '2.7'``.
|
||||
For details on requirement specifiers, see :ref:`Requirement Specifiers`.
|
||||
|
||||
See the :ref:`pip install Examples<pip install Examples>` for examples of all these forms.
|
||||
|
||||
|
@ -136,23 +129,38 @@ Lastly, if you wish, you can refer to other requirements files, like this::
|
|||
Requirement Specifiers
|
||||
++++++++++++++++++++++
|
||||
|
||||
pip supports installing from "requirement specifiers" as implemented in
|
||||
`pkg_resources Requirements <http://packages.python.org/setuptools/pkg_resources.html#requirement-objects>`_
|
||||
pip supports installing from a package index using a :term:`requirement
|
||||
specifier <pypug:Requirement Specifier>`. Generally speaking, a requirement
|
||||
specifier is composed of a project name followed by optional :term:`version
|
||||
specifiers <pypug:Version Specifier>`. :ref:`PEP440 <pypa:PEP440s>` contains
|
||||
a `full specification
|
||||
<https://www.python.org/dev/peps/pep-0440/#version-specifiers>`_ of the
|
||||
currently supported specifiers.
|
||||
|
||||
Some Examples:
|
||||
Some examples:
|
||||
|
||||
::
|
||||
|
||||
'FooProject >= 1.2'
|
||||
Fizzy [foo, bar]
|
||||
'PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1'
|
||||
SomethingWhoseVersionIDontCareAbout
|
||||
SomeProject
|
||||
SomeProject == 1.3
|
||||
SomeProject >=1.2,<.2.0
|
||||
SomeProject[foo, bar]
|
||||
SomeProject~=1.4.2
|
||||
|
||||
Since version 6.0, pip also supports specifers containing `environment markers
|
||||
<https://www.python.org/dev/peps/pep-0426/#environment-markers>`_ like so:
|
||||
|
||||
::
|
||||
|
||||
SomeProject ==5.4 ; python_version < '2.7'
|
||||
SomeProject; sys.platform == 'win32'
|
||||
|
||||
Environment markers are supported in the command line and in requirements files.
|
||||
|
||||
.. note::
|
||||
|
||||
Use single or double quotes around specifiers when using them in a shell to avoid ``>`` and ``<`` being
|
||||
interpreted as shell redirects. e.g. ``pip install 'FooProject>=1.2'``.
|
||||
Don't use single or double quotes in a ``requirements.txt`` file.
|
||||
Use quotes around specifiers in the shell when using ``>``, ``<``, or when
|
||||
using environment markers. Don't use quotes in requirement files. [1]_
|
||||
|
||||
|
||||
.. _`Per-requirement Overrides`:
|
||||
|
@ -160,10 +168,12 @@ Some Examples:
|
|||
Per-requirement Overrides
|
||||
+++++++++++++++++++++++++
|
||||
|
||||
When pip installs packages, it normally executes the ``setup.py`` file
|
||||
behind the scenes. You may extend the arguments with which the
|
||||
``setup.py`` file is called through the ``--global-option`` and
|
||||
``--install-option`` options. For example:
|
||||
Since version 7.0 pip supports controlling the command line options given to
|
||||
``setup.py`` via requirements files. This disables the use of wheels (cached or
|
||||
otherwise) for that package, as ``setup.py`` does not exist for wheels.
|
||||
|
||||
The ``--global-option`` and ``--install-option`` options are used to pass
|
||||
options to ``setup.py``. For example:
|
||||
|
||||
::
|
||||
|
||||
|
@ -631,3 +641,8 @@ Examples
|
|||
::
|
||||
|
||||
$ pip install --pre SomePackage
|
||||
|
||||
----
|
||||
|
||||
.. [1] This is true with the exception that pip v7.0 and v7.0.1 required quotes
|
||||
around specifiers containing environment markers in requirement files.
|
||||
|
|
|
@ -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.0.1"
|
||||
__version__ = "7.0.2.dev0"
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
|
@ -16,7 +16,12 @@ except ImportError:
|
|||
try:
|
||||
import ipaddress
|
||||
except ImportError:
|
||||
from pip._vendor import ipaddress
|
||||
try:
|
||||
from pip._vendor import ipaddress
|
||||
except ImportError:
|
||||
import ipaddr as ipaddress
|
||||
ipaddress.ip_address = ipaddress.IPAddress
|
||||
ipaddress.ip_network = ipaddress.IPNetwork
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
|
|
@ -111,11 +111,11 @@ def process_line(line, filename, line_number, finder=None, comes_from=None,
|
|||
if finder:
|
||||
# `finder.format_control` will be updated during parsing
|
||||
defaults.format_control = finder.format_control
|
||||
opts, args = parser.parse_args(shlex.split(line), defaults)
|
||||
args_str, options_str = break_args_options(line)
|
||||
opts, _ = parser.parse_args(shlex.split(options_str), defaults)
|
||||
|
||||
# yield a line requirement
|
||||
if args:
|
||||
args_line = ' '.join(args)
|
||||
if args_str:
|
||||
comes_from = '-r %s (line %s)' % (filename, line_number)
|
||||
isolated = options.isolated_mode if options else False
|
||||
if options:
|
||||
|
@ -126,7 +126,7 @@ def process_line(line, filename, line_number, finder=None, comes_from=None,
|
|||
if dest in opts.__dict__ and opts.__dict__[dest]:
|
||||
req_options[dest] = opts.__dict__[dest]
|
||||
yield InstallRequirement.from_line(
|
||||
args_line, comes_from, isolated=isolated, options=req_options,
|
||||
args_str, comes_from, isolated=isolated, options=req_options,
|
||||
wheel_cache=wheel_cache
|
||||
)
|
||||
|
||||
|
@ -193,6 +193,23 @@ def process_line(line, filename, line_number, finder=None, comes_from=None,
|
|||
finder.find_links.append(value)
|
||||
|
||||
|
||||
def break_args_options(line):
|
||||
"""Break up the line into an args and options string. We only want to shlex
|
||||
(and then optparse) the options, not the args. args can contain markers
|
||||
which are corrupted by shlex.
|
||||
"""
|
||||
tokens = line.split(' ')
|
||||
args = []
|
||||
options = tokens[:]
|
||||
for token in tokens:
|
||||
if token.startswith('-') or token.startswith('--'):
|
||||
break
|
||||
else:
|
||||
args.append(token)
|
||||
options.pop(0)
|
||||
return ' '.join(args), ' '.join(options)
|
||||
|
||||
|
||||
def build_parser():
|
||||
"""
|
||||
Return a parser for parsing requirement lines
|
||||
|
|
|
@ -9,7 +9,7 @@ import sys
|
|||
from pip._vendor import lockfile
|
||||
from pip._vendor.packaging import version as packaging_version
|
||||
|
||||
from pip.compat import total_seconds
|
||||
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
|
||||
|
@ -139,11 +139,18 @@ def pip_version_check(session):
|
|||
# Determine if our pypi_version is older
|
||||
if (pip_version < remote_version and
|
||||
pip_version.base_version != remote_version.base_version):
|
||||
# Advise "python -m pip" on Windows to avoid issues
|
||||
# with overwriting pip.exe.
|
||||
if WINDOWS:
|
||||
pip_cmd = "python -m pip"
|
||||
else:
|
||||
pip_cmd = "pip"
|
||||
logger.warning(
|
||||
"You are using pip version %s, however version %s is "
|
||||
"available.\nYou should consider upgrading via the "
|
||||
"'pip install --upgrade pip' command." % (pip.__version__,
|
||||
pypi_version)
|
||||
"'%s install --upgrade pip' command." % (pip.__version__,
|
||||
pypi_version,
|
||||
pip_cmd)
|
||||
)
|
||||
|
||||
except Exception:
|
||||
|
|
|
@ -10,6 +10,7 @@ import functools
|
|||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import shutil
|
||||
import stat
|
||||
|
@ -54,7 +55,7 @@ class WheelCache(object):
|
|||
:param format_control: A pip.index.FormatControl object to limit
|
||||
binaries being read from the cache.
|
||||
"""
|
||||
self._cache_dir = cache_dir
|
||||
self._cache_dir = os.path.expanduser(cache_dir)
|
||||
self._format_control = format_control
|
||||
|
||||
def cached_wheel(self, link, package_name):
|
||||
|
|
|
@ -292,6 +292,7 @@ def test_freeze_with_requirement_option(script):
|
|||
script.scratch_path.join("hint.txt").write(textwrap.dedent("""\
|
||||
INITools==0.1
|
||||
NoExist==4.2
|
||||
simple==3.0; python_version > '1.0'
|
||||
""") + ignores)
|
||||
result = script.pip_install_local('initools==0.2')
|
||||
result = script.pip_install_local('simple')
|
||||
|
@ -306,6 +307,7 @@ Requirement file contains NoExist==4.2, but that package is not installed
|
|||
|
||||
-- stdout: --------------------
|
||||
INITools==0.2
|
||||
simple==3.0
|
||||
""" + ignores + "## The following requirements were added by pip freeze:..."
|
||||
_check_output(result, expected)
|
||||
|
||||
|
|
|
@ -343,6 +343,10 @@ class TestUpgradeDistributeToSetuptools(object):
|
|||
expect_stderr=True,
|
||||
)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info >= (3, 5),
|
||||
reason="distribute doesn't work on Python 3.5",
|
||||
)
|
||||
def test_from_distribute_6_to_setuptools_7(
|
||||
self, script, data, virtualenv):
|
||||
self.prep_ve(
|
||||
|
|
|
@ -12,7 +12,7 @@ from pip.download import PipSession
|
|||
from pip.index import PackageFinder
|
||||
from pip.req.req_install import InstallRequirement
|
||||
from pip.req.req_file import (parse_requirements, process_line, join_lines,
|
||||
ignore_comments)
|
||||
ignore_comments, break_args_options)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -302,6 +302,23 @@ class TestProcessLine(object):
|
|||
assert req.extras[1] == 'ex2'
|
||||
|
||||
|
||||
class TestBreakOptionsArgs(object):
|
||||
|
||||
def test_no_args(self):
|
||||
assert ('', '--option') == break_args_options('--option')
|
||||
|
||||
def test_no_options(self):
|
||||
assert ('arg arg', '') == break_args_options('arg arg')
|
||||
|
||||
def test_args_short_options(self):
|
||||
result = break_args_options('arg arg -s')
|
||||
assert ('arg arg', '-s') == result
|
||||
|
||||
def test_args_long_options(self):
|
||||
result = break_args_options('arg arg --long')
|
||||
assert ('arg arg', '--long') == result
|
||||
|
||||
|
||||
class TestOptionVariants(object):
|
||||
|
||||
# this suite is really just testing optparse, but added it anyway
|
||||
|
|
|
@ -390,3 +390,10 @@ class TestWheelBuilder(object):
|
|||
wb.build()
|
||||
assert "due to being editable" in caplog.text()
|
||||
assert mock_build_one.mock_calls == []
|
||||
|
||||
|
||||
class TestWheelCache:
|
||||
|
||||
def test_expands_path(self):
|
||||
wc = wheel.WheelCache("~/.foo/", None)
|
||||
assert wc._cache_dir == os.path.expanduser("~/.foo/")
|
||||
|
|
3
tox.ini
3
tox.ini
|
@ -1,5 +1,6 @@
|
|||
[tox]
|
||||
envlist = docs, packaging, pep8, py3pep8, py26, py27, py32, py33, py34, pypy
|
||||
envlist =
|
||||
docs, packaging, pep8, py3pep8, py26, py27, py32, py33, py34, py35, pypy
|
||||
|
||||
[testenv]
|
||||
setenv =
|
||||
|
|
Loading…
Reference in a new issue