Merge branch 'master' of github.com:pypa/pip into cache/ephem-wheel-cache

This commit is contained in:
Pradyun Gedam 2017-10-20 13:51:22 +05:30
commit 1c6a450643
No known key found for this signature in database
GPG Key ID: DA17C4B29CB32E4B
75 changed files with 719 additions and 382 deletions

37
.gitignore vendored
View File

@ -1,16 +1,37 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# Distribution / packaging
build/
dist/
docs/_build/
pip.egg-info/
MANIFEST
.tox
.cache
.mypy_cache
*.egg
*.eggs
*.py[cod]
*~
*.egg-info/
MANIFEST
# Documentation
docs/build/
# mypy
.mypy_cache/
# Unit test / coverage reports
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
# Misc
*~
.*.sw?
# For IntelliJ IDEs (basically PyCharm)
.idea/
# Scratch Pad for experiments
.scratch/

View File

@ -26,6 +26,7 @@ Ludovic Gasc <gmludo@gmail.com> <git@gmludo.eu>
Markus Hametner <fin+github@xbhd.org>
Masklinn <bitbucket.org@masklinn.net>
Matthew Iversen <teh.ivo@gmail.com> <teh.ivo@gmail.com>
Pi Delport <pjdelport@gmail.com>
<pnasrat@gmail.com> <pnasrat@googlemail.com>
Pradyun Gedam <pradyunsg@gmail.com> <pradyunsg@users.noreply.github.com>
Pradyun Gedam <pradyunsg@gmail.com>

View File

@ -3,6 +3,7 @@ sudo: false
dist: trusty
matrix:
fast_finish: true
include:
- env: TOXENV=docs
- env: TOXENV=lint-py2

View File

@ -235,7 +235,7 @@ Phil Freo <phil@philfreo.com>
Phil Whelan <phil123@gmail.com>
Philippe Ombredanne <pombredanne@gmail.com>
Pierre-Yves Rofes <github@rofes.fr>
Piet Delport <pjdelport@gmail.com>
Pi Delport <pjdelport@gmail.com>
Pradyun <pradyunsg@users.noreply.github.com>
Pradyun S. Gedam <pradyunsg@gmail.com>
Preston Holmes <preston@ptone.com>

View File

@ -23,7 +23,7 @@ recursive-exclude src/pip/_vendor *.pyi
prune .github
prune .travis
prune docs/_build
prune docs/build
prune news
prune contrib
prune tasks

View File

@ -1,16 +1,36 @@
environment:
matrix:
# Unit and integration tests.
- PYTHON: "C:\\Python27"
- PYTHON: "C:\\Python33"
- PYTHON: "C:\\Python34"
- PYTHON: "C:\\Python35"
RUN_INTEGRATION_TESTS: "True"
- PYTHON: "C:\\Python36-x64"
RUN_INTEGRATION_TESTS: "True"
# Unit tests only.
- PYTHON: "C:\\Python27-x64"
- PYTHON: "C:\\Python33"
- PYTHON: "C:\\Python33-x64"
- PYTHON: "C:\\Python34"
- PYTHON: "C:\\Python34-x64"
- PYTHON: "C:\\Python35"
- PYTHON: "C:\\Python35-x64"
- PYTHON: "C:\\Python36"
install:
cmd: "%PYTHON%\\python.exe -m pip install tox"
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
- "python --version"
- "pip install certifi tox"
# Fix git SSL errors.
- "python -m certifi >cacert.txt"
- "set /p GIT_SSL_CAINFO=<cacert.txt"
- "set GIT_SSL_CAINFO"
build: off
test_script:
- "%PYTHON%\\Scripts\\tox.exe -e py -- -m unit -n 8"
# Shorten paths, workaround https://bugs.python.org/issue18199
- "subst T: %TEMP%"
- "set TEMP=T:\\"
- "set TMP=T:\\"
- "tox -e py -- -m unit -n 3"
- "if \"%RUN_INTEGRATION_TESTS%\" == \"True\" (
tox -e py -- -m integration -n 3 --duration=5 )"

View File

@ -5,7 +5,7 @@
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
BUILDDIR = build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)

View File

