Skip to content

Commit cd9ecdf

Browse files
authored
Merge pull request #4706 from benoit-pierre/speedup_testsuite
2 parents a9d56c7 + e792c48 commit cd9ecdf

File tree

4 files changed

+54
-67
lines changed

4 files changed

+54
-67
lines changed

.travis.yml

-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ matrix:
3030
python: nightly
3131
allow_failures:
3232
- python: nightly
33-
- python: pypy3
3433

3534
install: travis_retry .travis/install.sh
3635
script: .travis/run.sh

tests/conftest.py

+24-22
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import six
99

1010
import pip._internal
11-
from pip._internal.utils import appdirs
1211
from tests.lib import SRC_DIR, TestData
1312
from tests.lib.path import Path
1413
from tests.lib.scripttest import PipTestEnvironment
@@ -124,18 +123,9 @@ def isolate(tmpdir):
124123
)
125124

126125

127-
@pytest.fixture
128-
def virtualenv(tmpdir, monkeypatch, isolate):
129-
"""
130-
Return a virtual environment which is unique to each test function
131-
invocation created inside of a sub directory of the test function's
132-
temporary directory. The returned object is a
133-
``tests.lib.venv.VirtualEnvironment`` object.
134-
"""
135-
# Force shutil to use the older method of rmtree that didn't use the fd
136-
# functions. These seem to fail on Travis (and only on Travis).
137-
monkeypatch.setattr(shutil, "_use_fd_functions", False, raising=False)
138-
126+
@pytest.yield_fixture(scope='session')
127+
def virtualenv_template(tmpdir_factory):
128+
tmpdir = Path(str(tmpdir_factory.mktemp('virtualenv')))
139129
# Copy over our source tree so that each virtual environment is self
140130
# contained
141131
pip_src = tmpdir.join("pip_src").abspath
@@ -147,21 +137,33 @@ def virtualenv(tmpdir, monkeypatch, isolate):
147137
"tests", "pip.egg-info", "build", "dist", ".tox", ".git",
148138
),
149139
)
150-
151140
# Create the virtual environment
152141
venv = VirtualEnvironment.create(
153-
tmpdir.join("workspace", "venv"),
142+
tmpdir.join("venv_orig"),
154143
pip_source_dir=pip_src,
144+
relocatable=True,
155145
)
146+
# Rename original virtualenv directory to make sure
147+
# it's not reused by mistake from one of the copies.
148+
venv_template = tmpdir / "venv_template"
149+
os.rename(venv.location, venv_template)
150+
yield venv_template
151+
tmpdir.rmtree(noerrors=True)
156152

157-
# Clean out our cache: creating the venv injects wheels into it.
158-
if os.path.exists(appdirs.user_cache_dir("pip")):
159-
shutil.rmtree(appdirs.user_cache_dir("pip"))
160153

161-
# Undo our monkeypatching of shutil
162-
monkeypatch.undo()
163-
164-
return venv
154+
@pytest.yield_fixture
155+
def virtualenv(virtualenv_template, tmpdir, isolate):
156+
"""
157+
Return a virtual environment which is unique to each test function
158+
invocation created inside of a sub directory of the test function's
159+
temporary directory. The returned object is a
160+
``tests.lib.venv.VirtualEnvironment`` object.
161+
"""
162+
venv_location = tmpdir.join("workspace", "venv")
163+
shutil.copytree(virtualenv_template, venv_location, symlinks=True)
164+
venv = VirtualEnvironment(venv_location)
165+
yield venv
166+
venv_location.rmtree(noerrors=True)
165167

166168

167169
@pytest.fixture

tests/lib/__init__.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import shutil
1010

1111
import scripttest
12+
import six
1213
import virtualenv
1314

1415
from tests.lib.path import Path, curdir
@@ -35,6 +36,15 @@ def path_to_url(path):
3536
return 'file://' + url
3637

3738

