tests: rework tests virtual environment

- cleanup virtualenv creation code
- ensure all testing virtual environments use a recent version
  of setuptools / wheel, making it easier to switch to custom
  versions of those, as well as reducing network accesses
- reduce size of testing virtual environment, slightly speeding
  up the testsuite
This commit is contained in:
Benoit Pierre 2018-10-08 18:09:53 +02:00
parent c30b10a7a0
commit add3801163
18 changed files with 326 additions and 422 deletions

1
.gitignore vendored
View File

@ -26,6 +26,7 @@ htmlcov/
nosetests.xml
coverage.xml
*.cover
tests/data/common_wheels/
# Misc
*~

View File

@ -1,3 +1,4 @@
import compileall
import io
import os
import shutil
@ -6,9 +7,10 @@ import sys
import pytest
import six
from setuptools.wheel import Wheel
import pip._internal
from tests.lib import SRC_DIR, TestData
from tests.lib import DATA_DIR, SRC_DIR, TestData
from tests.lib.path import Path
from tests.lib.scripttest import PipTestEnvironment
from tests.lib.venv import VirtualEnvironment
@ -163,62 +165,69 @@ def pip_src(tmpdir_factory):
return pip_src
def _common_wheel_editable_install(tmpdir_factory, common_wheels, package):
wheel_candidates = list(common_wheels.glob('%s-*.whl' % package))
assert len(wheel_candidates) == 1, wheel_candidates
install_dir = Path(str(tmpdir_factory.mktemp(package))) / 'install'
Wheel(wheel_candidates[0]).install_as_egg(install_dir)
(install_dir / 'EGG-INFO').rename(install_dir / '%s.egg-info' % package)
assert compileall.compile_dir(str(install_dir), quiet=1)
return install_dir
@pytest.fixture(scope='session')
def setuptools_install(tmpdir_factory, common_wheels):
return _common_wheel_editable_install(tmpdir_factory,
common_wheels,
'setuptools')
@pytest.fixture(scope='session')
def wheel_install(tmpdir_factory, common_wheels):
return _common_wheel_editable_install(tmpdir_factory,
common_wheels,
'wheel')
def install_egg_link(venv, project_name, egg_info_dir):
with open(venv.site / 'easy-install.pth', 'a') as fp:
fp.write(str(egg_info_dir.abspath) + '\n')
with open(venv.site / (project_name + '.egg-link'), 'w') as fp:
fp.write(str(egg_info_dir) + '\n.')
@pytest.yield_fixture(scope='session')
def virtualenv_template(tmpdir_factory, pip_src):
tmpdir = Path(str(tmpdir_factory.mktemp('virtualenv')))
def virtualenv_template(tmpdir_factory, pip_src,
setuptools_install, common_wheels):
# Create the virtual environment
venv = VirtualEnvironment.create(
tmpdir.join("venv_orig"),
pip_source_dir=pip_src,
relocatable=True,
)
# Fix `site.py`.
site_py = venv.lib / 'site.py'
with open(site_py) as fp:
site_contents = fp.read()
for pattern, replace in (
(
# Ensure `virtualenv.system_site_packages = True` (needed
# for testing `--user`) does not result in adding the real
# site-packages' directory to `sys.path`.
(
'\ndef virtual_addsitepackages(known_paths):\n'
),
(
'\ndef virtual_addsitepackages(known_paths):\n'
' return known_paths\n'
),
),
(
# Fix sites ordering: user site must be added before system site.
(
'\n paths_in_sys = addsitepackages(paths_in_sys)'
'\n paths_in_sys = addusersitepackages(paths_in_sys)\n'
),
(
'\n paths_in_sys = addusersitepackages(paths_in_sys)'
'\n paths_in_sys = addsitepackages(paths_in_sys)\n'
),
),
):
assert pattern in site_contents
site_contents = site_contents.replace(pattern, replace)
with open(site_py, 'w') as fp:
fp.write(site_contents)
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')
tmpdir = Path(str(tmpdir_factory.mktemp('virtualenv')))
venv = VirtualEnvironment(tmpdir.join("venv_orig"))
# Install setuptools and pip.
install_egg_link(venv, 'setuptools', setuptools_install)
pip_editable = Path(str(tmpdir_factory.mktemp('pip'))) / 'pip'
pip_src.copytree(pip_editable)
assert compileall.compile_dir(str(pip_editable), quiet=1)
subprocess.check_call([venv.bin / 'python', 'setup.py', '-q', 'develop'],
cwd=pip_editable)
# Drop (non-relocatable) launchers.
for exe in os.listdir(venv.bin):
if not (
exe.startswith('python') or
exe.startswith('libpy') # Don't remove libpypy-c.so...
):
(venv.bin / exe).remove()
# Enable user site packages.
venv.user_site_packages = True
# Rename original virtualenv directory to make sure
# it's not reused by mistake from one of the copies.
venv_template = tmpdir / "venv_template"
os.rename(venv.location, venv_template)
yield venv_template
venv.move(venv_template)
yield venv
tmpdir.rmtree(noerrors=True)
@ -231,12 +240,15 @@ def virtualenv(virtualenv_template, tmpdir, isolate):
``tests.lib.venv.VirtualEnvironment`` object.
"""
venv_location = tmpdir.join("workspace", "venv")
shutil.copytree(virtualenv_template, venv_location, symlinks=True)
venv = VirtualEnvironment(venv_location)
yield venv
yield VirtualEnvironment(venv_location, virtualenv_template)
venv_location.rmtree(noerrors=True)
@pytest.fixture
def with_wheel(virtualenv, wheel_install):
install_egg_link(virtualenv, 'wheel', wheel_install)
@pytest.fixture
def script(tmpdir, virtualenv):
"""
@ -250,7 +262,7 @@ def script(tmpdir, virtualenv):
tmpdir.join("workspace"),
# Tell the Test Environment where our virtualenv is located
virtualenv=virtualenv.location,
virtualenv=virtualenv,
# Do not ignore hidden files, they need to be checked as well
ignore_hidden=False,
@ -266,15 +278,9 @@ def script(tmpdir, virtualenv):
@pytest.fixture(scope="session")
def common_wheels(tmpdir_factory):
def common_wheels():
"""Provide a directory with latest setuptools and wheel wheels"""
wheels_dir = tmpdir_factory.mktemp('common_wheels')
subprocess.check_call([
'pip', 'download', 'wheel', 'setuptools',
'-d', str(wheels_dir),
])
yield wheels_dir
wheels_dir.remove(ignore_errors=True)
return DATA_DIR.join('common_wheels')
@pytest.fixture

View File