@ -33,7 +33,7 @@ extensions = ['sphinx.ext.extlinks', 'docs.pipext', 'sphinx.ext.intersphinx']
# intersphinx
intersphinx_cache_limit = 0
intersphinx_mapping = {
'pypug': ('https://packaging.python.org/en/latest/', None),
'pypug': ('https://packaging.python.org/', None),
'pypa': ('https://www.pypa.io/en/latest/', None),
}
@ -52,7 +52,7 @@ master_doc = 'index'
# General information about the project.
project = 'pip'
copyright = '2008-2016, PyPA'
copyright = '2008-2017, PyPA'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@ -83,7 +83,7 @@ today_fmt = '%B %d, %Y'
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_patterns = ['_build/', 'man/']
exclude_patterns = ['build/', 'man/']
# The reST default role (used for this markup: `text`) to use for all documents
# default_role = None
@ -114,19 +114,17 @@ extlinks = {
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'default'
if not on_rtd:
try:
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
except ImportError:
pass
html_theme = "pypa_theme"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
# html_theme_options = {}
html_theme_options = {
'collapsiblesidebar': True,
'externalrefs': True,
'navigation_depth': 2,
'issues_url': 'https://github.com/pypa/pip/issues'
}
# Add any paths that contain custom themes here, relative to this directory.
@ -157,10 +155,13 @@ html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = False
smart_quotes = False
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
html_sidebars = {
'**': ['localtoc.html', 'relations.html'],
'index': ['localtoc.html']
}
# Additional templates that should be rendered to pages, maps page names to
# template names.

View File

@ -12,7 +12,7 @@ The `PyPA recommended <https://packaging.python.org/en/latest/current/>`_ tool
for installing Python packages.
.. toctree::
:maxdepth: 2
:maxdepth: 1
quickstart
installing

View File

@ -5,7 +5,7 @@ REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set BUILDDIR=build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (

View File

@ -17,7 +17,7 @@ class PipCommandUsage(rst.Directive):
def run(self):
cmd = commands[self.arguments[0]]
prog = '%s %s' % (get_prog(), cmd.name)
usage = dedent(cmd.usage.replace('%prog', prog))
usage = dedent(cmd.usage.replace('%prog', prog)).strip()
node = nodes.literal_block(usage, usage)
return [node]

View File

@ -3,7 +3,7 @@ Reference Guide
===============
.. toctree::
:maxdepth: 2
:maxdepth: 1
pip
pip_install

View File

@ -1,8 +1,6 @@
pip
---
.. contents::
Usage
*****

View File

@ -3,8 +3,6 @@
pip check
---------
.. contents::
Usage
*****

View File

@ -4,8 +4,6 @@
pip config
------------
.. contents::
Usage
*****

View File

@ -4,8 +4,6 @@
pip download
------------
.. contents::
Usage
*****

View File

@ -4,8 +4,6 @@
pip freeze
-----------
.. contents::
Usage
*****

View File

@ -3,8 +3,6 @@
pip hash
------------
.. contents::
Usage
*****

View File

@ -3,8 +3,6 @@
pip install
-----------
.. contents::
Usage
*****
@ -374,6 +372,10 @@ Passing branch names, a commit hash or a tag name is possible like so::
[-e] git://git.example.com/MyProject.git@v1.0#egg=MyProject
[-e] git://git.example.com/MyProject.git@da39a3ee5e6b4b0d3255bfef95601890afd80709#egg=MyProject
When passing a commit hash, specifying a full hash is preferable to a partial
hash because a full hash allows pip to operate more efficiently (e.g. by
making fewer network calls).
Mercurial
~~~~~~~~~

View File

@ -3,8 +3,6 @@
pip list
---------
.. contents::
Usage
*****

View File

@ -3,8 +3,6 @@
pip search
----------
.. contents::
Usage
*****

View File

@ -3,9 +3,6 @@
pip show
--------
.. contents::
Usage
*****

View File

@ -3,8 +3,6 @@
pip uninstall
-------------
.. contents::
Usage
*****

View File

@ -4,8 +4,6 @@
pip wheel
---------
.. contents::
Usage
*****

View File

@ -2,8 +2,6 @@
User Guide
==========
.. contents::
Running pip
***********

2
news/1130.bugfix Normal file
View File

@ -0,0 +1,2 @@
Allow pip to work if the ``GIT_DIR`` and ``GIT_WORK_TREE`` environment
variables are set.

2
news/3997.bugfix Normal file
View File

@ -0,0 +1,2 @@
Shell completion scripts now use correct executable names (e.g., ``pip3``
instead of ``pip``)

2
news/4507.feature Normal file
View File

@ -0,0 +1,2 @@
Don't log a warning when installing a dependency from Git if the name looks
like a commit hash.

View File

@ -1 +0,0 @@
Integrate with mypy for utilizing static typing.

1
news/4655.bugfix Normal file
View File

@ -0,0 +1 @@
Fix warning message on mismatched versions during installation.

3
news/4675.bugfix Normal file
View File

@ -0,0 +1,3 @@
Fix an issue where ``pip install -e`` on a Git url would fail to update if
a branch or tag name is specified that happens to match the prefix of the
current ``HEAD`` commit hash.

1
news/4758.feature Normal file
View File

@ -0,0 +1 @@
Change documentation theme to be in line with Python Documentation

1
news/DEADBEEF.trivial Normal file
View File

@ -0,0 +1 @@

View File

@ -25,7 +25,10 @@ follow_imports = skip
ignore_errors = True
[tool:pytest]
addopts = --ignore src/pip/_vendor --ignore tests/tests_cache
addopts = --ignore src/pip/_vendor --ignore tests/tests_cache -r aR
[bdist_wheel]
universal=1
universal = 1
[metadata]
license_file = LICENSE.txt

View File

@ -12,7 +12,8 @@ here = os.path.abspath(os.path.dirname(__file__))
def read(*parts):
# intentionally *not* adding an encoding option to open, See:
# https://github.com/pypa/virtualenv/issues/201#issuecomment-3145690
return codecs.open(os.path.join(here, *parts), 'r').read()
with codecs.open(os.path.join(here, *parts), 'r') as fp:
return fp.read()
def find_version(*file_paths):

View File

@ -4,6 +4,7 @@ import sys
import textwrap
from pip._internal.basecommand import Command
from pip._internal.utils.misc import get_prog
BASE_COMPLETION = """
# pip %(shell)s completion start%(script)s# pip %(shell)s completion end
@ -17,7 +18,7 @@ COMPLETION_SCRIPTS = {
COMP_CWORD=$COMP_CWORD \\
PIP_AUTO_COMPLETE=1 $1 ) )
}
complete -o default -F _pip_completion pip
complete -o default -F _pip_completion %(prog)s
""",
'zsh': """
function _pip_completion {
@ -28,17 +29,19 @@ COMPLETION_SCRIPTS = {
COMP_CWORD=$(( cword-1 )) \\
PIP_AUTO_COMPLETE=1 $words[1] ) )
}
compctl -K _pip_completion pip
compctl -K _pip_completion %(prog)s
""",
'fish': """
function __fish_complete_pip
set -lx COMP_WORDS (commandline -o) ""
set -lx COMP_CWORD {cword}
set -lx COMP_CWORD ( \\
math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\
)
set -lx PIP_AUTO_COMPLETE 1
string split \\ -- (eval $COMP_WORDS[1])
end
complete -fa "(__fish_complete_pip)" -c pip
""".format(cword="(math (contains -i -- (commandline -t) $COMP_WORDS)-1)")
complete -fa "(__fish_complete_pip)" -c %(prog)s
""",
}
@ -80,7 +83,9 @@ class CompletionCommand(Command):
shell_options = ['--' + shell for shell in sorted(shells)]
if options.shell in shells:
script = textwrap.dedent(
COMPLETION_SCRIPTS.get(options.shell, '')
COMPLETION_SCRIPTS.get(options.shell, '') % {
'prog': get_prog(),
}
)
print(BASE_COMPLETION % {'script': script, 'shell': options.shell})
else:

View File

@ -289,7 +289,7 @@ class PackageFinder(object):
)
pri = -(wheel.support_index_min(self.valid_tags))
if wheel.build_tag is not None:
match = re.match('^(\d+)(.*)$', wheel.build_tag)
match = re.match(r'^(\d+)(.*)$', wheel.build_tag)
build_tag_groups = match.groups()
build_tag = (int(build_tag_groups[0]), build_tag_groups[1])
else: # sdist

View File

@ -595,7 +595,7 @@ class InstallRequirement(object):
logger.warning(
'Requested %s, but installing version %s',
self,
self.installed_version,
version,
)
else:
logger.debug(
@ -945,7 +945,7 @@ class InstallRequirement(object):
def get_dist(self):
"""Return a pkg_resources.Distribution built from self.egg_info_path"""
egg_info = self.egg_info_path('').rstrip('/')
egg_info = self.egg_info_path('').rstrip(os.path.sep)
base_dir = os.path.dirname(egg_info)
metadata = pkg_resources.PathMetadata(base_dir, egg_info)
dist_name = os.path.splitext(os.path.basename(egg_info))[0]

View File

@ -128,7 +128,7 @@ def compress_for_output_listing(paths):
if fname.endswith(".pyc"):
continue
file_ = os.path.join(dirpath, fname)
file_ = os.path.normcase(os.path.join(dirpath, fname))
if os.path.isfile(file_) and file_ not in files:
# We are skipping this file. Add it to the set.
will_skip.add(file_)

View File

@ -1,7 +1,6 @@
from __future__ import absolute_import
import ctypes
import platform
import re
import warnings
@ -73,9 +72,13 @@ def have_compatible_glibc(required_major, minimum_minor):
# misleading. Solution: instead of using platform, use our code that actually
# works.
def libc_ver():
"""Try to determine the glibc version
Returns a tuple of strings (lib, version) which default to empty strings
in case the lookup fails.
"""
glibc_version = glibc_version_string()
if glibc_version is None:
# For non-glibc platforms, fall back on platform.libc_ver
return platform.libc_ver()
return ("", "")
else:
return ("glibc", glibc_version)

View File

@ -91,8 +91,11 @@ def ensure_dir(path):
def get_prog():
try:
if os.path.basename(sys.argv[0]) in ('__main__.py', '-c'):
prog = os.path.basename(sys.argv[0])
if prog in ('__main__.py', '-c'):
return "%s -m pip" % sys.executable
else:
return prog
except (AttributeError, TypeError, IndexError):
pass
return 'pip'
@ -627,7 +630,14 @@ def unpack_file(filename, location, content_type, link):
def call_subprocess(cmd, show_stdout=True, cwd=None,
on_returncode='raise',
command_desc=None,
extra_environ=None, spinner=None):
extra_environ=None, unset_environ=None, spinner=None):
"""
Args:
unset_environ: an iterable of environment variable names to unset
prior to calling subprocess.Popen().
"""
if unset_environ is None:
unset_environ = []
# This function's handling of subprocess output is confusing and I
# previously broke it terribly, so as penance I will write a long comment
# explaining things.
@ -664,6 +674,8 @@ def call_subprocess(cmd, show_stdout=True, cwd=None,
env = os.environ.copy()
if extra_environ:
env.update(extra_environ)
for name in unset_environ:
env.pop(name, None)
try:
proc = subprocess.Popen(
cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,

View File

@ -166,6 +166,8 @@ class VersionControl(object):
dirname = ''
# List of supported schemes for this Version Control
schemes = () # type: Tuple[str, ...]
# Iterable of environment variable names to pass to call_subprocess().
unset_environ = () # type: Tuple[str, ...]
default_arg_rev = None # type: Optional[str]
def __init__(self, url=None, *args, **kwargs):
@ -277,13 +279,13 @@ class VersionControl(object):
"""
raise NotImplementedError
def check_version(self, dest, rev_options):
def is_commit_id_equal(self, dest, name):
"""
Return True if the version is identical to what exists and
doesn't need to be updated.
Return whether the id of the current commit equals the given name.
Args:
rev_options: a RevOptions object.
dest: the repository directory.
name: a string name.
"""
raise NotImplementedError
@ -311,7 +313,7 @@ class VersionControl(object):
display_path(dest),
url,
)
if not self.check_version(dest, rev_options):
if not self.is_commit_id_equal(dest, rev_options.rev):
logger.info(
'Updating %s %s%s',
display_path(dest),
@ -403,8 +405,7 @@ class VersionControl(object):
def get_revision(self, location):
"""
Return the current revision of the files at location
Used in get_info
Return the current commit id of the files at the given location.
"""
raise NotImplementedError
@ -422,7 +423,8 @@ class VersionControl(object):
return call_subprocess(cmd, show_stdout, cwd,
on_returncode,
command_desc, extra_environ,
spinner)
unset_environ=self.unset_environ,
spinner=spinner)
except OSError as e:
# errno.ENOENT = no such file or directory
# In other words, the VCS executable isn't available

View File

@ -104,7 +104,7 @@ class Bazaar(VersionControl):
current_rev = self.get_revision(location)
return '%s@%s#egg=%s' % (repo, current_rev, egg_project_name)
def check_version(self, dest, rev_options):
def is_commit_id_equal(self, dest, name):
"""Always assume the versions don't match"""
return False

View File

@ -2,6 +2,7 @@ from __future__ import absolute_import
import logging
import os.path
import re
from pip._vendor.packaging.version import parse as parse_version
from pip._vendor.six.moves.urllib import parse as urllib_parse
@ -20,6 +21,13 @@ urlunsplit = urllib_parse.urlunsplit
logger = logging.getLogger(__name__)
HASH_REGEX = re.compile('[a-fA-F0-9]{40}')
def looks_like_hash(sha):
return bool(HASH_REGEX.match(sha))
class Git(VersionControl):
name = 'git'
dirname = '.git'
@ -27,7 +35,10 @@ class Git(VersionControl):
schemes = (
'git', 'git+http', 'git+https', 'git+ssh', 'git+git', 'git+file',
)
default_arg_rev = 'origin/HEAD'
# Prevent the user's environment variables from interfering with pip:
# https://github.com/pypa/pip/issues/1130
unset_environ = ('GIT_DIR', 'GIT_WORK_TREE')
default_arg_rev = 'HEAD'
def __init__(self, url=None, *args, **kwargs):
@ -78,43 +89,71 @@ class Git(VersionControl):
show_stdout=False, cwd=temp_dir.path
)
def get_revision_sha(self, dest, rev):
"""
Return a commit hash for the given revision if it names a remote
branch or tag. Otherwise, return None.
Args:
dest: the repository directory.
rev: the revision name.
"""
# Pass rev to pre-filter the list.
output = self.run_command(['show-ref', rev], cwd=dest,
show_stdout=False, on_returncode='ignore')
refs = {}
for line in output.strip().splitlines():
try:
sha, ref = line.split()
except ValueError:
# Include the offending line to simplify troubleshooting if
# this error ever occurs.
raise ValueError('unexpected show-ref line: {!r}'.format(line))
refs[ref] = sha
branch_ref = 'refs/remotes/origin/{}'.format(rev)
tag_ref = 'refs/tags/{}'.format(rev)
return refs.get(branch_ref) or refs.get(tag_ref)
def check_rev_options(self, dest, rev_options):
"""Check the revision options before checkout to compensate that tags
and branches may need origin/ as a prefix.
"""Check the revision options before checkout.
Returns a new RevOptions object for the SHA1 of the branch or tag
if found.
Args:
rev_options: a RevOptions object.
"""
revisions = self.get_short_refs(dest)
rev = rev_options.arg_rev
origin_rev = 'origin/%s' % rev
if origin_rev in revisions:
# remote branch
return rev_options.make_new(revisions[origin_rev])
elif rev in revisions:
# a local tag or branch name
return rev_options.make_new(revisions[rev])
else:
sha = self.get_revision_sha(dest, rev)
if sha is not None:
return rev_options.make_new(sha)
# Do not show a warning for the common case of something that has
# the form of a Git commit hash.
if not looks_like_hash(rev):
logger.warning(
"Could not find a tag or branch '%s', assuming commit or ref",
"Did not find branch or tag '%s', assuming revision or ref.",
rev,
)
return rev_options
return rev_options
def check_version(self, dest, rev_options):
def is_commit_id_equal(self, dest, name):
"""
Compare the current sha to the ref. ref may be a branch or tag name,
but current rev will always point to a sha. This means that a branch
or tag will never compare as True. So this ultimately only matches
against exact shas.
Return whether the current commit hash equals the given name.
Args:
rev_options: a RevOptions object.
dest: the repository directory.
name: a string name.
"""
return self.get_revision(dest).startswith(rev_options.arg_rev)
if not name:
# Then avoid an unnecessary subprocess call.
return False
return self.get_revision(dest) == name
def switch(self, dest, url, rev_options):
self.run_command(['config', 'remote.origin.url', url], cwd=dest)
@ -149,10 +188,11 @@ class Git(VersionControl):
if rev:
rev_options = self.check_rev_options(dest, rev_options)
# Only do a checkout if rev_options differs from HEAD
if not self.check_version(dest, rev_options):
# Only do a checkout if the current commit id doesn't match
# the requested revision.
if not self.is_commit_id_equal(dest, rev_options.rev):
cmd_args = ['fetch', '-q', url] + rev_options.to_args()
self.run_command(cmd_args, cwd=dest,)
self.run_command(cmd_args, cwd=dest)
self.run_command(
['checkout', '-q', 'FETCH_HEAD'],
cwd=dest,
@ -180,50 +220,6 @@ class Git(VersionControl):
['rev-parse', 'HEAD'], show_stdout=False, cwd=location)
return current_rev.strip()
def get_full_refs(self, location):
"""Yields tuples of (commit, ref) for branches and tags"""
output = self.run_command(['show-ref'],
show_stdout=False, cwd=location)
for line in output.strip().splitlines():
commit, ref = line.split(' ', 1)
yield commit.strip(), ref.strip()
def is_ref_remote(self, ref):
return ref.startswith('refs/remotes/')
def is_ref_branch(self, ref):
return ref.startswith('refs/heads/')
def is_ref_tag(self, ref):
return ref.startswith('refs/tags/')
def is_ref_commit(self, ref):
"""A ref is a commit sha if it is not anything else"""
return not any((
self.is_ref_remote(ref),
self.is_ref_branch(ref),
self.is_ref_tag(ref),
))
# Should deprecate `get_refs` since it's ambiguous
def get_refs(self, location):
return self.get_short_refs(location)
def get_short_refs(self, location):
"""Return map of named refs (branches or tags) to commit hashes."""
rv = {}
for commit, ref in self.get_full_refs(location):
ref_name = None
if self.is_ref_remote(ref):
ref_name = ref[len('refs/remotes/'):]
elif self.is_ref_branch(ref):
ref_name = ref[len('refs/heads/'):]
elif self.is_ref_tag(ref):
ref_name = ref[len('refs/tags/'):]
if ref_name is not None:
rv[ref_name] = commit
return rv
def _get_subdirectory(self, location):
"""Return the relative path of setup.py to the git repo root."""
# find the repo root

View File

@ -97,7 +97,7 @@ class Mercurial(VersionControl):
current_rev_hash = self.get_revision_hash(location)
return '%s@%s#egg=%s' % (repo, current_rev_hash, egg_project_name)
def check_version(self, dest, rev_options):
def is_commit_id_equal(self, dest, name):
"""Always assume the versions don't match"""
return False