39+
# workaround for https://github.com/pypa/virtualenv/issues/306
40+
def virtualenv_lib_path(venv_home, venv_lib):
41+
if not hasattr(sys, "pypy_version_info"):
42+
return venv_lib
43+
version_fmt = '{0}' if six.PY3 else '{0}.{1}'
44+
version_dir = version_fmt.format(*sys.version_info)
45+
return os.path.join(venv_home, 'lib-python', version_dir)
46+
47+
3848
def create_file(path, contents=None):
3949
"""Create a file on the path, with the given contents
4050
"""
@@ -262,11 +272,8 @@ def __init__(self, base_path, *args, **kwargs):
262272
path_locations = virtualenv.path_locations(_virtualenv)
263273
# Make sure we have test.lib.path.Path objects
264274
venv, lib, include, bin = map(Path, path_locations)
265-
# workaround for https://github.com/pypa/virtualenv/issues/306
266-
if hasattr(sys, "pypy_version_info"):
267-
lib = os.path.join(venv, 'lib-python', pyversion)
268275
self.venv_path = venv
269-
self.lib_path = lib
276+
self.lib_path = virtualenv_lib_path(venv, lib)
270277
self.include_path = include
271278
self.bin_path = bin
272279

tests/lib/venv.py

+19-40
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,39 @@
11
from __future__ import absolute_import
22

3-
import os
4-
import subprocess
5-
import sys
3+
import distutils
64

75
import virtualenv as _virtualenv
86

7+
from . import virtualenv_lib_path
98
from .path import Path
109

11-
# On Python < 3.3 we don't have subprocess.DEVNULL
12-
try:
13-
DEVNULL = subprocess.DEVNULL
14-
except AttributeError:
15-
DEVNULL = open(os.devnull, "wb")
16-
1710

1811
class VirtualEnvironment(object):
1912
"""
2013
An abstraction around virtual environments, currently it only uses
2114
virtualenv but in the future it could use pyvenv.
2215
"""
2316

24-
def __init__(self, location, *args, **kwargs):
17+
def __init__(self, location, system_site_packages=False):
2518
self.location = Path(location)
26-
self.pip_source_dir = kwargs.pop("pip_source_dir")
27-
self._system_site_packages = kwargs.pop("system_site_packages", False)
28-
19+
self._system_site_packages = system_site_packages
2920
home, lib, inc, bin = _virtualenv.path_locations(self.location)
30-
# workaround for https://github.com/pypa/virtualenv/issues/306
31-
if hasattr(sys, "pypy_version_info"):
32-
lib = os.path.join(home, 'lib-python', sys.version[:3])
33-
self.lib = Path(lib)
21+
self.lib = Path(virtualenv_lib_path(home, lib))
3422
self.bin = Path(bin)
3523

36-
super(VirtualEnvironment, self).__init__(*args, **kwargs)
37-
3824
def __repr__(self):
3925
return "<VirtualEnvironment {0}>".format(self.location)
4026

4127
@classmethod
42-
def create(cls, location, clear=False, pip_source_dir=None):
43-
obj = cls(location, pip_source_dir=pip_source_dir)
44-
obj._create(clear=clear)
28+
def create(cls, location, clear=False,
29+
pip_source_dir=None, relocatable=False):
30+
obj = cls(location)
31+
obj._create(clear=clear,
32+
pip_source_dir=pip_source_dir,
33+
relocatable=relocatable)
4534
return obj
4635

47-
def _create(self, clear=False):
36+
def _create(self, clear=False, pip_source_dir=None, relocatable=False):
4837
# Create the actual virtual environment
4938
_virtualenv.create_environment(
5039
self.location,
@@ -53,23 +42,13 @@ def _create(self, clear=False):
5342
no_pip=True,
5443
no_wheel=True,
5544
)
56-
57-
# Install our development version of pip install the virtual
58-
# environment
59-
cmd = [self.bin.join("python"), "setup.py", "install", "--no-compile"]
60-
p = subprocess.Popen(
61-
cmd,
62-
cwd=self.pip_source_dir,
63-
stderr=subprocess.STDOUT,
64-
stdout=DEVNULL,
65-
)
66-
p.communicate()
67-
if p.returncode != 0:
68-
raise subprocess.CalledProcessError(
69-
p.returncode,
70-
cmd,
71-
output=p.stdout,
72-
)
45+
_virtualenv.install_wheel([pip_source_dir or '.'],
46+
self.bin.join("python"))
47+
if relocatable:
48+
_virtualenv.make_environment_relocatable(self.location)
49+
# FIXME: some tests rely on 'easy-install.pth' being already present.
50+
site_package = distutils.sysconfig.get_python_lib(prefix=self.location)
51+
Path(site_package).join('easy-install.pth').touch()
7352

7453
def clear(self):
7554
self._create(clear=True)

0 commit comments

Comments
 (0)