@ -3,48 +3,16 @@ import sys
import pytest
def test_completion_for_bash(script):
"""
Test getting completion for bash shell
"""
bash_completion = """\
COMPLETION_FOR_SUPPORTED_SHELLS_TESTS = (
('bash', """\
_pip_completion()
{
COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\
COMP_CWORD=$COMP_CWORD \\
PIP_AUTO_COMPLETE=1 $1 ) )
}
complete -o default -F _pip_completion pip"""
result = script.pip('completion', '--bash')
assert bash_completion in result.stdout, 'bash completion is wrong'
def test_completion_for_zsh(script):
"""
Test getting completion for zsh shell
"""
zsh_completion = """\
function _pip_completion {
local words cword
read -Ac words
read -cn cword
reply=( $( COMP_WORDS="$words[*]" \\
COMP_CWORD=$(( cword-1 )) \\
PIP_AUTO_COMPLETE=1 $words[1] ) )
}
compctl -K _pip_completion pip"""
result = script.pip('completion', '--zsh')
assert zsh_completion in result.stdout, 'zsh completion is wrong'
def test_completion_for_fish(script):
"""
Test getting completion for fish shell
"""
fish_completion = """\
complete -o default -F _pip_completion pip"""),
('fish', """\
function __fish_complete_pip
set -lx COMP_WORDS (commandline -o) ""
set -lx COMP_CWORD ( \\
@ -53,10 +21,34 @@ function __fish_complete_pip
set -lx PIP_AUTO_COMPLETE 1
string split \\ -- (eval $COMP_WORDS[1])
end
complete -fa "(__fish_complete_pip)" -c pip"""
complete -fa "(__fish_complete_pip)" -c pip"""),
('zsh', """\
function _pip_completion {
local words cword
read -Ac words
read -cn cword
reply=( $( COMP_WORDS="$words[*]" \\
COMP_CWORD=$(( cword-1 )) \\
PIP_AUTO_COMPLETE=1 $words[1] ) )
}
compctl -K _pip_completion pip"""),
)
result = script.pip('completion', '--fish')
assert fish_completion in result.stdout, 'fish completion is wrong'
@pytest.mark.parametrize(
'shell, completion',
COMPLETION_FOR_SUPPORTED_SHELLS_TESTS,
ids=[t[0] for t in COMPLETION_FOR_SUPPORTED_SHELLS_TESTS],
)
def test_completion_for_supported_shells(script, pip_src, shell, completion):
"""
Test getting completion for bash shell
"""
# Re-install pip so we get the launchers.
script.pip_install_local('--no-build-isolation', pip_src)
result = script.pip('completion', '--' + shell, use_module=False)
assert completion in result.stdout, str(result.stdout)
def test_completion_for_unknown_shell(script):

View File