View File

@ -217,7 +217,7 @@ class Subversion(VersionControl):
rev = self.get_revision(location)
return 'svn+%s@%s#egg=%s' % (repo, rev, egg_project_name)
def check_version(self, dest, rev_options):
def is_commit_id_equal(self, dest, name):
"""Always assume the versions don't match"""
return False

View File

@ -70,11 +70,13 @@ if DEBUNDLED:
vendored("six")
vendored("six.moves")
vendored("six.moves.urllib")
vendored("six.moves.urllib.parse")
vendored("packaging")
vendored("packaging.version")
vendored("packaging.specifiers")
vendored("pkg_resources")
vendored("progress")
vendored("pytoml")
vendored("retrying")
vendored("requests")
vendored("requests.packages")

View File

@ -77,8 +77,6 @@ def isolate(tmpdir):
We use an autouse function scoped fixture because we want to ensure that
every test has it's own isolated home directory.
"""
# TODO: Ensure Windows will respect $HOME, including for the cache
# directory
# TODO: Figure out how to isolate from *system* level configuration files
# as well as user level configuration files.
@ -91,21 +89,36 @@ def isolate(tmpdir):
fake_root = os.path.join(str(tmpdir), "fake-root")
os.makedirs(fake_root)
# Set our home directory to our temporary directory, this should force all
# of our relative configuration files to be read from here instead of the
# user's actual $HOME directory.
os.environ["HOME"] = home_dir
# Isolate ourselves from XDG directories
os.environ["XDG_DATA_HOME"] = os.path.join(home_dir, ".local", "share")
os.environ["XDG_CONFIG_HOME"] = os.path.join(home_dir, ".config")
os.environ["XDG_CACHE_HOME"] = os.path.join(home_dir, ".cache")
os.environ["XDG_RUNTIME_DIR"] = os.path.join(home_dir, ".runtime")
os.environ["XDG_DATA_DIRS"] = ":".join([
os.path.join(fake_root, "usr", "local", "share"),
os.path.join(fake_root, "usr", "share"),
])
os.environ["XDG_CONFIG_DIRS"] = os.path.join(fake_root, "etc", "xdg")
if sys.platform == 'win32':
# Note: this will only take effect in subprocesses...
home_drive, home_path = os.path.splitdrive(home_dir)
os.environ.update({
'USERPROFILE': home_dir,
'HOMEDRIVE': home_drive,
'HOMEPATH': home_path,
})
for env_var, sub_path in (
('APPDATA', 'AppData/Roaming'),
('LOCALAPPDATA', 'AppData/Local'),
):
path = os.path.join(home_dir, *sub_path.split('/'))
os.environ[env_var] = path
os.makedirs(path)
else:
# Set our home directory to our temporary directory, this should force
# all of our relative configuration files to be read from here instead
# of the user's actual $HOME directory.
os.environ["HOME"] = home_dir
# Isolate ourselves from XDG directories
os.environ["XDG_DATA_HOME"] = os.path.join(home_dir, ".local", "share")
os.environ["XDG_CONFIG_HOME"] = os.path.join(home_dir, ".config")
os.environ["XDG_CACHE_HOME"] = os.path.join(home_dir, ".cache")
os.environ["XDG_RUNTIME_DIR"] = os.path.join(home_dir, ".runtime")
os.environ["XDG_DATA_DIRS"] = ":".join([
os.path.join(fake_root, "usr", "local", "share"),
os.path.join(fake_root, "usr", "share"),
])
os.environ["XDG_CONFIG_DIRS"] = os.path.join(fake_root, "etc", "xdg")
# Configure git, because without an author name/email git will complain
# and cause test failures.
@ -116,6 +129,7 @@ def isolate(tmpdir):
# We want to disable the version check from running in the tests
os.environ["PIP_DISABLE_PIP_VERSION_CHECK"] = "true"
# FIXME: Windows...
os.makedirs(os.path.join(home_dir, ".config", "git"))
with open(os.path.join(home_dir, ".config", "git", "config"), "wb") as fp:
fp.write(
@ -143,6 +157,15 @@ def virtualenv_template(tmpdir_factory):
pip_source_dir=pip_src,
relocatable=True,
)
if sys.platform == 'win32':
# Work around setuptools' easy_install.exe
# not working properly after relocation.
for exe in os.listdir(venv.bin):
if exe.startswith('easy_install'):
(venv.bin / exe).remove()
with open(venv.bin / 'easy_install.bat', 'w') as fp:
fp.write('python.exe -m easy_install %*\n')
# Rename original virtualenv directory to make sure
# it's not reused by mistake from one of the copies.
venv_template = tmpdir / "venv_template"

View File

@ -1,4 +1,7 @@
import os
import sys
import pytest
def test_completion_for_bash(script):
@ -44,7 +47,9 @@ def test_completion_for_fish(script):
fish_completion = """\
function __fish_complete_pip
set -lx COMP_WORDS (commandline -o) ""
set -lx COMP_CWORD (math (contains -i -- (commandline -t) $COMP_WORDS)-1)
set -lx COMP_CWORD ( \\
math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\
)
set -lx PIP_AUTO_COMPLETE 1
string split \\ -- (eval $COMP_WORDS[1])
end
@ -114,3 +119,13 @@ def test_completion_option_for_command(script):
res, env = setup_completion(script, 'pip search --', '2')
assert '--help' in res.stdout,\
"autocomplete function could not complete ``--``"
@pytest.mark.parametrize('flag', ['--bash', '--zsh', '--fish'])
def test_completion_uses_same_executable_name(script, flag):
expect_stderr = sys.version_info[:2] == (3, 3)
executable_name = 'pip{}'.format(sys.version_info[0])
result = script.run(
executable_name, 'completion', flag, expect_stderr=expect_stderr
)
assert executable_name in result.stdout

View File

