diff --git a/.tox_helpers/runpip.py b/.tox_helpers/runpip.py new file mode 100644 index 00000000000..3b279cf3379 --- /dev/null +++ b/.tox_helpers/runpip.py @@ -0,0 +1,54 @@ +from glob import glob +import distutils.sysconfig +import os +import shutil +import subprocess +import sys +import textwrap + + +VIRTUAL_ENV = os.environ['VIRTUAL_ENV'] +TOX_PIP_DIR = os.path.join(VIRTUAL_ENV, 'pip') +SITE_PACKAGES = distutils.sysconfig.get_python_lib() + + +def pip(args): + # First things first, safeguard the environment + # original pip so it can be used for all calls. + if not os.path.exists(TOX_PIP_DIR): + os.mkdir(TOX_PIP_DIR) + # Remove executable/launchers. + for entry in glob(os.path.join(VIRTUAL_ENV, 'bin', 'pip*')): + os.unlink(entry) + # Relocate package and distribution info. + for src in ( + os.path.join(SITE_PACKAGES, 'pip'), + glob(os.path.join(SITE_PACKAGES, 'pip-*.dist-info'))[0], + ): + shutil.move(src, TOX_PIP_DIR) + # Create a very simple launcher that + # can be used for Linux and Windows. + with open(os.path.join(TOX_PIP_DIR, 'pip.py'), 'w') as fp: + fp.write(textwrap.dedent( + ''' + import sys + from pip._vendor import pkg_resources + sys.exit(pkg_resources.load_entry_point( + 'pip', 'console_scripts', 'pip' + )()) + ''' + ).lstrip()) + # And use a temporary copy of that version + # so it can uninstall itself if needed. + temp_pip = TOX_PIP_DIR + '.tmp' + try: + shutil.copytree(TOX_PIP_DIR, temp_pip) + cmd = [sys.executable, os.path.join(temp_pip, 'pip.py')] + cmd.extend(args) + subprocess.check_call(cmd) + finally: + shutil.rmtree(temp_pip) + + +if __name__ == '__main__': + pip(sys.argv[1:]) diff --git a/MANIFEST.in b/MANIFEST.in index f3a38197890..ce825014773 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -19,6 +19,7 @@ recursive-include src/pip/_vendor *.pem recursive-include docs Makefile *.rst *.py *.bat prune .github +prune .tox_helpers prune .travis prune docs/_build prune news diff --git a/tox.ini b/tox.ini index df776e05e47..5908bd23e7e 100644 --- a/tox.ini +++ b/tox.ini @@ -3,6 +3,11 @@ envlist = docs, packaging, lint-py2, lint-py3, py27, py33, py34, py35, py36, py37, pypy +[helpers] +# Wrapper for calls to pip that make sure the version being used is the +# original virtualenv (stable) version, and not the code being tested. +pip = python {toxinidir}/.tox_helpers/runpip.py + [testenv] setenv = # This is required in order to get UTF-8 output inside of the subprocesses @@ -10,7 +15,8 @@ setenv = LC_CTYPE = en_US.UTF-8 deps = -r{toxinidir}/dev-requirements.txt commands = py.test --timeout 300 [] -install_command = python -m pip install {opts} {packages} +install_command = {[helpers]pip} install {opts} {packages} +list_dependencies_command = {[helpers]pip} freeze [testenv:docs] deps = sphinx == 1.6.1