@ -576,7 +576,6 @@ def test_freeze_user(script, virtualenv, data):
Testing freeze with --user, first we have to install some stuff.
"""
script.pip('download', 'setuptools', 'wheel', '-d', data.packages)
virtualenv.system_site_packages = True
script.pip_install_local('--find-links', data.find_links,
'--user', 'simple==2.0')
script.pip_install_local('--find-links', data.find_links,

View File

@ -26,15 +26,14 @@ def test_pep518_uses_build_env(script, data, common_wheels, command, variant):
if variant == 'missing_setuptools':
script.pip("uninstall", "-y", "setuptools")
elif variant == 'bad_setuptools':
setuptools_init_path = script.site_packages_path.join(
"setuptools", "__init__.py")
with open(setuptools_init_path, 'a') as f:
setuptools_mod = script.site_packages_path.join("setuptools.py")
with open(setuptools_mod, 'a') as f:
f.write('\nraise ImportError("toto")')
else:
raise ValueError(variant)
script.pip(
command, '--no-index', '-f', common_wheels, '-f', data.packages,
data.src.join("pep518-3.0"), use_module=True
data.src.join("pep518-3.0"),
)
@ -74,11 +73,8 @@ def test_pep518_allows_missing_requires(script, data, common_wheels):
assert result.files_created
def test_pep518_with_user_pip(script, virtualenv, pip_src,
data, common_wheels):
virtualenv.system_site_packages = True
script.pip("install", "--ignore-installed", "--user", pip_src,
use_module=True)
def test_pep518_with_user_pip(script, pip_src, data, common_wheels):
script.pip("install", "--ignore-installed", "--user", pip_src)
system_pip_dir = script.site_packages_path / 'pip'
system_pip_dir.rmtree()
system_pip_dir.mkdir()
@ -86,7 +82,7 @@ def test_pep518_with_user_pip(script, virtualenv, pip_src,
fp.write('raise ImportError\n')
script.pip(
'wheel', '--no-index', '-f', common_wheels, '-f', data.packages,
data.src.join("pep518-3.0"), use_module=True,
data.src.join("pep518-3.0"),
)
@ -96,7 +92,6 @@ def test_pep518_with_extra_and_markers(script, data, common_wheels):
'-f', common_wheels,
'-f', data.find_links,
data.src.join("pep518_with_extra_and_markers-1.0"),
use_module=True,
)
@ -130,10 +125,12 @@ def test_pep518_forkbombs(script, data, common_wheels, command, package):
@pytest.mark.network
def test_pip_second_command_line_interface_works(script, data):
def test_pip_second_command_line_interface_works(script, data, pip_src):
"""
Check if ``pip<PYVERSION>`` commands behaves equally
"""
# Re-install pip so we get the launchers.
script.pip_install_local('--no-build-isolation', pip_src)
# On old versions of Python, urllib3/requests will raise a warning about
# the lack of an SSLContext.
kwargs = {}
@ -226,10 +223,8 @@ def test_basic_install_editable_from_git(script, tmpdir):
_test_install_editable_from_git(script, tmpdir)
@pytest.mark.network
def test_install_editable_from_git_autobuild_wheel(
script, tmpdir, common_wheels):
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
script, tmpdir, with_wheel):
_test_install_editable_from_git(script, tmpdir)
@ -742,14 +737,11 @@ def test_install_nonlocal_compatible_wheel_path(script, data):
assert result.returncode == ERROR
def test_install_with_target_and_scripts_no_warning(script, common_wheels):
def test_install_with_target_and_scripts_no_warning(script, with_wheel):
"""
Test that installing with --target does not trigger the "script not
in PATH" warning (issue #5201)
"""
# We need to have wheel installed so that the project builds via a wheel,
# which is the only execution path that has the script warning.
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
target_dir = script.scratch_path / 'target'
pkga_path = script.scratch_path / 'pkga'
pkga_path.mkdir()
@ -1093,23 +1085,13 @@ def test_install_topological_sort(script, data):
assert order1 in res or order2 in res, res
@pytest.mark.network
def test_install_wheel_broken(script, data, common_wheels):
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
res = script.pip(
'install', '--no-index', '-f', data.find_links, '-f', common_wheels,
'wheelbroken',
expect_stderr=True)
def test_install_wheel_broken(script, with_wheel):
res = script.pip_install_local('wheelbroken', expect_stderr=True)
assert "Successfully installed wheelbroken-0.1" in str(res), str(res)
@pytest.mark.network
def test_cleanup_after_failed_wheel(script, data, common_wheels):
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
res = script.pip(
'install', '--no-index', '-f', data.find_links, '-f', common_wheels,
'wheelbrokenafter',
expect_stderr=True)
def test_cleanup_after_failed_wheel(script, with_wheel):
res = script.pip_install_local('wheelbrokenafter', expect_stderr=True)
# One of the effects of not cleaning up is broken scripts:
script_py = script.bin_path / "script.py"
assert script_py.exists, script_py
@ -1119,8 +1101,7 @@ def test_cleanup_after_failed_wheel(script, data, common_wheels):
assert "Running setup.py clean for wheelbrokenafter" in str(res), str(res)
@pytest.mark.network
def test_install_builds_wheels(script, data, common_wheels):
def test_install_builds_wheels(script, data, with_wheel):
# We need to use a subprocess to get the right value on Windows.
res = script.run('python', '-c', (
'from pip._internal.utils import appdirs; '
@ -1130,10 +1111,9 @@ def test_install_builds_wheels(script, data, common_wheels):
# NB This incidentally tests a local tree + tarball inputs
# see test_install_editable_from_git_autobuild_wheel for editable
# vcs coverage.
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
to_install = data.packages.join('requires_wheelbroken_upper')
res = script.pip(
'install', '--no-index', '-f', data.find_links, '-f', common_wheels,
'install', '--no-index', '-f', data.find_links,
to_install, expect_stderr=True)
expected = ("Successfully installed requires-wheelbroken-upper-0"
" upper-2.0 wheelbroken-0.1")
@ -1162,14 +1142,10 @@ def test_install_builds_wheels(script, data, common_wheels):
]
@pytest.mark.network
def test_install_no_binary_disables_building_wheels(
script, data, common_wheels):
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
def test_install_no_binary_disables_building_wheels(script, data, with_wheel):
to_install = data.packages.join('requires_wheelbroken_upper')
res = script.pip(
'install', '--no-index', '--no-binary=upper', '-f', data.find_links,
'-f', common_wheels,
to_install, expect_stderr=True)
expected = ("Successfully installed requires-wheelbroken-upper-0"
" upper-2.0 wheelbroken-0.1")
@ -1188,12 +1164,10 @@ def test_install_no_binary_disables_building_wheels(
assert "Running setup.py install for upper" in str(res), str(res)
@pytest.mark.network
def test_install_no_binary_disables_cached_wheels(script, data, common_wheels):
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
def test_install_no_binary_disables_cached_wheels(script, data, with_wheel):
# Seed the cache
script.pip(
'install', '--no-index', '-f', data.find_links, '-f', common_wheels,
'install', '--no-index', '-f', data.find_links,
'upper')
script.pip('uninstall', 'upper', '-y')
res = script.pip(
@ -1246,7 +1220,6 @@ def test_double_install(script):
Test double install passing with two same version requirements
"""
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
@ -1262,7 +1235,7 @@ def test_double_install_fail(script):
assert msg in result.stderr
def test_install_incompatible_python_requires(script, common_wheels):
def test_install_incompatible_python_requires(script):
script.scratch_path.join("pkga").mkdir()
pkga_path = script.scratch_path / 'pkga'
pkga_path.join("setup.py").write(textwrap.dedent("""
@ -1271,16 +1244,12 @@ def test_install_incompatible_python_requires(script, common_wheels):
python_requires='<1.0',
version='0.1')
"""))
script.pip(
'install', 'setuptools>24.2', # This should not be needed
'--no-index', '-f', 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, str(result)
def test_install_incompatible_python_requires_editable(script, common_wheels):
def test_install_incompatible_python_requires_editable(script):
script.scratch_path.join("pkga").mkdir()
pkga_path = script.scratch_path / 'pkga'
pkga_path.join("setup.py").write(textwrap.dedent("""
@ -1289,18 +1258,13 @@ def test_install_incompatible_python_requires_editable(script, common_wheels):
python_requires='<1.0',
version='0.1')
"""))
script.pip(
'install', 'setuptools>24.2', # This should not be needed
'--no-index', '-f', 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, str(result)
@pytest.mark.network
def test_install_incompatible_python_requires_wheel(script, common_wheels):
def test_install_incompatible_python_requires_wheel(script, with_wheel):
script.scratch_path.join("pkga").mkdir()
pkga_path = script.scratch_path / 'pkga'
pkga_path.join("setup.py").write(textwrap.dedent("""
@ -1309,11 +1273,6 @@ def test_install_incompatible_python_requires_wheel(script, common_wheels):
python_requires='<1.0',
version='0.1')
"""))
script.pip(
'install', 'setuptools>24.2', # This should not be needed
'--no-index', '-f', common_wheels,
)
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
script.run(
'python', 'setup.py', 'bdist_wheel', '--universal', cwd=pkga_path)
result = script.pip('install', './pkga/dist/pkga-0.1-py2.py3-none-any.whl',
@ -1322,7 +1281,7 @@ def test_install_incompatible_python_requires_wheel(script, common_wheels):
"but the running Python is ") in result.stderr
def test_install_compatible_python_requires(script, common_wheels):
def test_install_compatible_python_requires(script):
script.scratch_path.join("pkga").mkdir()
pkga_path = script.scratch_path / 'pkga'
pkga_path.join("setup.py").write(textwrap.dedent("""
@ -1331,10 +1290,6 @@ def test_install_compatible_python_requires(script, common_wheels):
python_requires='>1.0',
version='0.1')
"""))
script.pip(
'install', 'setuptools>24.2', # This should not be needed
'--no-index', '-f', common_wheels,
)
res = script.pip('install', pkga_path, expect_error=True)
assert "Successfully installed pkga-0.1" in res.stdout, res

View File

@ -199,10 +199,8 @@ def test_options_from_venv_config(script, virtualenv):
)
@pytest.mark.network
def test_install_no_binary_via_config_disables_cached_wheels(
script, data, common_wheels):
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
script, data, with_wheel):
config_file = tempfile.NamedTemporaryFile(mode='wt', delete=False)
try:
script.environ['PIP_CONFIG_FILE'] = config_file.name

View File