@ -93,7 +93,7 @@ def test_download_wheel_archive(script, data):
It should download a wheel archive path
"""
wheel_filename = 'colander-0.9.9-py2.py3-none-any.whl'
wheel_path = os.path.join(data.find_links, wheel_filename)
wheel_path = '/'.join((data.find_links, wheel_filename))
result = script.pip(
'download', wheel_path,
'-d', '.', '--no-deps'
@ -107,7 +107,7 @@ def test_download_should_download_wheel_deps(script, data):
"""
wheel_filename = 'colander-0.9.9-py2.py3-none-any.whl'
dep_filename = 'translationstring-1.1.tar.gz'
wheel_path = os.path.join(data.find_links, wheel_filename)
wheel_path = '/'.join((data.find_links, wheel_filename))
result = script.pip(
'download', wheel_path,
'-d', '.', '--find-links', data.find_links, '--no-index'

View File

@ -6,7 +6,10 @@ from doctest import ELLIPSIS, OutputChecker
import pytest
from tests.lib import _create_test_package, _create_test_package_with_srcdir
from tests.lib import (
_create_test_package, _create_test_package_with_srcdir, need_bzr,
need_mercurial
)
distribute_re = re.compile('^distribute==[0-9.]+\n', re.MULTILINE)
@ -319,7 +322,7 @@ def test_freeze_git_remote(script, tmpdir):
_check_output(result.stdout, expected)
@pytest.mark.mercurial
@need_mercurial
def test_freeze_mercurial_clone(script, tmpdir):
"""
Test freezing a Mercurial clone.
@ -361,7 +364,7 @@ def test_freeze_mercurial_clone(script, tmpdir):
_check_output(result.stdout, expected)
@pytest.mark.bzr
@need_bzr
def test_freeze_bazaar_clone(script, tmpdir):
"""
Test freezing a Bazaar clone.
@ -478,7 +481,7 @@ def test_freeze_with_requirement_option_multiple(script):
simple2==1.0
""")
expected += "## The following requirements were added by pip freeze:"
expected += os.linesep + textwrap.dedent("""\
expected += '\n' + textwrap.dedent("""\
...meta==1.0...
""")
_check_output(result.stdout, expected)

View File

@ -1,3 +1,4 @@
import distutils
import glob
import os
import sys
@ -8,11 +9,11 @@ import pytest
from pip._internal import pep425tags
from pip._internal.status_codes import ERROR
from pip._internal.utils import appdirs
from pip._internal.utils.misc import rmtree
from tests.lib import (
_create_svn_repo, _create_test_package, create_test_package_with_setup,
path_to_url, pyversion, pyversion_tuple, requirements_file
need_bzr, need_mercurial, path_to_url, pyversion, pyversion_tuple,
requirements_file
)
from tests.lib.local_repos import local_checkout
from tests.lib.path import Path
@ -217,6 +218,7 @@ def test_install_editable_uninstalls_existing_from_path(script, data):
assert simple_folder in result.files_deleted, str(result.stdout)
@need_mercurial
def test_install_editable_from_hg(script, tmpdir):
"""Test cloning from Mercurial."""
pkg_path = _create_test_package(script, name='testpackage', vcs='hg')
@ -225,6 +227,7 @@ def test_install_editable_from_hg(script, tmpdir):
result.assert_installed('testpackage', with_files=['.hg'])
@need_mercurial
def test_vcs_url_final_slash_normalization(script, tmpdir):
"""
Test that presence or absence of final slash in VCS URL is normalized.
@ -235,7 +238,7 @@ def test_vcs_url_final_slash_normalization(script, tmpdir):
result.assert_installed('testpackage', with_files=['.hg'])
@pytest.mark.bzr
@need_bzr
def test_install_editable_from_bazaar(script, tmpdir):
"""Test checking out from Bazaar."""
pkg_path = _create_test_package(script, name='testpackage', vcs='bazaar')
@ -245,7 +248,7 @@ def test_install_editable_from_bazaar(script, tmpdir):
@pytest.mark.network
@pytest.mark.bzr
@need_bzr
def test_vcs_url_urlquote_normalization(script, tmpdir):
"""
Test that urlquoted characters are normalized for repo URL comparison.
@ -289,13 +292,14 @@ def test_install_relative_directory(script, data):
# Compute relative install path to FSPkg from scratch path.
full_rel_path = data.packages.join('FSPkg') - script.scratch_path
full_rel_url = (
'file:' + full_rel_path.replace(os.path.sep, '/') + '#egg=FSPkg'
)
embedded_rel_path = script.scratch_path.join(full_rel_path)
# For each relative path, install as either editable or not using either
# URLs with egg links or not.
for req_path in (full_rel_path,
'file:' + full_rel_path + '#egg=FSPkg',
embedded_rel_path):
for req_path in (full_rel_path, full_rel_url, embedded_rel_path):
# Regular install.
result = script.pip('install', req_path,
cwd=script.scratch_path)
@ -498,6 +502,7 @@ def test_install_using_install_option_and_editable(script, tmpdir):
@pytest.mark.network
@need_mercurial
def test_install_global_option_using_editable(script, tmpdir):
"""
Test using global distutils options, but in an editable installation
@ -653,12 +658,10 @@ def test_install_package_with_prefix(script, data):
'--no-binary', 'simple', '--no-index', 'simple==1.0',
)
if hasattr(sys, "pypy_version_info"):
path = script.scratch / 'prefix'
else:
path = script.scratch / 'prefix' / 'lib' / 'python{0}'.format(pyversion) # noqa
rel_prefix_path = script.scratch / 'prefix'
install_path = (
path / 'site-packages' / 'simple-1.0-py{0}.egg-info'.format(pyversion)
distutils.sysconfig.get_python_lib(prefix=rel_prefix_path) /
'simple-1.0-py{0}.egg-info'.format(pyversion)
)
assert install_path in result.files_created, str(result)
@ -673,8 +676,11 @@ def test_install_editable_with_prefix(script):
version='0.1')
"""))
site_packages = os.path.join(
'prefix', 'lib', 'python{0}'.format(pyversion), 'site-packages')
if hasattr(sys, "pypy_version_info"):
site_packages = os.path.join(
'prefix', 'lib', 'python{0}'.format(pyversion), 'site-packages')
else:
site_packages = distutils.sysconfig.get_python_lib(prefix='prefix')
# make sure target path is in PYTHONPATH
pythonpath = script.scratch_path / site_packages
@ -745,7 +751,7 @@ def test_url_req_case_mismatch_no_index(script, data):
tests/data/packages contains Upper-1.0.tar.gz and Upper-2.0.tar.gz
'requiresupper' has install_requires = ['upper']
"""
Upper = os.path.join(data.find_links, 'Upper-1.0.tar.gz')
Upper = '/'.join((data.find_links, 'Upper-1.0.tar.gz'))
result = script.pip(
'install', '--no-index', '-f', data.find_links, Upper, 'requiresupper'
)
@ -772,7 +778,7 @@ def test_url_req_case_mismatch_file_index(script, data):
set of packages as it requires a prepared index.html file and
subdirectory-per-package structure.
"""
Dinner = os.path.join(data.find_links3, 'dinner', 'Dinner-1.0.tar.gz')
Dinner = '/'.join((data.find_links3, 'dinner', 'Dinner-1.0.tar.gz'))
result = script.pip(
'install', '--index-url', data.find_links3, Dinner, 'requiredinner'
)
@ -964,6 +970,12 @@ def test_cleanup_after_failed_wheel(script, data, common_wheels):
@pytest.mark.network
def test_install_builds_wheels(script, data, common_wheels):
# We need to use a subprocess to get the right value on Windows.
res = script.run('python', '-c', (
'from pip._internal.utils import appdirs; '
'print(appdirs.user_cache_dir("pip"))'
))
wheels_cache = os.path.join(res.stdout.rstrip('\n'), 'wheels')
# NB This incidentally tests a local tree + tarball inputs
# see test_install_editable_from_git_autobuild_wheel for editable
# vcs coverage.
@ -976,9 +988,8 @@ def test_install_builds_wheels(script, data, common_wheels):
" upper-2.0 wheelbroken-0.1")
# Must have installed it all
assert expected in str(res), str(res)
root = appdirs.user_cache_dir('pip')
wheels = []
for top, dirs, files in os.walk(os.path.join(root, "wheels")):
for top, dirs, files in os.walk(wheels_cache):
wheels.extend(files)
# and built wheels for upper and wheelbroken
assert "Running setup.py bdist_wheel for upper" in str(res), str(res)
@ -1083,7 +1094,9 @@ def test_double_install(script):
"""
Test double install passing with two same version requirements
"""
result = script.pip('install', 'pip', 'pip', expect_error=False)
result = script.pip('install', 'pip', 'pip',
use_module=True,
expect_error=False)
msg = "Double requirement given: pip (already in pip, name='pip')"
assert msg not in result.stderr
@ -1113,7 +1126,7 @@ def test_install_incompatible_python_requires(script, common_wheels):
)
result = script.pip('install', pkga_path, expect_error=True)
assert ("pkga requires Python '<1.0' "
"but the running Python is ") in result.stderr
"but the running Python is ") in result.stderr, str(result)
def test_install_incompatible_python_requires_editable(script, common_wheels):
@ -1132,7 +1145,7 @@ def test_install_incompatible_python_requires_editable(script, common_wheels):
result = script.pip(
'install', '--editable=%s' % pkga_path, expect_error=True)
assert ("pkga requires Python '<1.0' "
"but the running Python is ") in result.stderr
"but the running Python is ") in result.stderr, str(result)
@pytest.mark.network

View File

