mirror of https://github.com/pypa/pip
tests: add support for using venv for the virtual environment
Add a new testsuite option `--use-venv` to enable the use of `venv` for creating a test virtual environment. The option is opt-in because creating a `venv` environment does not work right when running under a `virtualenv`; which is why `tox-venv` must be used in combination with tox.
This commit is contained in:
parent
add3801163
commit
a4209aa0fb
|
@ -1,6 +1,7 @@
|
|||
language: python
|
||||
cache: pip
|
||||
dist: trusty
|
||||
python: 3.6
|
||||
|
||||
stages:
|
||||
- primary
|
||||
|
@ -12,8 +13,8 @@ jobs:
|
|||
- stage: primary
|
||||
env: TOXENV=docs
|
||||
- env: TOXENV=lint-py2
|
||||
python: 2.7
|
||||
- env: TOXENV=lint-py3
|
||||
python: 3.6
|
||||
- env: TOXENV=mypy
|
||||
- env: TOXENV=packaging
|
||||
# Latest CPython
|
||||
|
|
|
@ -18,7 +18,8 @@ environment:
|
|||
install:
|
||||
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
||||
- "python --version"
|
||||
- "pip install certifi tox"
|
||||
- "pip install --upgrade certifi tox tox-venv"
|
||||
- "pip freeze --all"
|
||||
# Fix git SSL errors.
|
||||
- "python -m certifi >cacert.txt"
|
||||
- "set /p GIT_SSL_CAINFO=<cacert.txt"
|
||||
|
@ -61,7 +62,7 @@ test_script:
|
|||
$env:TEMP = "T:\"
|
||||
$env:TMP = "T:\"
|
||||
if ($env:RUN_INTEGRATION_TESTS -eq "True") {
|
||||
tox -e py -- -m integration -n 3 --duration=5
|
||||
tox -e py -- --use-venv -m integration -n 3 --duration=5
|
||||
}
|
||||
else {
|
||||
tox -e py -- -m unit -n 3
|
||||
|
|
|
@ -21,9 +21,11 @@ def pytest_addoption(parser):
|
|||
"--keep-tmpdir", action="store_true",
|
||||
default=False, help="keep temporary test directories"
|
||||
)
|
||||
parser.addoption("--use-venv", action="store_true",
|
||||
help="use venv for virtual environment creation")
|
||||
|
||||
|
||||
def pytest_collection_modifyitems(items):
|
||||
def pytest_collection_modifyitems(config, items):
|
||||
for item in items:
|
||||
if not hasattr(item, 'module'): # e.g.: DoctestTextfile
|
||||
continue
|
||||
|
@ -32,6 +34,16 @@ def pytest_collection_modifyitems(items):
|
|||
if item.get_marker('network') is not None and "CI" in os.environ:
|
||||
item.add_marker(pytest.mark.flaky(reruns=3))
|
||||
|
||||
if six.PY3:
|
||||
if (item.get_marker('incompatible_with_test_venv') and
|
||||
config.getoption("--use-venv")):
|
||||
item.add_marker(pytest.mark.skip(
|
||||
'Incompatible with test venv'))
|
||||
if (item.get_marker('incompatible_with_venv') and
|
||||
sys.prefix != sys.base_prefix):
|
||||
item.add_marker(pytest.mark.skip(
|
||||
'Incompatible with venv'))
|
||||
|
||||
module_path = os.path.relpath(
|
||||
item.module.__file__,
|
||||
os.path.commonprefix([__file__, item.module.__file__]),
|
||||
|
@ -197,12 +209,17 @@ def install_egg_link(venv, project_name, egg_info_dir):
|
|||
|
||||
|
||||
@pytest.yield_fixture(scope='session')
|
||||
def virtualenv_template(tmpdir_factory, pip_src,
|
||||
def virtualenv_template(request, tmpdir_factory, pip_src,
|
||||
setuptools_install, common_wheels):
|
||||
|
||||
if six.PY3 and request.config.getoption('--use-venv'):
|
||||
venv_type = 'venv'
|
||||
else:
|
||||
venv_type = 'virtualenv'
|
||||
|
||||
# Create the virtual environment
|
||||
tmpdir = Path(str(tmpdir_factory.mktemp('virtualenv')))
|
||||
venv = VirtualEnvironment(tmpdir.join("venv_orig"))
|
||||
venv = VirtualEnvironment(tmpdir.join("venv_orig"), venv_type=venv_type)
|
||||
|
||||
# Install setuptools and pip.
|
||||
install_egg_link(venv, 'setuptools', setuptools_install)
|
||||
|
|
|
@ -77,6 +77,7 @@ class Tests_UserSite:
|
|||
)
|
||||
assert dist_info_folder in result.files_created
|
||||
|
||||
@pytest.mark.incompatible_with_test_venv
|
||||
def test_install_user_venv_nositepkgs_fails(self, virtualenv,
|
||||
script, data):
|
||||
"""
|
||||
|
|
|
@ -10,7 +10,7 @@ import shutil
|
|||
import subprocess
|
||||
|
||||
import pytest
|
||||
import scripttest
|
||||
from scripttest import FoundDir, TestFileEnvironment
|
||||
|
||||
from tests.lib.path import Path, curdir
|
||||
|
||||
|
@ -248,7 +248,7 @@ class TestPipResult(object):
|
|||
)
|
||||
|
||||
|
||||
class PipTestEnvironment(scripttest.TestFileEnvironment):
|
||||
class PipTestEnvironment(TestFileEnvironment):
|
||||
"""
|
||||
A specialized TestFileEnvironment for testing pip
|
||||
"""
|
||||
|
@ -339,6 +339,16 @@ class PipTestEnvironment(scripttest.TestFileEnvironment):
|
|||
result = super(PipTestEnvironment, self)._ignore_file(fn)
|
||||
return result
|
||||
|
||||
def _find_traverse(self, path, result):
|
||||
# Ignore symlinked directories to avoid duplicates in `run()`
|
||||
# results because of venv `lib64 -> lib/` symlink on Linux.
|
||||
full = os.path.join(self.base_path, path)
|
||||
if os.path.isdir(full) and os.path.islink(full):
|
||||
if not self.temp_path or path != 'tmp':
|
||||
result[path] = FoundDir(self.base_path, path)
|
||||
else:
|
||||
super(PipTestEnvironment, self)._find_traverse(path, result)
|
||||
|
||||
def run(self, *args, **kw):
|
||||
if self.verbose:
|
||||
print('>> running %s %s' % (args, kw))
|
||||
|
|
|
@ -2,12 +2,16 @@ from __future__ import absolute_import
|
|||
|
||||
import compileall
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
import six
|
||||
import virtualenv as _virtualenv
|
||||
|
||||
from .path import Path
|
||||
|
||||
if six.PY3:
|
||||
import venv as _venv
|
||||
|
||||
|
||||
class VirtualEnvironment(object):
|
||||
"""
|
||||
|
@ -15,8 +19,11 @@ class VirtualEnvironment(object):
|
|||
virtualenv but in the future it could use pyvenv.
|
||||
"""
|
||||
|
||||
def __init__(self, location, template=None):
|
||||
def __init__(self, location, template=None, venv_type=None):
|
||||
assert template is None or venv_type is None
|
||||
assert venv_type in (None, 'virtualenv', 'venv')
|
||||
self.location = Path(location)
|
||||
self._venv_type = venv_type or template._venv_type or 'virtualenv'
|
||||
self._user_site_packages = False
|
||||
self._template = template
|
||||
self._sitecustomize = None
|
||||
|
@ -52,17 +59,24 @@ class VirtualEnvironment(object):
|
|||
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()
|
||||
if self._venv_type == 'virtualenv':
|
||||
_virtualenv.create_environment(
|
||||
self.location,
|
||||
no_pip=True,
|
||||
no_wheel=True,
|
||||
no_setuptools=True,
|
||||
)
|
||||
self._fix_virtualenv_site_module()
|
||||
elif self._venv_type == 'venv':
|
||||
builder = _venv.EnvBuilder()
|
||||
context = builder.ensure_directories(self.location)
|
||||
builder.create_configuration(context)
|
||||
builder.setup_python(context)
|
||||
self.site.makedirs()
|
||||
self.sitecustomize = self._sitecustomize
|
||||
self.user_site_packages = self._user_site_packages
|
||||
|
||||
def _fix_site_module(self):
|
||||
def _fix_virtualenv_site_module(self):
|
||||
# Patch `site.py` so user site work as expected.
|
||||
site_py = self.lib / 'site.py'
|
||||
with open(site_py) as fp:
|
||||
|
@ -100,6 +114,34 @@ class VirtualEnvironment(object):
|
|||
|
||||
def _customize_site(self):
|
||||
contents = ''
|
||||
if self._venv_type == 'venv':
|
||||
# Enable user site (before system).
|
||||
contents += textwrap.dedent(
|
||||
'''
|
||||
import os, site, sys
|
||||
|
||||
if not os.environ.get('PYTHONNOUSERSITE', False):
|
||||
|
||||
site.ENABLE_USER_SITE = True
|
||||
|
||||
# First, drop system-sites related paths.
|
||||
original_sys_path = sys.path[:]
|
||||
known_paths = set()
|
||||
for path in site.getsitepackages():
|
||||
site.addsitedir(path, known_paths=known_paths)
|
||||
system_paths = sys.path[len(original_sys_path):]
|
||||
for path in system_paths:
|
||||
if path in original_sys_path:
|
||||
original_sys_path.remove(path)
|
||||
sys.path = original_sys_path
|
||||
|
||||
# Second, add user-site.
|
||||
site.addsitedir(site.getusersitepackages())
|
||||
|
||||
# Third, add back system-sites related paths.
|
||||
for path in site.getsitepackages():
|
||||
site.addsitedir(path)
|
||||
''').strip()
|
||||
if self._sitecustomize is not None:
|
||||
contents += '\n' + self._sitecustomize
|
||||
sitecustomize = self.site / "sitecustomize.py"
|
||||
|
@ -131,8 +173,11 @@ class VirtualEnvironment(object):
|
|||
@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()
|
||||
if self._venv_type == 'virtualenv':
|
||||
marker = self.lib / "no-global-site-packages.txt"
|
||||
if self._user_site_packages:
|
||||
marker.rm()
|
||||
else:
|
||||
marker.touch()
|
||||
elif self._venv_type == 'venv':
|
||||
self._customize_site()
|
||||
|
|
|
@ -8,6 +8,7 @@ import shutil
|
|||
import sys
|
||||
import tempfile
|
||||
|
||||
import pytest
|
||||
from mock import Mock
|
||||
|
||||
from pip._internal.locations import distutils_scheme
|
||||
|
@ -90,6 +91,7 @@ class TestDisutilsScheme:
|
|||
expected = os.path.join(root, path[1:])
|
||||
assert os.path.abspath(root_scheme[key]) == expected
|
||||
|
||||
@pytest.mark.incompatible_with_venv
|
||||
def test_distutils_config_file_read(self, tmpdir, monkeypatch):
|
||||
# This deals with nt/posix path differences
|
||||
install_scripts = os.path.normcase(os.path.abspath(
|
||||
|
@ -106,6 +108,7 @@ class TestDisutilsScheme:
|
|||
scheme = distutils_scheme('example')
|
||||
assert scheme['scripts'] == install_scripts
|
||||
|
||||
@pytest.mark.incompatible_with_venv
|
||||
# when we request install-lib, we should install everything (.py &
|
||||
# .so) into that path; i.e. ensure platlib & purelib are set to
|
||||
# this path
|
||||
|
|
|
@ -3,4 +3,5 @@ set -e
|
|||
set -x
|
||||
|
||||
pip install --upgrade setuptools
|
||||
pip install --upgrade tox
|
||||
pip install --upgrade tox tox-venv
|
||||
pip freeze --all
|
||||
|
|
|
@ -43,10 +43,10 @@ if [[ "$GROUP" == "1" ]]; then
|
|||
# Unit tests
|
||||
tox -- -m unit
|
||||
# Integration tests (not the ones for 'pip install')
|
||||
tox -- -m integration -n 4 --duration=5 -k "not test_install"
|
||||
tox -- --use-venv -m integration -n 4 --duration=5 -k "not test_install"
|
||||
elif [[ "$GROUP" == "2" ]]; then
|
||||
# Separate Job for running integration tests for 'pip install'
|
||||
tox -- -m integration -n 4 --duration=5 -k "test_install"
|
||||
tox -- --use-venv -m integration -n 4 --duration=5 -k "test_install"
|
||||
else
|
||||
# Non-Testing Jobs should run once
|
||||
tox
|
||||
|
|
Loading…
Reference in New Issue