@ -223,12 +223,8 @@ def test_install_local_with_subdirectory(script):
result.assert_installed('version_subpkg.py', editable=False)
@pytest.mark.network
def test_wheel_user_with_prefix_in_pydistutils_cfg(
script, data, virtualenv, common_wheels):
# Make sure wheel is available in the virtualenv
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
virtualenv.system_site_packages = True
script, data, with_wheel):
if os.name == 'posix':
user_filename = ".pydistutils.cfg"
else:
@ -242,7 +238,7 @@ def test_wheel_user_with_prefix_in_pydistutils_cfg(
result = script.pip(
'install', '--user', '--no-index',
'-f', data.find_links, '-f', common_wheels,
'-f', data.find_links,
'requiresupper')
# Check that we are really installing a wheel
assert 'Running setup.py install for requiresupper' not in result.stdout
@ -353,9 +349,8 @@ def test_constrained_to_url_install_same_url(script, data):
in result.stdout), str(result)
@pytest.mark.network
def test_double_install_spurious_hash_mismatch(
script, tmpdir, data, common_wheels):
script, tmpdir, data, with_wheel):
"""Make sure installing the same hashed sdist twice doesn't throw hash
mismatch errors.
@ -366,13 +361,12 @@ def test_double_install_spurious_hash_mismatch(
"""
# Install wheel package, otherwise, it won't try to build wheels.
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
with requirements_file('simple==1.0 --hash=sha256:393043e672415891885c9a2a'
'0929b1af95fb866d6ca016b42d2e6ce53619b653',
tmpdir) as reqs_file:
# Install a package (and build its wheel):
result = script.pip_install_local(
'--find-links', data.find_links, '-f', common_wheels,
'--find-links', data.find_links,
'-r', reqs_file.abspath, expect_error=False)
assert 'Successfully installed simple-1.0' in str(result)
@ -382,7 +376,7 @@ def test_double_install_spurious_hash_mismatch(
# Then install it again. We should not hit a hash mismatch, and the
# package should install happily.
result = script.pip_install_local(
'--find-links', data.find_links, '-f', common_wheels,
'--find-links', data.find_links,
'-r', reqs_file.abspath, expect_error=False)
assert 'Successfully installed simple-1.0' in str(result)

View File

@ -1,46 +1,36 @@
"""
tests specific to "pip install --user"
"""
import os
import textwrap
from os.path import curdir, isdir, isfile
import pytest
from pip._internal.utils.compat import cache_from_source, uses_pycache
from tests.lib import pyversion
from tests.lib.local_repos import local_checkout
def _patch_dist_in_site_packages(script):
sitecustomize_path = script.lib_path.join("sitecustomize.py")
sitecustomize_path.write(textwrap.dedent("""
def _patch_dist_in_site_packages(virtualenv):
# Since the tests are run from a virtualenv, and to avoid the "Will not
# install to the usersite because it will lack sys.path precedence..."
# error: Monkey patch `pip._internal.req.req_install.dist_in_site_packages`
# so it's possible to install a conflicting distribution in the user site.
virtualenv.sitecustomize = textwrap.dedent("""
def dist_in_site_packages(dist):
return False
from pip._internal.req import req_install
req_install.dist_in_site_packages = dist_in_site_packages
"""))
# Caught py32 with an outdated __pycache__ file after a sitecustomize
# update (after python should have updated it) so will delete the cache
# file to be sure
# See: https://github.com/pypa/pip/pull/893#issuecomment-16426701
if uses_pycache:
cache_path = cache_from_source(sitecustomize_path)
if os.path.isfile(cache_path):
os.remove(cache_path)
""")
class Tests_UserSite:
@pytest.mark.network
def test_reset_env_system_site_packages_usersite(self, script, virtualenv):
def test_reset_env_system_site_packages_usersite(self, script):
"""
reset_env(system_site_packages=True) produces env where a --user
install can be found using pkg_resources
Check user site works as expected.
"""
virtualenv.system_site_packages = True
script.pip('install', '--user', 'INITools==0.2')
result = script.run(
'python', '-c',
@ -52,12 +42,11 @@ class Tests_UserSite:
@pytest.mark.network
def test_install_subversion_usersite_editable_with_distribute(
self, script, virtualenv, tmpdir):
self, script, tmpdir):
"""
Test installing current directory ('.') into usersite after installing
distribute
"""
virtualenv.system_site_packages = True
result = script.pip(
'install', '--user', '-e',
'%s#egg=initools' %
@ -68,15 +57,11 @@ class Tests_UserSite:
)
result.assert_installed('INITools', use_user_site=True)
@pytest.mark.network
def test_install_from_current_directory_into_usersite(
self, script, virtualenv, data, common_wheels):
self, script, data, with_wheel):
"""
Test installing current directory ('.') into usersite
"""
virtualenv.system_site_packages = True
script.pip("install", "wheel", '--no-index', '-f', common_wheels)
run_from = data.packages.join("FSPkg")
result = script.pip(
'install', '-vvv', '--user', curdir,
@ -92,10 +77,14 @@ class Tests_UserSite:
)
assert dist_info_folder in result.files_created
def test_install_user_venv_nositepkgs_fails(self, script, data):
def test_install_user_venv_nositepkgs_fails(self, virtualenv,
script, data):
"""
user install in virtualenv (with no system packages) fails with message
"""
# We can't use PYTHONNOUSERSITE, as it's not
# honoured by virtualenv's custom site.py.
virtualenv.user_site_packages = False
run_from = data.packages.join("FSPkg")
result = script.pip(
'install', '--user', curdir,
@ -108,11 +97,10 @@ class Tests_UserSite:
)
@pytest.mark.network
def test_install_user_conflict_in_usersite(self, script, virtualenv):
def test_install_user_conflict_in_usersite(self, script):
"""
Test user install with conflict in usersite updates usersite.
"""
virtualenv.system_site_packages = True
script.pip('install', '--user', 'INITools==0.3', '--no-binary=:all:')
@ -132,26 +120,12 @@ class Tests_UserSite:
assert not isfile(initools_v3_file), initools_v3_file
@pytest.mark.network
def test_install_user_conflict_in_globalsite(self, script, virtualenv):
def test_install_user_conflict_in_globalsite(self, virtualenv, script):
"""
Test user install with conflict in global site ignores site and
installs to usersite
"""
# the test framework only supports testing using virtualenvs
# the sys.path ordering for virtualenvs with --system-site-packages is
# this: virtualenv-site, user-site, global-site
# this test will use 2 modifications to simulate the
# user-site/global-site relationship
# 1) a monkey patch which will make it appear INITools==0.2 is not in
# the virtualenv site if we don't patch this, pip will return an
# installation error: "Will not install to the usersite because it
# will lack sys.path precedence..."
# 2) adding usersite to PYTHONPATH, so usersite as sys.path precedence
# over the virtualenv site
virtualenv.system_site_packages = True
script.environ["PYTHONPATH"] = script.base_path / script.user_site
_patch_dist_in_site_packages(script)
_patch_dist_in_site_packages(virtualenv)
script.pip('install', 'INITools==0.2', '--no-binary=:all:')
@ -176,26 +150,12 @@ class Tests_UserSite:
assert isdir(initools_folder)
@pytest.mark.network
def test_upgrade_user_conflict_in_globalsite(self, script, virtualenv):
def test_upgrade_user_conflict_in_globalsite(self, virtualenv, script):
"""
Test user install/upgrade with conflict in global site ignores site and
installs to usersite
"""
# the test framework only supports testing using virtualenvs
# the sys.path ordering for virtualenvs with --system-site-packages is
# this: virtualenv-site, user-site, global-site
# this test will use 2 modifications to simulate the
# user-site/global-site relationship
# 1) a monkey patch which will make it appear INITools==0.2 is not in
# the virtualenv site if we don't patch this, pip will return an
# installation error: "Will not install to the usersite because it
# will lack sys.path precedence..."
# 2) adding usersite to PYTHONPATH, so usersite as sys.path precedence
# over the virtualenv site
virtualenv.system_site_packages = True
script.environ["PYTHONPATH"] = script.base_path / script.user_site
_patch_dist_in_site_packages(script)
_patch_dist_in_site_packages(virtualenv)
script.pip('install', 'INITools==0.2', '--no-binary=:all:')
result2 = script.pip(
@ -220,26 +180,12 @@ class Tests_UserSite:
@pytest.mark.network
def test_install_user_conflict_in_globalsite_and_usersite(
self, script, virtualenv):
self, virtualenv, script):
"""
Test user install with conflict in globalsite and usersite ignores
global site and updates usersite.
"""
# the test framework only supports testing using virtualenvs.
# the sys.path ordering for virtualenvs with --system-site-packages is
# this: virtualenv-site, user-site, global-site.
# this test will use 2 modifications to simulate the
# user-site/global-site relationship
# 1) a monkey patch which will make it appear INITools==0.2 is not in
# the virtualenv site if we don't patch this, pip will return an
# installation error: "Will not install to the usersite because it
# will lack sys.path precedence..."
# 2) adding usersite to PYTHONPATH, so usersite as sys.path precedence
# over the virtualenv site
virtualenv.system_site_packages = True
script.environ["PYTHONPATH"] = script.base_path / script.user_site
_patch_dist_in_site_packages(script)
_patch_dist_in_site_packages(virtualenv)
script.pip('install', 'INITools==0.2', '--no-binary=:all:')
script.pip('install', '--user', 'INITools==0.3', '--no-binary=:all:')
@ -270,12 +216,11 @@ class Tests_UserSite:
@pytest.mark.network
def test_install_user_in_global_virtualenv_with_conflict_fails(
self, script, virtualenv):
self, script):
"""
Test user install in --system-site-packages virtualenv with conflict in
site fails.
"""
virtualenv.system_site_packages = True
script.pip('install', 'INITools==0.2')