@ -5,6 +5,7 @@ import pytest
from pip._internal.locations import write_delete_marker_file
from pip._internal.status_codes import PREVIOUS_BUILD_DIR_ERROR
from tests.lib import need_mercurial
from tests.lib.local_repos import local_checkout
@ -36,6 +37,7 @@ def test_no_clean_option_blocks_cleaning_after_install(script, data):
@pytest.mark.network
@need_mercurial
def test_cleanup_after_install_editable_from_hg(script, tmpdir):
"""
Test clean up after cloning from Mercurial.

View File

@ -203,16 +203,19 @@ def test_options_from_venv_config(script, virtualenv):
def test_install_no_binary_via_config_disables_cached_wheels(
script, data, common_wheels):
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
config_file = tempfile.NamedTemporaryFile(mode='wt')
script.environ['PIP_CONFIG_FILE'] = config_file.name
config_file.write(textwrap.dedent("""\
[global]
no-binary = :all:
"""))
config_file.flush()
res = script.pip(
'install', '--no-index', '-f', data.find_links,
'upper', expect_stderr=True)
config_file = tempfile.NamedTemporaryFile(mode='wt', delete=False)
try:
script.environ['PIP_CONFIG_FILE'] = config_file.name
config_file.write(textwrap.dedent("""\
[global]
no-binary = :all:
"""))
config_file.close()
res = script.pip(
'install', '--no-index', '-f', data.find_links,
'upper', expect_stderr=True)
finally:
os.unlink(config_file.name)
assert "Successfully installed upper-2.0" in str(res), str(res)
# No wheel building for upper, which was blacklisted
assert "Running setup.py bdist_wheel for upper" not in str(res), str(res)

View File

@ -70,7 +70,7 @@ def test_nonexistent_extra_warns_user_no_wheel(script, data):
assert (
"simple 3.0 does not provide the extra 'nonexistent'"
in result.stderr
)
), str(result)
def test_nonexistent_extra_warns_user_with_wheel(script, data):

View File

@ -1,3 +1,4 @@
import os
import textwrap
from pip._vendor.six.moves.urllib import parse as urllib_parse
@ -29,7 +30,7 @@ def test_find_links_requirements_file_relative_path(script, data):
--no-index
--find-links=%s
parent==0.1
""" % data.packages))
""" % data.packages.replace(os.path.sep, '/')))
result = script.pip(
'install',
'-r',

View File

@ -1,10 +1,11 @@
import os.path
import os
import textwrap
import pytest
from tests.lib import (
_create_test_package_with_subdirectory, pyversion, requirements_file
_create_test_package_with_subdirectory, path_to_url, pyversion,
requirements_file
)
from tests.lib.local_repos import local_checkout
@ -68,13 +69,13 @@ def test_relative_requirements_file(script, data):
# Compute relative install path to FSPkg from scratch path.
full_rel_path = data.packages.join('FSPkg') - script.scratch_path
full_rel_url = 'file:' + full_rel_path + '#egg=FSPkg'
embedded_rel_path = script.scratch_path.join(full_rel_path)
# For each relative path, install as either editable or not using either
# URLs with egg links or not.
for req_path in (full_rel_path,
'file:' + full_rel_path + '#egg=FSPkg',
embedded_rel_path):
for req_path in (full_rel_path, full_rel_url, embedded_rel_path):
req_path = req_path.replace(os.path.sep, '/')
# Regular install.
with requirements_file(req_path + '\n',
script.scratch_path) as reqs_file:
@ -203,7 +204,7 @@ def test_install_local_editable_with_subdirectory(script):
result = script.pip(
'install', '-e',
'%s#egg=version_subpkg&subdirectory=version_subdir' %
('git+file://%s' % version_pkg_path,)
('git+%s' % path_to_url(version_pkg_path),)
)
result.assert_installed('version-subpkg', sub_dir='version_subdir')
@ -216,7 +217,7 @@ def test_install_local_with_subdirectory(script):
result = script.pip(
'install',
'%s#egg=version_subpkg&subdirectory=version_subdir' %
('git+file://%s' % version_pkg_path,)
('git+' + path_to_url(version_pkg_path),)
)
result.assert_installed('version_subpkg.py', editable=False)
@ -228,9 +229,13 @@ def test_wheel_user_with_prefix_in_pydistutils_cfg(
# Make sure wheel is available in the virtualenv
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
virtualenv.system_site_packages = True
homedir = script.environ["HOME"]
if os.name == 'posix':
user_filename = ".pydistutils.cfg"
else:
user_filename = "pydistutils.cfg"
user_cfg = os.path.join(os.path.expanduser('~'), user_filename)
script.scratch_path.join("bin").mkdir()
with open(os.path.join(homedir, ".pydistutils.cfg"), "w") as cfg:
with open(user_cfg, "w") as cfg:
cfg.write(textwrap.dedent("""
[install]
prefix=%s""" % script.scratch_path))
@ -310,7 +315,7 @@ def test_constraints_local_install_causes_error(script, data):
def test_constraints_constrain_to_local_editable(script, data):
to_install = data.src.join("singlemodule")
script.scratch_path.join("constraints.txt").write(
"-e file://%s#egg=singlemodule" % to_install
"-e %s#egg=singlemodule" % path_to_url(to_install)
)
result = script.pip(
'install', '--no-index', '-f', data.find_links, '-c',
@ -321,7 +326,7 @@ def test_constraints_constrain_to_local_editable(script, data):
def test_constraints_constrain_to_local(script, data):
to_install = data.src.join("singlemodule")
script.scratch_path.join("constraints.txt").write(
"file://%s#egg=singlemodule" % to_install
"%s#egg=singlemodule" % path_to_url(to_install)
)
result = script.pip(
'install', '--no-index', '-f', data.find_links, '-c',
@ -331,13 +336,13 @@ def test_constraints_constrain_to_local(script, data):
def test_constrained_to_url_install_same_url(script, data):
to_install = data.src.join("singlemodule")
script.scratch_path.join("constraints.txt").write(
"file://%s#egg=singlemodule" % to_install
)
constraints = path_to_url(to_install) + "#egg=singlemodule"
script.scratch_path.join("constraints.txt").write(constraints)
result = script.pip(
'install', '--no-index', '-f', data.find_links, '-c',
script.scratch_path / 'constraints.txt', to_install)
assert 'Running setup.py install for singlemodule' in result.stdout
assert ('Running setup.py install for singlemodule'
in result.stdout), str(result)
@pytest.mark.network
@ -377,7 +382,7 @@ def test_double_install_spurious_hash_mismatch(
def test_install_with_extras_from_constraints(script, data):
to_install = data.packages.join("LocalExtras")
script.scratch_path.join("constraints.txt").write(
"file://%s#egg=LocalExtras[bar]" % to_install
"%s#egg=LocalExtras[bar]" % path_to_url(to_install)
)
result = script.pip_install_local(
'-c', script.scratch_path / 'constraints.txt', 'LocalExtras')
@ -387,7 +392,7 @@ def test_install_with_extras_from_constraints(script, data):
def test_install_with_extras_from_install(script, data):
to_install = data.packages.join("LocalExtras")
script.scratch_path.join("constraints.txt").write(
"file://%s#egg=LocalExtras" % to_install
"%s#egg=LocalExtras" % path_to_url(to_install)
)
result = script.pip_install_local(
'-c', script.scratch_path / 'constraints.txt', 'LocalExtras[baz]')
@ -397,7 +402,7 @@ def test_install_with_extras_from_install(script, data):
def test_install_with_extras_joined(script, data):
to_install = data.packages.join("LocalExtras")
script.scratch_path.join("constraints.txt").write(
"file://%s#egg=LocalExtras[bar]" % to_install
"%s#egg=LocalExtras[bar]" % path_to_url(to_install)
)
result = script.pip_install_local(
'-c', script.scratch_path / 'constraints.txt', 'LocalExtras[baz]'
@ -409,7 +414,7 @@ def test_install_with_extras_joined(script, data):
def test_install_with_extras_editable_joined(script, data):
to_install = data.packages.join("LocalExtras")
script.scratch_path.join("constraints.txt").write(
"-e file://%s#egg=LocalExtras[bar]" % to_install
"-e %s#egg=LocalExtras[bar]" % path_to_url(to_install)
)
result = script.pip_install_local(
'-c', script.scratch_path / 'constraints.txt', 'LocalExtras[baz]')

View File

@ -6,6 +6,57 @@ from tests.lib import (
from tests.lib.local_repos import local_checkout
def _install_version_pkg(script, path, rev=None):
"""
Install the version_pkg package, and return the version installed.
Args:
path: a tests.lib.path.Path object pointing to a Git repository
containing the package.
rev: an optional revision to install like a branch name or tag.
"""
path = path.abspath.replace('\\', '/')
revision = '' if rev is None else '@{}'.format(rev)
url = 'git+file://{}{}#egg=version_pkg'.format(path, revision)
script.pip('install', '-e', url)
result = script.run('version_pkg')
version = result.stdout.strip()
return version
def test_git_install_again_after_changes(script):
"""
Test installing a repository a second time without specifying a revision,
and after updates to the remote repository.
This test also checks that no warning message like the following gets
logged on the update: "Did not find branch or tag ..., assuming ref or
revision."
"""
version_pkg_path = _create_test_package(script)
version = _install_version_pkg(script, version_pkg_path)
assert version == '0.1'
_change_test_package_version(script, version_pkg_path)
version = _install_version_pkg(script, version_pkg_path)
assert version == 'some different version'
def test_git_install_branch_again_after_branch_changes(script):
"""
Test installing a branch again after the branch is updated in the remote
repository.
"""
version_pkg_path = _create_test_package(script)
version = _install_version_pkg(script, version_pkg_path, rev='master')
assert version == '0.1'
_change_test_package_version(script, version_pkg_path)
version = _install_version_pkg(script, version_pkg_path, rev='master')
assert version == 'some different version'
@pytest.mark.network
def test_install_editable_from_git_with_https(script, tmpdir):
"""

View File