View File

@ -114,12 +114,10 @@ def test_install_from_wheel_with_headers(script, data):
result.stdout)
@pytest.mark.network
def test_install_wheel_with_target(script, data, common_wheels):
def test_install_wheel_with_target(script, data, with_wheel):
"""
Test installing a wheel using pip install --target
"""
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
target_dir = script.scratch_path / 'target'
result = script.pip(
'install', 'simple.dist==0.1', '-t', target_dir,
@ -130,8 +128,7 @@ def test_install_wheel_with_target(script, data, common_wheels):
)
@pytest.mark.network
def test_install_wheel_with_target_and_data_files(script, data, common_wheels):
def test_install_wheel_with_target_and_data_files(script, data, with_wheel):
"""
Test for issue #4092. It will be checked that a data_files specification in
setup.py is handled correctly when a wheel is installed with the --target
@ -150,7 +147,6 @@ def test_install_wheel_with_target_and_data_files(script, data, common_wheels):
]
)
"""
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
target_dir = script.scratch_path / 'prjwithdatafile'
package = data.packages.join("prjwithdatafile-1.0-py2.py3-none-any.whl")
result = script.pip('install', package,
@ -234,13 +230,10 @@ def test_wheel_record_lines_in_deterministic_order(script, data):
assert record_lines == sorted(record_lines)
@pytest.mark.network
def test_install_user_wheel(script, virtualenv, data, common_wheels):
def test_install_user_wheel(script, data, with_wheel):
"""
Test user install from wheel (that has a script)
"""
virtualenv.system_site_packages = True
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
result = script.pip(
'install', 'has.script==1.0', '--user', '--no-index',
'--find-links=' + data.find_links,

View File

@ -99,12 +99,11 @@ def test_local_columns_flag(script, data):
@pytest.mark.network
def test_user_flag(script, data, virtualenv):
def test_user_flag(script, data):
"""
Test the behavior of --user flag in the list command
"""
virtualenv.system_site_packages = True
script.pip('download', 'setuptools', 'wheel', '-d', data.packages)
script.pip('install', '-f', data.find_links, '--no-index', 'simple==1.0')
script.pip('install', '-f', data.find_links, '--no-index',
@ -116,12 +115,11 @@ def test_user_flag(script, data, virtualenv):
@pytest.mark.network
def test_user_columns_flag(script, data, virtualenv):
def test_user_columns_flag(script, data):
"""
Test the behavior of --user --format=columns flags in the list command
"""
virtualenv.system_site_packages = True
script.pip('download', 'setuptools', 'wheel', '-d', data.packages)
script.pip('install', '-f', data.find_links, '--no-index', 'simple==1.0')
script.pip('install', '-f', data.find_links, '--no-index',

View File

@ -67,7 +67,7 @@ def test_basic_uninstall_with_scripts(script):
Uninstall an easy_installed package with scripts.
"""
result = script.run('easy_install', 'PyLogo', expect_stderr=True)
result = script.easy_install('PyLogo', expect_stderr=True)
easy_install_pth = script.site_packages / 'easy-install.pth'
pylogo = sys.platform == 'win32' and 'pylogo' or 'PyLogo'
assert(pylogo in result.files_updated[easy_install_pth].bytes)
@ -85,7 +85,8 @@ def test_uninstall_easy_install_after_import(script):
Uninstall an easy_installed package after it's been imported
"""
result = script.run('easy_install', 'INITools==0.2', expect_stderr=True)
result = script.easy_install('--always-unzip', 'INITools==0.2',
expect_stderr=True)
# the import forces the generation of __pycache__ if the version of python
# supports it
script.run('python', '-c', "import initools")
@ -108,8 +109,8 @@ def test_uninstall_trailing_newline(script):
lacks a trailing newline
"""
script.run('easy_install', 'INITools==0.2', expect_stderr=True)
script.run('easy_install', 'PyLogo', expect_stderr=True)
script.easy_install('INITools==0.2', expect_stderr=True)
script.easy_install('PyLogo', expect_stderr=True)
easy_install_pth = script.site_packages_path / 'easy-install.pth'
# trim trailing newline from easy-install.pth
@ -269,9 +270,7 @@ def test_uninstall_easy_installed_console_scripts(script):
"""
Test uninstalling package with console_scripts that is easy_installed.
"""
args = ['easy_install']
args.append('discover')
result = script.run(*args, **{"expect_stderr": True})
result = script.easy_install('discover', expect_error=True)
assert script.bin / 'discover' + script.exe in result.files_created, (
sorted(result.files_created.keys())
)

View File

@ -12,35 +12,20 @@ from tests.lib import assert_all_changes, pyversion
class Tests_UninstallUserSite:
@pytest.mark.network
def test_uninstall_from_usersite(self, script, virtualenv):
def test_uninstall_from_usersite(self, script):
"""
Test uninstall from usersite
"""
virtualenv.system_site_packages = True
result1 = script.pip('install', '--user', 'INITools==0.3')
result2 = script.pip('uninstall', '-y', 'INITools')
assert_all_changes(result1, result2, [script.venv / 'build', 'cache'])
def test_uninstall_from_usersite_with_dist_in_global_site(
self, script, virtualenv):
self, virtualenv, script):
"""
Test uninstall from usersite (with same dist in global site)
"""
# the test framework only supports testing using virtualenvs.
# the sys.path ordering for virtualenvs with --system-site-packages is
# this: virtualenv-site, user-site, global-site.
# this test will use 2 modifications to simulate the
# user-site/global-site relationship
# 1) a monkey patch which will make it appear piptestpackage is not in
# the virtualenv site if we don't patch this, pip will return an
# installation error: "Will not install to the usersite because it
# will lack sys.path precedence..."
# 2) adding usersite to PYTHONPATH, so usersite has sys.path precedence
# over the virtualenv site
virtualenv.system_site_packages = True
script.environ["PYTHONPATH"] = script.base_path / script.user_site
_patch_dist_in_site_packages(script)
_patch_dist_in_site_packages(virtualenv)
script.pip_install_local('pip-test-package==0.1', '--no-binary=:all:')
@ -62,11 +47,10 @@ class Tests_UninstallUserSite:
)
assert isdir(egg_info_folder)
def test_uninstall_editable_from_usersite(self, script, virtualenv, data):
def test_uninstall_editable_from_usersite(self, script, data):
"""
Test uninstall editable local user install
"""
virtualenv.system_site_packages = True
script.user_site_path.makedirs()
# install

View File

@ -9,34 +9,34 @@ from pip._internal.locations import write_delete_marker_file
from tests.lib import pyversion
def test_wheel_exit_status_code_when_no_requirements(script, common_wheels):
@pytest.fixture(autouse=True)
def auto_with_wheel(with_wheel):
pass
def test_wheel_exit_status_code_when_no_requirements(script):
"""
Test wheel exit status code when no requirements specified
"""
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
result = script.pip('wheel', expect_error=True)
assert "You must give at least one requirement to wheel" in result.stderr
assert result.returncode == ERROR
def test_wheel_exit_status_code_when_blank_requirements_file(
script, common_wheels):
def test_wheel_exit_status_code_when_blank_requirements_file(script):
"""
Test wheel exit status code when blank requirements file specified
"""
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
script.scratch_path.join("blank.txt").write("\n")
script.pip('wheel', '-r', 'blank.txt')
@pytest.mark.network
def test_pip_wheel_success(script, data, common_wheels):
def test_pip_wheel_success(script, data):
"""
Test 'pip wheel' success.
"""
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
result = script.pip(
'wheel', '--no-index', '-f', data.find_links, '-f', common_wheels,
'wheel', '--no-index', '-f', data.find_links,
'simple==3.0',
)
wheel_file_name = 'simple-3.0-py%s-none-any.whl' % pyversion[0]
@ -45,12 +45,10 @@ def test_pip_wheel_success(script, data, common_wheels):
assert "Successfully built simple" in result.stdout, result.stdout
@pytest.mark.network
def test_basic_pip_wheel_downloads_wheels(script, data, common_wheels):
def test_basic_pip_wheel_downloads_wheels(script, data):
"""
Test 'pip wheel' downloads wheels
"""
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
result = script.pip(
'wheel', '--no-index', '-f', data.find_links, 'simple.dist',
)
@ -60,27 +58,23 @@ def test_basic_pip_wheel_downloads_wheels(script, data, common_wheels):
assert "Saved" in result.stdout, result.stdout
@pytest.mark.network
def test_pip_wheel_builds_when_no_binary_set(script, data, common_wheels):
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
def test_pip_wheel_builds_when_no_binary_set(script, data):
data.packages.join('simple-3.0-py2.py3-none-any.whl').touch()
# Check that the wheel package is ignored
res = script.pip(
'wheel', '--no-index', '--no-binary', ':all:',
'-f', data.find_links, '-f', common_wheels,
'-f', data.find_links,
'simple==3.0')
assert "Running setup.py bdist_wheel for simple" in str(res), str(res)
@pytest.mark.network
def test_pip_wheel_builds_editable_deps(script, data, common_wheels):
def test_pip_wheel_builds_editable_deps(script, data):
"""
Test 'pip wheel' finds and builds dependencies of editables
"""
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
editable_path = os.path.join(data.src, 'requires_simple')
result = script.pip(
'wheel', '--no-index', '-f', data.find_links, '-f', common_wheels,
'wheel', '--no-index', '-f', data.find_links,
'-e', editable_path
)
wheel_file_name = 'simple-1.0-py%s-none-any.whl' % pyversion[0]
@ -88,15 +82,13 @@ def test_pip_wheel_builds_editable_deps(script, data, common_wheels):
assert wheel_file_path in result.files_created, result.stdout
@pytest.mark.network
def test_pip_wheel_builds_editable(script, data, common_wheels):
def test_pip_wheel_builds_editable(script, data):
"""
Test 'pip wheel' builds an editable package
"""
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
editable_path = os.path.join(data.src, 'simplewheel-1.0')
result = script.pip(
'wheel', '--no-index', '-f', data.find_links, '-f', common_wheels,
'wheel', '--no-index', '-f', data.find_links,
'-e', editable_path
)
wheel_file_name = 'simplewheel-1.0-py%s-none-any.whl' % pyversion[0]
@ -104,14 +96,12 @@ def test_pip_wheel_builds_editable(script, data, common_wheels):
assert wheel_file_path in result.files_created, result.stdout
@pytest.mark.network
def test_pip_wheel_fail(script, data, common_wheels):
def test_pip_wheel_fail(script, data):
"""
Test 'pip wheel' failure.
"""
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
result = script.pip(
'wheel', '--no-index', '-f', data.find_links, '-f', common_wheels,
'wheel', '--no-index', '-f', data.find_links,
'wheelbroken==0.1',
expect_error=True,
)
@ -126,17 +116,14 @@ def test_pip_wheel_fail(script, data, common_wheels):
assert result.returncode != 0
@pytest.mark.network
def test_no_clean_option_blocks_cleaning_after_wheel(
script, data, common_wheels):
def test_no_clean_option_blocks_cleaning_after_wheel(script, data):
"""
Test --no-clean option blocks cleaning after wheel build
"""
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
build = script.venv_path / 'build'
result = script.pip(
'wheel', '--no-clean', '--no-index', '--build', build,
'--find-links=%s' % data.find_links, '-f', common_wheels,
'--find-links=%s' % data.find_links,
'simple',
expect_temp=True,
)
@ -144,16 +131,14 @@ def test_no_clean_option_blocks_cleaning_after_wheel(
assert exists(build), "build/simple should still exist %s" % str(result)
@pytest.mark.network
def test_pip_wheel_source_deps(script, data, common_wheels):
def test_pip_wheel_source_deps(script, data):
"""
Test 'pip wheel' finds and builds source archive dependencies
of wheels
"""
# 'requires_source' is a wheel that depends on the 'source' project
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
result = script.pip(
'wheel', '--no-index', '-f', data.find_links, '-f', common_wheels,
'wheel', '--no-index', '-f', data.find_links,
'requires_source',
)
wheel_file_name = 'source-1.0-py%s-none-any.whl' % pyversion[0]
@ -162,16 +147,12 @@ def test_pip_wheel_source_deps(script, data, common_wheels):
assert "Successfully built source" in result.stdout, result.stdout
@pytest.mark.network
def test_pip_wheel_fail_cause_of_previous_build_dir(
script, data, common_wheels):
def test_pip_wheel_fail_cause_of_previous_build_dir(script, data):
"""
Test when 'pip wheel' tries to install a package that has a previous build
directory
"""
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
# Given that I have a previous build dir of the `simple` package
build = script.venv_path / 'build' / 'simple'
os.makedirs(build)
@ -189,19 +170,15 @@ def test_pip_wheel_fail_cause_of_previous_build_dir(
assert result.returncode == PREVIOUS_BUILD_DIR_ERROR, result
@pytest.mark.network
def test_wheel_package_with_latin1_setup(script, data, common_wheels):
def test_wheel_package_with_latin1_setup(script, data):
"""Create a wheel from a package with latin-1 encoded setup.py."""
script.pip('install', 'wheel', '--no-index', '-f', common_wheels)
pkg_to_wheel = data.packages.join("SetupPyLatin1")
result = script.pip('wheel', pkg_to_wheel)
assert 'Successfully built SetupPyUTF8' in result.stdout
@pytest.mark.network
def test_pip_wheel_with_pep518_build_reqs(script, data, common_wheels):
script.pip_install_local('-f', common_wheels, 'wheel')
result = script.pip('wheel', '--no-index', '-f', data.find_links,
'-f', common_wheels, 'pep518==3.0',)
wheel_file_name = 'pep518-3.0-py%s-none-any.whl' % pyversion[0]
@ -211,10 +188,8 @@ def test_pip_wheel_with_pep518_build_reqs(script, data, common_wheels):
assert "Installing build dependencies" in result.stdout, result.stdout
@pytest.mark.network
def test_pip_wheel_with_pep518_build_reqs_no_isolation(script, data,
common_wheels):
script.pip_install_local('-f', common_wheels, 'wheel', 'simplewheel==2.0')
def test_pip_wheel_with_pep518_build_reqs_no_isolation(script, data):
script.pip_install_local('simplewheel==2.0')
result = script.pip(
'wheel', '--no-index', '-f', data.find_links,
'--no-build-isolation', 'pep518==3.0',
@ -226,9 +201,7 @@ def test_pip_wheel_with_pep518_build_reqs_no_isolation(script, data,
assert "Installing build dependencies" not in result.stdout, result.stdout
@pytest.mark.network
def test_pip_wheel_with_user_set_in_config(script, data, common_wheels):
script.pip_install_local('-f', common_wheels, 'wheel')
config_file = script.scratch_path / 'pip.conf'
script.environ['PIP_CONFIG_FILE'] = str(config_file)
config_file.write("[install]\nuser = true")

View File

@ -11,8 +11,6 @@ import subprocess
import pytest
import scripttest
import six
import virtualenv
from tests.lib.path import Path, curdir
@ -40,15 +38,6 @@ def path_to_url(path):
return 'file://' + url
# workaround for https://github.com/pypa/virtualenv/issues/306
def virtualenv_lib_path(venv_home, venv_lib):
if not hasattr(sys, "pypy_version_info"):
return venv_lib
version_fmt = '{0}' if six.PY3 else '{0}.{1}'
version_dir = version_fmt.format(*sys.version_info)
return os.path.join(venv_home, 'lib-python', version_dir)
def create_file(path, contents=None):
"""Create a file on the path, with the given contents
"""
@ -281,19 +270,11 @@ class PipTestEnvironment(scripttest.TestFileEnvironment):
base_path = Path(base_path)
# Store paths related to the virtual environment
_virtualenv = kwargs.pop("virtualenv")
path_locations = virtualenv.path_locations(_virtualenv)
# Make sure we have test.lib.path.Path objects
venv, lib, include, bin = map(Path, path_locations)
self.venv_path = venv
self.lib_path = virtualenv_lib_path(venv, lib)
self.include_path = include
self.bin_path = bin
if hasattr(sys, "pypy_version_info"):
self.site_packages_path = self.venv_path.join("site-packages")
else:
self.site_packages_path = self.lib_path.join("site-packages")
venv = kwargs.pop("virtualenv")
self.venv_path = venv.location
self.lib_path = venv.lib
self.site_packages_path = venv.site
self.bin_path = venv.bin
self.user_base_path = self.venv_path.join("user")
self.user_site_path = self.venv_path.join(
@ -336,7 +317,7 @@ class PipTestEnvironment(scripttest.TestFileEnvironment):
super(PipTestEnvironment, self).__init__(base_path, *args, **kwargs)
# Expand our absolute path directories into relative
for name in ["base", "venv", "lib", "include", "bin", "site_packages",
for name in ["base", "venv", "bin", "lib", "site_packages",
"user_base", "user_site", "user_bin", "scratch"]:
real_name = "%s_path" % name
setattr(self, name, getattr(self, real_name) - self.base_path)
@ -380,7 +361,7 @@ class PipTestEnvironment(scripttest.TestFileEnvironment):
if (pyversion_tuple < (2, 7, 9) and
args and args[0] in ('search', 'install', 'download')):
kwargs['expect_stderr'] = True
if kwargs.pop('use_module', False):
if kwargs.pop('use_module', True):
exe = 'python'
args = ('-m', 'pip') + args
else:
@ -394,6 +375,10 @@ class PipTestEnvironment(scripttest.TestFileEnvironment):
*args, **kwargs
)
def easy_install(self, *args, **kwargs):
args = ('-m', 'easy_install') + args
return self.run('python', *args, **kwargs)
# FIXME ScriptTest does something similar, but only within a single
# ProcResult; this generalizes it so states can be compared across

View File

@ -1,10 +1,11 @@
from __future__ import absolute_import
import distutils
import compileall
import sys
import six
import virtualenv as _virtualenv
from . import virtualenv_lib_path
from .path import Path
@ -14,54 +15,124 @@ class VirtualEnvironment(object):
virtualenv but in the future it could use pyvenv.
"""
def __init__(self, location, system_site_packages=False):
def __init__(self, location, template=None):
self.location = Path(location)
self._system_site_packages = system_site_packages
self._user_site_packages = False
self._template = template
self._sitecustomize = None
self._update_paths()
self._create()
def _update_paths(self):
home, lib, inc, bin = _virtualenv.path_locations(self.location)
self.lib = Path(virtualenv_lib_path(home, lib))
self.bin = Path(bin)
self.site = Path(lib) / 'site-packages'
# Workaround for https://github.com/pypa/virtualenv/issues/306
if hasattr(sys, "pypy_version_info"):
version_fmt = '{0}' if six.PY3 else '{0}.{1}'
version_dir = version_fmt.format(*sys.version_info)
self.lib = Path(home, 'lib-python', version_dir)
else:
self.lib = Path(lib)
def __repr__(self):
return "<VirtualEnvironment {}>".format(self.location)
@classmethod
def create(cls, location, clear=False,
pip_source_dir=None, relocatable=False):
obj = cls(location)
obj._create(clear=clear,
pip_source_dir=pip_source_dir,
relocatable=relocatable)
return obj
def _create(self, clear=False):
if clear:
self.location.rmtree()
if self._template:
# On Windows, calling `_virtualenv.path_locations(target)`
# will have created the `target` directory...
if sys.platform == 'win32' and self.location.exists:
self.location.rmdir()
# Clone virtual environment from template.
self._template.location.copytree(self.location)
self._sitecustomize = self._template.sitecustomize
self._user_site_packages = self._template.user_site_packages
else:
# Create a new virtual environment.
_virtualenv.create_environment(
self.location,
no_pip=True,
no_wheel=True,
no_setuptools=True,
)
self._fix_site_module()
self.sitecustomize = self._sitecustomize
self.user_site_packages = self._user_site_packages
def _create(self, clear=False, pip_source_dir=None, relocatable=False):
# Create the actual virtual environment
_virtualenv.create_environment(
self.location,
clear=clear,
download=False,
no_pip=True,
no_wheel=True,
)
_virtualenv.install_wheel([pip_source_dir or '.'],
self.bin.join("python"))
if relocatable:
_virtualenv.make_environment_relocatable(self.location)
# FIXME: some tests rely on 'easy-install.pth' being already present.
site_package = distutils.sysconfig.get_python_lib(prefix=self.location)
Path(site_package).join('easy-install.pth').touch()
def _fix_site_module(self):
# Patch `site.py` so user site work as expected.
site_py = self.lib / 'site.py'
with open(site_py) as fp:
site_contents = fp.read()
for pattern, replace in (
(
# Ensure enabling user site does not result in adding
# the real site-packages' directory to `sys.path`.
(
'\ndef virtual_addsitepackages(known_paths):\n'
),
(
'\ndef virtual_addsitepackages(known_paths):\n'
' return known_paths\n'
),
),
(
# Fix sites ordering: user site must be added before system.
(
'\n paths_in_sys = addsitepackages(paths_in_sys)'
'\n paths_in_sys = addusersitepackages(paths_in_sys)\n'
),
(
'\n paths_in_sys = addusersitepackages(paths_in_sys)'
'\n paths_in_sys = addsitepackages(paths_in_sys)\n'
),
),
):
assert pattern in site_contents
site_contents = site_contents.replace(pattern, replace)
with open(site_py, 'w') as fp:
fp.write(site_contents)
# Make sure bytecode is up-to-date too.
assert compileall.compile_file(str(site_py), quiet=1, force=True)
def _customize_site(self):
contents = ''
if self._sitecustomize is not None:
contents += '\n' + self._sitecustomize
sitecustomize = self.site / "sitecustomize.py"
sitecustomize.write(contents)
# Make sure bytecode is up-to-date too.
assert compileall.compile_file(str(sitecustomize), quiet=1, force=True)
def clear(self):
self._create(clear=True)
@property
def system_site_packages(self):
return self._system_site_packages
def move(self, location):
self.location.move(location)
self.location = Path(location)
self._update_paths()
@system_site_packages.setter
def system_site_packages(self, value):
marker = self.lib.join("no-global-site-packages.txt")
if value:
@property
def sitecustomize(self):
return self._sitecustomize
@sitecustomize.setter
def sitecustomize(self, value):
self._sitecustomize = value
self._customize_site()
@property
def user_site_packages(self):
return self._user_site_packages
@user_site_packages.setter
def user_site_packages(self, value):
self._user_site_packages = value
marker = self.lib / "no-global-site-packages.txt"
if self._user_site_packages:
marker.rm()
else:
marker.touch()
self._system_site_packages = value

View File

@ -0,0 +1,2 @@
setuptools
wheel

View File

@ -7,5 +7,7 @@ pytest-rerunfailures
pytest-timeout
pytest-xdist
pyyaml
setuptools>=39.2.0 # Needed for `setuptools.wheel.Wheel` support.
scripttest
https://github.com/pypa/virtualenv/archive/master.zip#egg=virtualenv
wheel

View File

@ -15,6 +15,9 @@ setenv =
# that our tests use.
LC_CTYPE = en_US.UTF-8
deps = -r{toxinidir}/tools/tests-requirements.txt
commands_pre =
python -c 'import shutil, sys; shutil.rmtree(sys.argv[1], ignore_errors=True)' {toxinidir}/tests/data/common_wheels
{[helpers]pip} wheel -w {toxinidir}/tests/data/common_wheels -r {toxinidir}/tools/tests-common_wheels-requirements.txt
commands = pytest --timeout 300 []
install_command = {[helpers]pip} install {opts} {packages}
list_dependencies_command = {[helpers]pip} freeze --all
@ -41,6 +44,7 @@ skip_install = True
deps =
check-manifest
readme_renderer
commands_pre =
commands =
check-manifest
python setup.py check -m -r -s
@ -55,18 +59,21 @@ commands =
skip_install = True
basepython = python2
deps = {[lint]deps}
commands_pre =
commands = {[lint]commands}
[testenv:lint-py3]
skip_install = True
basepython = python3
deps = {[lint]deps}
commands_pre =
commands = {[lint]commands}
[testenv:mypy]
skip_install = True
basepython = python3
deps = -r{toxinidir}/tools/mypy-requirements.txt
commands_pre =
commands =
mypy src
mypy src -2