@ -10,22 +10,10 @@ from tests.lib.git_submodule_helpers import (
@pytest.mark.network
def test_get_short_refs_should_return_tag_name_and_commit_pair(script):
version_pkg_path = _create_test_package(script)
script.run('git', 'tag', '0.1', cwd=version_pkg_path)
script.run('git', 'tag', '0.2', cwd=version_pkg_path)
commit = script.run(
'git', 'rev-parse', 'HEAD',
cwd=version_pkg_path
).stdout.strip()
git = Git()
result = git.get_short_refs(version_pkg_path)
assert result['0.1'] == commit, result
assert result['0.2'] == commit, result
@pytest.mark.network
def test_get_short_refs_should_return_branch_name_and_commit_pair(script):
def test_is_commit_id_equal(script):
"""
Test Git.is_commit_id_equal().
"""
version_pkg_path = _create_test_package(script)
script.run('git', 'branch', 'branch0.1', cwd=version_pkg_path)
commit = script.run(
@ -33,79 +21,54 @@ def test_get_short_refs_should_return_branch_name_and_commit_pair(script):
cwd=version_pkg_path
).stdout.strip()
git = Git()
result = git.get_short_refs(version_pkg_path)
assert result['master'] == commit, result
assert result['branch0.1'] == commit, result
assert git.is_commit_id_equal(version_pkg_path, commit)
assert not git.is_commit_id_equal(version_pkg_path, commit[:7])
assert not git.is_commit_id_equal(version_pkg_path, 'branch0.1')
assert not git.is_commit_id_equal(version_pkg_path, 'abc123')
# Also check passing a None value.
assert not git.is_commit_id_equal(version_pkg_path, None)
@pytest.mark.network
def test_get_short_refs_should_ignore_no_branch(script):
version_pkg_path = _create_test_package(script)
script.run('git', 'branch', 'branch0.1', cwd=version_pkg_path)
commit = script.run(
'git', 'rev-parse', 'HEAD',
cwd=version_pkg_path
).stdout.strip()
# current branch here is "* (nobranch)"
script.run(
'git', 'checkout', commit,
cwd=version_pkg_path,
expect_stderr=True,
)
@patch('pip._internal.vcs.git.Git.get_revision_sha')
def test_check_rev_options_ref_exists(get_sha_mock):
get_sha_mock.return_value = '123456'
git = Git()
result = git.get_short_refs(version_pkg_path)
assert result['master'] == commit, result
assert result['branch0.1'] == commit, result
def call_check_version(vcs, path, rev):
rev_options = vcs.make_rev_options(rev)
return vcs.check_version(path, rev_options)
@pytest.mark.network
def test_check_version(script):
version_pkg_path = _create_test_package(script)
script.run('git', 'branch', 'branch0.1', cwd=version_pkg_path)
commit = script.run(
'git', 'rev-parse', 'HEAD',
cwd=version_pkg_path
).stdout.strip()
git = Git()
assert call_check_version(git, version_pkg_path, commit)
assert call_check_version(git, version_pkg_path, commit[:7])
assert not call_check_version(git, version_pkg_path, 'branch0.1')
assert not call_check_version(git, version_pkg_path, 'abc123')
@patch('pip._internal.vcs.git.Git.get_short_refs')
def test_check_rev_options_should_handle_branch_name(get_refs_mock):
get_refs_mock.return_value = {'master': '123456', '0.1': 'abc123'}
git = Git()
rev_options = git.make_rev_options('master')
rev_options = git.make_rev_options('develop')
new_options = git.check_rev_options('.', rev_options)
assert new_options.rev == '123456'
@patch('pip._internal.vcs.git.Git.get_short_refs')
def test_check_rev_options_should_handle_tag_name(get_refs_mock):
get_refs_mock.return_value = {'master': '123456', '0.1': 'abc123'}
@patch('pip._internal.vcs.git.Git.get_revision_sha')
def test_check_rev_options_ref_not_found(get_sha_mock):
get_sha_mock.return_value = None
git = Git()
rev_options = git.make_rev_options('0.1')
rev_options = git.make_rev_options('develop')
new_options = git.check_rev_options('.', rev_options)
assert new_options.rev == 'abc123'
assert new_options.rev == 'develop'
@patch('pip._internal.vcs.git.Git.get_short_refs')
def test_check_rev_options_should_handle_ambiguous_commit(get_refs_mock):
get_refs_mock.return_value = {'master': '123456', '0.1': '123456'}
@patch('pip._internal.vcs.git.Git.get_revision_sha')
def test_check_rev_options_not_found_warning(get_sha_mock, caplog):
get_sha_mock.return_value = None
git = Git()
rev_options = git.make_rev_options('0.1')
sha = 40 * 'a'
rev_options = git.make_rev_options(sha)
new_options = git.check_rev_options('.', rev_options)
assert new_options.rev == '123456'
assert new_options.rev == sha
rev_options = git.make_rev_options(sha[:6])
new_options = git.check_rev_options('.', rev_options)
assert new_options.rev == 'aaaaaa'
# Check that a warning got logged only for the abbreviated hash.
messages = [r.getMessage() for r in caplog.records]
messages = [msg for msg in messages if msg.startswith('Did not find ')]
assert messages == [
"Did not find branch or tag 'aaaaaa', assuming revision or ref."
]
# TODO(pnasrat) fix all helpers to do right things with paths on windows.

View File

@ -1,3 +1,4 @@
import distutils
import glob
import os
import sys
@ -187,11 +188,8 @@ def test_install_wheel_with_prefix(script, data):
'install', 'simple.dist==0.1', '--prefix', prefix_dir,
'--no-index', '--find-links=' + data.find_links,
)
if hasattr(sys, "pypy_version_info"):
lib = Path('scratch') / 'prefix' / 'site-packages'
else:
lib = Path('scratch') / 'prefix' / 'lib'
assert lib in result.files_created
lib = distutils.sysconfig.get_python_lib(prefix=Path('scratch') / 'prefix')
assert lib in result.files_created, str(result)
def test_install_from_wheel_installs_deps(script, data):
@ -234,7 +232,7 @@ def test_install_user_wheel(script, virtualenv, data, common_wheels):
egg_info_folder = script.user_site / 'has.script-1.0.dist-info'
assert egg_info_folder in result.files_created, str(result)
script_file = script.user_bin / 'script.py'
assert script_file in result.files_created
assert script_file in result.files_created, str(result)
def test_install_from_wheel_gen_entrypoint(script, data):

View File

@ -180,6 +180,8 @@ def test_uninstall_entry_point(script, console_scripts):
}
)
script_name = script.bin_path.join(console_scripts.split('=')[0].strip())
if sys.platform == 'win32':
script_name += '.exe'
result = script.pip('install', pkg_path)
assert script_name.exists
result = script.pip('list', '--format=json')
@ -204,6 +206,8 @@ def test_uninstall_gui_scripts(script):
entry_points={"gui_scripts": ["test_ = distutils_install", ], }
)
script_name = script.bin_path.join('test_')
if sys.platform == 'win32':
script_name += '.exe'
script.pip('install', pkg_path)
assert script_name.exists
script.pip('uninstall', pkg_name, '-y')
@ -424,8 +428,8 @@ def test_uninstall_setuptools_develop_install(script, data):
script.run('python', 'setup.py', 'install',
expect_stderr=True, cwd=pkg_path)
list_result = script.pip('list', '--format=json')
assert {"name": "FSPkg", "version": "0.1.dev0"} \
in json.loads(list_result.stdout)
assert {"name": os.path.normcase("FSPkg"), "version": "0.1.dev0"} \
in json.loads(list_result.stdout), str(list_result)
# Uninstall both develop and install
uninstall = script.pip('uninstall', 'FSPkg', '-y')
assert any(filename.endswith('.egg')

View File

@ -1,7 +1,7 @@
"""
tests specific to uninstalling --user installs
"""
from os.path import isdir, isfile
from os.path import isdir, isfile, normcase
import pytest
@ -49,8 +49,8 @@ class Tests_UninstallUserSite:
result3 = script.pip('uninstall', '-vy', 'pip-test-package')
# uninstall console is mentioning user scripts, but not global scripts
assert script.user_bin_path in result3.stdout
assert script.bin_path not in result3.stdout
assert normcase(script.user_bin_path) in result3.stdout, str(result3)
assert normcase(script.bin_path) not in result3.stdout, str(result3)
# uninstall worked
assert_all_changes(result2, result3, [script.venv / 'build', 'cache'])

View File

@ -0,0 +1,32 @@
import os
from pip._internal.utils.temp_dir import TempDirectory
from pip._internal.vcs.git import Git
def test_git_dir_ignored():
"""
Test that a GIT_DIR environment variable is ignored.
"""
git = Git()
with TempDirectory() as temp:
temp_dir = temp.path
env = {'GIT_DIR': 'foo'}
# If GIT_DIR is not ignored, then os.listdir() will return ['foo'].
git.run_command(['init', temp_dir], cwd=temp_dir, extra_environ=env)
assert os.listdir(temp_dir) == ['.git']
def test_git_work_tree_ignored():
"""
Test that a GIT_WORK_TREE environment variable is ignored.
"""
git = Git()
with TempDirectory() as temp:
temp_dir = temp.path
git.run_command(['init', temp_dir], cwd=temp_dir)
# Choose a directory relative to the cwd that does not exist.
# If GIT_WORK_TREE is not ignored, then the command will error out
# with: "fatal: This operation must be run in a work tree".
env = {'GIT_WORK_TREE': 'foo'}
git.run_command(['status', temp_dir], extra_environ=env, cwd=temp_dir)

View File

@ -0,0 +1,92 @@
"""
Contains functional tests of the Git class.
"""
from pip._internal.utils.temp_dir import TempDirectory
from pip._internal.vcs.git import Git
def get_head_sha(script, dest):
"""Return the HEAD sha."""
result = script.run('git', 'rev-parse', 'HEAD', cwd=dest)
sha = result.stdout.strip()
return sha
def do_commit(script, dest):
script.run(
'git', 'commit', '-q', '--author', 'pip <pypa-dev@googlegroups.com>',
'--allow-empty', '-m', 'test commit', cwd=dest
)
return get_head_sha(script, dest)
def add_commits(script, dest, count):
"""Return a list of the commit hashes from oldest to newest."""
shas = []
for index in range(count):
sha = do_commit(script, dest)
shas.append(sha)
return shas
def check_rev(repo_dir, rev, expected_sha):
git = Git()
assert git.get_revision_sha(repo_dir, rev) == expected_sha
def test_get_revision_sha(script):
with TempDirectory(kind="testing") as temp:
repo_dir = temp.path
script.run('git', 'init', cwd=repo_dir)
shas = add_commits(script, repo_dir, count=3)
tag_sha = shas[0]
origin_sha = shas[1]
head_sha = shas[2]
assert head_sha == shas[-1]
origin_ref = 'refs/remotes/origin/origin-branch'
generic_ref = 'refs/generic-ref'
script.run(
'git', 'branch', 'local-branch', head_sha, cwd=repo_dir
)
script.run('git', 'tag', 'v1.0', tag_sha, cwd=repo_dir)
script.run('git', 'update-ref', origin_ref, origin_sha, cwd=repo_dir)
script.run(
'git', 'update-ref', 'refs/remotes/upstream/upstream-branch',
head_sha, cwd=repo_dir
)
script.run('git', 'update-ref', generic_ref, head_sha, cwd=repo_dir)
# Test two tags pointing to the same sha.
script.run('git', 'tag', 'v2.0', tag_sha, cwd=repo_dir)
# Test tags sharing the same suffix as another tag, both before and
# after the suffix alphabetically.
script.run('git', 'tag', 'aaa/v1.0', head_sha, cwd=repo_dir)
script.run('git', 'tag', 'zzz/v1.0', head_sha, cwd=repo_dir)
check_rev(repo_dir, 'v1.0', tag_sha)
check_rev(repo_dir, 'v2.0', tag_sha)
check_rev(repo_dir, 'origin-branch', origin_sha)
ignored_names = [
# Local branches should be ignored.
'local-branch',
# Non-origin remote branches should be ignored.
'upstream-branch',
# Generic refs should be ignored.
'generic-ref',
# Fully spelled-out refs should be ignored.
origin_ref,
generic_ref,
# Test passing a valid commit hash.
tag_sha,
# Test passing a non-existent name.
'does-not-exist',
]
for name in ignored_names:
check_rev(repo_dir, name, None)

View File

@ -12,7 +12,7 @@ from tests.lib.yaml_helpers import generate_yaml_tests, id_func
_conflict_finder_re = re.compile(
# Conflicting Requirements: \
# A 1.0.0 requires B == 2.0.0, C 1.0.0 requires B == 1.0.0.
"""
r"""
(?P<package>[\w\-_]+?)
[ ]
(?P<version>\S+?)

View File

@ -7,7 +7,9 @@ import re
import textwrap
import site
import shutil
import subprocess
import pytest
import scripttest
import six
import virtualenv
@ -32,7 +34,9 @@ def path_to_url(path):
filepath = path.split(os.path.sep)
url = '/'.join(filepath)
if drive:
return 'file:///' + drive + url
# Note: match urllib.request.pathname2url's
# behavior: uppercase the drive letter.
return 'file:///' + drive.upper() + url
return 'file://' + url
@ -197,10 +201,11 @@ class TestPipResult(object):
)
egg_link_file = self.files_created[egg_link_path]
egg_link_contents = egg_link_file.bytes.replace(os.linesep, '\n')
# FIXME: I don't understand why there's a trailing . here
if not (egg_link_file.bytes.endswith('\n.') and
egg_link_file.bytes[:-2].endswith(pkg_dir)):
if not (egg_link_contents.endswith('\n.') and
egg_link_contents[:-2].endswith(pkg_dir)):
raise TestFailure(textwrap.dedent(u'''\
Incorrect egg_link file %r
Expected ending: %r
@ -209,7 +214,7 @@ class TestPipResult(object):
-------------------------------''' % (
egg_link_file,
pkg_dir + '\n.',
repr(egg_link_file.bytes))
repr(egg_link_contents))
))
if use_user_site:
@ -283,13 +288,20 @@ class PipTestEnvironment(scripttest.TestFileEnvironment):
self.site_packages_path = self.lib_path.join("site-packages")
self.user_base_path = self.venv_path.join("user")
self.user_bin_path = self.user_base_path.join(
self.bin_path - self.venv_path
)
self.user_site_path = self.venv_path.join(
"user",
site.USER_SITE[len(site.USER_BASE) + 1:],
)
if sys.platform == 'win32':
if sys.version_info >= (3, 5):
scripts_base = self.user_site_path.join('..').normpath
else:
scripts_base = self.user_base_path
self.user_bin_path = scripts_base.join('Scripts')
else:
self.user_bin_path = self.user_base_path.join(
self.bin_path - self.venv_path
)
# Create a Directory to use as a scratch pad
self.scratch_path = base_path.join("scratch").mkdir()
@ -308,6 +320,8 @@ class PipTestEnvironment(scripttest.TestFileEnvironment):
environ["PYTHONUSERBASE"] = self.user_base_path
# Writing bytecode can mess up updated file detection
environ["PYTHONDONTWRITEBYTECODE"] = "1"
# Make sure we get UTF-8 on output, even on Windows...
environ["PYTHONIOENCODING"] = "UTF-8"
kwargs["environ"] = environ
# Call the TestFileEnvironment __init__
@ -343,6 +357,9 @@ class PipTestEnvironment(scripttest.TestFileEnvironment):
run_from = kw.pop('run_from', None)
assert not cwd or not run_from, "Don't use run_from; it's going away"
cwd = cwd or run_from or self.cwd
if sys.platform == 'win32':
# Partial fix for ScriptTest.run using `shell=True` on Windows.
args = [str(a).replace('^', '^^').replace('&', '^&') for a in args]
return TestPipResult(
super(PipTestEnvironment, self).run(cwd=cwd, *args, **kw),
verbose=self.verbose,
@ -358,8 +375,12 @@ class PipTestEnvironment(scripttest.TestFileEnvironment):
# Python 3.3 is deprecated and we emit a warning on it.
if pyversion_tuple[:2] == (3, 3):
kwargs['expect_stderr'] = True
return self.run("pip", *args, **kwargs)
if kwargs.pop('use_module', False):
exe = 'python'
args = ('-m', 'pip') + args
else:
exe = 'pip'
return self.run(exe, *args, **kwargs)
def pip_install_local(self, *args, **kwargs):
return self.pip(
@ -730,3 +751,25 @@ def create_basic_wheel_for_package(script, name, version, depends, extras):
script.temp_path.mkdir()
return retval
def need_executable(name, check_cmd):
def wrapper(fn):
try:
subprocess.check_output(check_cmd)
except OSError:
return pytest.mark.skip(reason='%s is not available' % name)(fn)
return fn
return wrapper
def need_bzr(fn):
return pytest.mark.bzr(need_executable(
'Bazaar', ('bzr', 'version', '--short')
)(fn))
def need_mercurial(fn):
return pytest.mark.mercurial(need_executable(
'Mercurial', ('hg', 'version')
)(fn))

View File

@ -39,7 +39,7 @@ class TestUserCacheDir:
def test_user_cache_dir_linux(self, monkeypatch):
monkeypatch.setattr(appdirs, "WINDOWS", False)
monkeypatch.setattr(os, "path", posixpath)
monkeypatch.delenv("XDG_CACHE_HOME")
monkeypatch.delenv("XDG_CACHE_HOME", raising=False)
monkeypatch.setenv("HOME", "/home/test")
monkeypatch.setattr(sys, "platform", "linux2")
@ -58,7 +58,7 @@ class TestUserCacheDir:
monkeypatch.setattr(appdirs, "WINDOWS", False)
monkeypatch.setattr(os, "path", posixpath)
# Verify that we are not affected by http://bugs.python.org/issue14768
monkeypatch.delenv("XDG_CACHE_HOME")
monkeypatch.delenv("XDG_CACHE_HOME", raising=False)
monkeypatch.setenv("HOME", "/")
monkeypatch.setattr(sys, "platform", "linux2")
@ -115,7 +115,7 @@ class TestSiteConfigDirs:
def test_site_config_dirs_linux(self, monkeypatch):
monkeypatch.setattr(appdirs, "WINDOWS", False)
monkeypatch.setattr(os, "path", posixpath)
monkeypatch.delenv("XDG_CONFIG_DIRS")
monkeypatch.delenv("XDG_CONFIG_DIRS", raising=False)
monkeypatch.setattr(sys, "platform", "linux2")
assert appdirs.site_config_dirs("pip") == [
@ -194,7 +194,7 @@ class TestUserDataDir:
def test_user_data_dir_linux(self, monkeypatch):
monkeypatch.setattr(appdirs, "WINDOWS", False)
monkeypatch.setattr(os, "path", posixpath)
monkeypatch.delenv("XDG_DATA_HOME")
monkeypatch.delenv("XDG_DATA_HOME", raising=False)
monkeypatch.setenv("HOME", "/home/test")
monkeypatch.setattr(sys, "platform", "linux2")
@ -213,7 +213,7 @@ class TestUserDataDir:
monkeypatch.setattr(appdirs, "WINDOWS", False)
monkeypatch.setattr(os, "path", posixpath)
# Verify that we are not affected by http://bugs.python.org/issue14768
monkeypatch.delenv("XDG_DATA_HOME")
monkeypatch.delenv("XDG_DATA_HOME", raising=False)
monkeypatch.setenv("HOME", "/")
monkeypatch.setattr(sys, "platform", "linux2")
@ -276,7 +276,7 @@ class TestUserConfigDir:
def test_user_config_dir_linux(self, monkeypatch):
monkeypatch.setattr(appdirs, "WINDOWS", False)
monkeypatch.setattr(os, "path", posixpath)
monkeypatch.delenv("XDG_CONFIG_HOME")
monkeypatch.delenv("XDG_CONFIG_HOME", raising=False)
monkeypatch.setenv("HOME", "/home/test")
monkeypatch.setattr(sys, "platform", "linux2")
@ -295,7 +295,7 @@ class TestUserConfigDir:
monkeypatch.setattr(appdirs, "WINDOWS", False)
monkeypatch.setattr(os, "path", posixpath)
# Verify that we are not affected by http://bugs.python.org/issue14768
monkeypatch.delenv("XDG_CONFIG_HOME")
monkeypatch.delenv("XDG_CONFIG_HOME", raising=False)
monkeypatch.setenv("HOME", "/")
monkeypatch.setattr(sys, "platform", "linux2")

View File

@ -21,7 +21,7 @@ from pip._internal.req.req_file import process_line
from pip._internal.req.req_install import parse_editable
from pip._internal.resolve import Resolver
from pip._internal.utils.misc import read_text_file
from tests.lib import assert_raises_regexp, requirements_file
from tests.lib import DATA_DIR, assert_raises_regexp, requirements_file
class TestRequirementSet(object):
@ -165,10 +165,6 @@ class TestRequirementSet(object):
wheel_cache=None)
assert req_set.require_hashes
# This test doesn't appear to handle URL-encoded Windows paths
# correctly. Needs reviewing by someone who understands the logic.
@pytest.mark.xfail("sys.platform == 'win32'",
reason="Code doesn't handle url-encoded Windows paths")
def test_unsupported_hashes(self, data):
"""VCS and dir links should raise errors when --require-hashes is
on.
@ -385,22 +381,18 @@ class TestInstallRequirement(object):
req = InstallRequirement.from_editable(url)
assert req.link.url == url
def test_get_dist(self):
req = InstallRequirement.from_line('foo')
req.egg_info_path = Mock(return_value='/path/to/foo.egg-info')
dist = req.get_dist()
assert isinstance(dist, pkg_resources.Distribution)
assert dist.project_name == 'foo'
assert dist.location == '/path/to'
def test_get_dist_trailing_slash(self):
@pytest.mark.parametrize('path', (
'/path/to/foo.egg-info'.replace('/', os.path.sep),
# Tests issue fixed by https://github.com/pypa/pip/pull/2530
'/path/to/foo.egg-info/'.replace('/', os.path.sep),
))
def test_get_dist(self, path):
req = InstallRequirement.from_line('foo')
req.egg_info_path = Mock(return_value='/path/to/foo.egg-info/')
req.egg_info_path = Mock(return_value=path)
dist = req.get_dist()
assert isinstance(dist, pkg_resources.Distribution)
assert dist.project_name == 'foo'
assert dist.location == '/path/to'
assert dist.location == '/path/to'.replace('/', os.path.sep)
def test_markers(self):
for line in (
@ -605,3 +597,17 @@ def test_exclusive_environment_markers():
req_set.add_requirement(eq26)
req_set.add_requirement(ne26)
assert req_set.has_requirement('Django')
def test_mismatched_versions(caplog, tmpdir):
original_source = os.path.join(DATA_DIR, 'src', 'simplewheel-1.0')
source_dir = os.path.join(tmpdir, 'simplewheel')
shutil.copytree(original_source, source_dir)
req = InstallRequirement(req=Requirement('simplewheel==2.0'),
comes_from=None, source_dir=source_dir)
req.run_egg_info()
req.assert_source_matches_version()
assert caplog.records[-1].message == (
'Requested simplewheel==2.0, '
'but installing version 1.0'
)

View File

@ -48,9 +48,9 @@ def test_compressed_listing(tmpdir):
def in_tmpdir(paths):
li = []
for path in paths:
li.append(
str(os.path.join(tmpdir, path.replace("/", os.path.sep)))
)
li.append(str(os.path.normcase(
os.path.join(tmpdir, path.replace("/", os.path.sep))
)))
return li
sample = in_tmpdir([

View File

@ -23,8 +23,8 @@ from pip._internal.utils.encoding import auto_decode
from pip._internal.utils.glibc import check_glibc_version
from pip._internal.utils.hashes import Hashes, MissingHashes
from pip._internal.utils.misc import (
egg_link_path, ensure_dir, get_installed_distributions, normalize_path,
rmtree, untar_file, unzip_file
egg_link_path, ensure_dir, get_installed_distributions, get_prog,
normalize_path, rmtree, untar_file, unzip_file
)
from pip._internal.utils.packaging import check_dist_requires_python
from pip._internal.utils.temp_dir import TempDirectory
@ -592,3 +592,23 @@ class TestCheckRequiresPython(object):
check_dist_requires_python(fake_dist)
else:
check_dist_requires_python(fake_dist)
class TestGetProg(object):
@pytest.mark.parametrize(
("argv", "executable", "expected"),
[
('/usr/bin/pip', '', 'pip'),
('-c', '/usr/bin/python', '/usr/bin/python -m pip'),
('__main__.py', '/usr/bin/python', '/usr/bin/python -m pip'),
('/usr/bin/pip3', '', 'pip3'),
]
)
def test_get_prog(self, monkeypatch, argv, executable, expected):
monkeypatch.setattr('pip._internal.utils.misc.sys.argv', [argv])
monkeypatch.setattr(
'pip._internal.utils.misc.sys.executable',
executable
)
assert get_prog() == expected

View File

@ -4,7 +4,7 @@ from pip._vendor.packaging.version import parse as parse_version
from pip._internal.vcs import RevOptions, VersionControl
from pip._internal.vcs.bazaar import Bazaar
from pip._internal.vcs.git import Git
from pip._internal.vcs.git import Git, looks_like_hash
from pip._internal.vcs.mercurial import Mercurial
from pip._internal.vcs.subversion import Subversion
from tests.lib import pyversion
@ -23,11 +23,11 @@ def test_rev_options_repr():
@pytest.mark.parametrize(('vcs', 'expected1', 'expected2', 'kwargs'), [
# First check VCS-specific RevOptions behavior.
(Bazaar(), [], ['-r', '123'], {}),
(Git(), ['origin/HEAD'], ['123'], {}),
(Git(), ['HEAD'], ['123'], {}),
(Mercurial(), [], ['123'], {}),
(Subversion(), [], ['-r', '123'], {}),
# Test extra_args. For this, test using a single VersionControl class.
(Git(), ['origin/HEAD', 'opt1', 'opt2'], ['123', 'opt1', 'opt2'],
(Git(), ['HEAD', 'opt1', 'opt2'], ['123', 'opt1', 'opt2'],
dict(extra_args=['opt1', 'opt2'])),
])
def test_rev_options_to_args(vcs, expected1, expected2, kwargs):
@ -73,22 +73,10 @@ def test_rev_options_make_new():
@pytest.fixture
def git():
git_url = 'http://github.com/pypa/pip-test-package'
refs = {
'0.1': 'a8992fc7ee17e5b9ece022417b64594423caca7c',
'0.1.1': '7d654e66c8fa7149c165ddeffa5b56bc06619458',
'0.1.2': 'f1c1020ebac81f9aeb5c766ff7a772f709e696ee',
'foo': '5547fa909e83df8bd743d3978d6667497983a4b7',
'bar': '5547fa909e83df8bd743d3978d6667497983a4b7',
'master': '5547fa909e83df8bd743d3978d6667497983a4b7',
'origin/master': '5547fa909e83df8bd743d3978d6667497983a4b7',
'origin/HEAD': '5547fa909e83df8bd743d3978d6667497983a4b7',
}
sha = refs['foo']
sha = '5547fa909e83df8bd743d3978d6667497983a4b7'
git = Git()
git.get_url = Mock(return_value=git_url)
git.get_revision = Mock(return_value=sha)
git.get_short_refs = Mock(return_value=refs)
return git
@ -99,6 +87,15 @@ def dist():
return dist
def test_looks_like_hash():
assert looks_like_hash(40 * 'a')
assert looks_like_hash(40 * 'A')
# Test a string containing all valid characters.
assert looks_like_hash(18 * 'a' + '0123456789abcdefABCDEF')
assert not looks_like_hash(40 * 'g')
assert not looks_like_hash(39 * 'a')
def test_git_get_src_requirements(git, dist):
ret = git.get_src_requirement(dist, location='.')
@ -109,15 +106,19 @@ def test_git_get_src_requirements(git, dist):
])
@pytest.mark.parametrize('ref,result', (
@pytest.mark.parametrize('rev_name,result', (
('5547fa909e83df8bd743d3978d6667497983a4b7', True),
('5547fa909', True),
('5547fa909', False),
('5678', False),
('abc123', False),
('foo', False),
(None, False),
))
def test_git_check_version(git, ref, result):
rev_options = git.make_rev_options(ref)
assert git.check_version('foo', rev_options) is result
def test_git_is_commit_id_equal(git, rev_name, result):
"""
Test Git.is_commit_id_equal().
"""
assert git.is_commit_id_equal('/path', rev_name) is result
def test_translate_egg_surname():

12
tox.ini
View File

@ -4,6 +4,7 @@ envlist =
py27, py33, py34, py35, py36, py37, pypy
[testenv]
passenv = GIT_SSL_CAINFO
setenv =
# This is required in order to get UTF-8 output inside of the subprocesses
# that our tests use.
@ -11,13 +12,18 @@ setenv =
deps = -r{toxinidir}/dev-requirements.txt
commands = py.test --timeout 300 []
install_command = python -m pip install {opts} {packages}
usedevelop = True
[testenv:docs]
deps = sphinx == 1.6.1
deps =
sphinx == 1.6.1
git+https://github.com/python/python-docs-theme.git#egg=python-docs-theme
git+https://github.com/pypa/pypa-docs-theme.git#egg=pypa-docs-theme
basepython = python2.7
commands =
sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/_build/html
sphinx-build -W -b man -d {envtmpdir}/doctrees docs docs/_build/man
sphinx-build -W -b html -d {envtmpdir}/doctrees docs docs/build/html
sphinx-build -W -b man -d {envtmpdir}/doctrees docs docs/build/man
[testenv:packaging]
deps =