Skip to content

Commit 7751436

Browse files
committed
Extract venv management from test_installation
- Create and use a test.lib.helper.VirtualEnvironment class. - Import and use venv module instead of running "python -m venv". These changes make no significant difference in speed or clarity for the existing test in test_installation. The reason for this change is instead to support the use of new per-test virtual environments in at least one other test.
1 parent 66ff4c1 commit 7751436

File tree

2 files changed

+61
-22
lines changed

2 files changed

+61
-22
lines changed

test/lib/helper.py

+41
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import textwrap
1515
import time
1616
import unittest
17+
import venv
1718

1819
import gitdb
1920

@@ -36,6 +37,7 @@
3637
"with_rw_repo",
3738
"with_rw_and_rw_remote_repo",
3839
"TestBase",
40+
"VirtualEnvironment",
3941
"TestCase",
4042
"SkipTest",
4143
"skipIf",
@@ -390,3 +392,42 @@ def _make_file(self, rela_path, data, repo=None):
390392
with open(abs_path, "w") as fp:
391393
fp.write(data)
392394
return abs_path
395+
396+
397+
class VirtualEnvironment:
398+
"""A newly created Python virtual environment for use in a test."""
399+
400+
__slots__ = ("_env_dir",)
401+
402+
def __init__(self, env_dir, *, with_pip):
403+
self._env_dir = env_dir
404+
venv.create(env_dir, symlinks=(os.name != "nt"), with_pip=with_pip)
405+
406+
@property
407+
def env_dir(self):
408+
"""The top-level directory of the environment."""
409+
return self._env_dir
410+
411+
@property
412+
def python(self):
413+
"""Path to the Python executable in the environment."""
414+
return self._executable("python")
415+
416+
@property
417+
def pip(self):
418+
"""Path to the pip executable in the environment, or RuntimeError if absent."""
419+
return self._executable("pip")
420+
421+
@property
422+
def sources(self):
423+
"""Path to a src directory in the environment, which may not exist yet."""
424+
return os.path.join(self.env_dir, "src")
425+
426+
def _executable(self, basename):
427+
if os.name == "nt":
428+
path = osp.join(self.env_dir, "Scripts", basename + ".exe")
429+
else:
430+
path = osp.join(self.env_dir, "bin", basename)
431+
if osp.isfile(path) or osp.islink(path):
432+
return path
433+
raise RuntimeError(f"no regular file or symlink {path!r}")

test/test_installation.py

+20-22
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,19 @@
44
import ast
55
import os
66
import subprocess
7-
import sys
87

9-
from test.lib import TestBase
10-
from test.lib.helper import with_rw_directory
8+
from test.lib import TestBase, VirtualEnvironment, with_rw_directory
119

1210

1311
class TestInstallation(TestBase):
14-
def setUp_venv(self, rw_dir):
15-
self.venv = rw_dir
16-
subprocess.run([sys.executable, "-m", "venv", self.venv], stdout=subprocess.PIPE)
17-
bin_name = "Scripts" if os.name == "nt" else "bin"
18-
self.python = os.path.join(self.venv, bin_name, "python")
19-
self.pip = os.path.join(self.venv, bin_name, "pip")
20-
self.sources = os.path.join(self.venv, "src")
21-
self.cwd = os.path.dirname(os.path.dirname(__file__))
22-
os.symlink(self.cwd, self.sources, target_is_directory=True)
23-
2412
@with_rw_directory
2513
def test_installation(self, rw_dir):
26-
self.setUp_venv(rw_dir)
14+
venv = self._set_up_venv(rw_dir)
2715

2816
result = subprocess.run(
29-
[self.pip, "install", "."],
17+
[venv.pip, "install", "."],
3018
stdout=subprocess.PIPE,
31-
cwd=self.sources,
19+
cwd=venv.sources,
3220
)
3321
self.assertEqual(
3422
0,
@@ -37,9 +25,9 @@ def test_installation(self, rw_dir):
3725
)
3826

3927
result = subprocess.run(
40-
[self.python, "-c", "import git"],
28+
[venv.python, "-c", "import git"],
4129
stdout=subprocess.PIPE,
42-
cwd=self.sources,
30+
cwd=venv.sources,
4331
)
4432
self.assertEqual(
4533
0,
@@ -48,9 +36,9 @@ def test_installation(self, rw_dir):
4836
)
4937

5038
result = subprocess.run(
51-
[self.python, "-c", "import gitdb; import smmap"],
39+
[venv.python, "-c", "import gitdb; import smmap"],
5240
stdout=subprocess.PIPE,
53-
cwd=self.sources,
41+
cwd=venv.sources,
5442
)
5543
self.assertEqual(
5644
0,
@@ -62,9 +50,9 @@ def test_installation(self, rw_dir):
6250
# by inserting its location into PYTHONPATH or otherwise patched into
6351
# sys.path, make sure it is not wrongly inserted as the *first* entry.
6452
result = subprocess.run(
65-
[self.python, "-c", "import sys; import git; print(sys.path)"],
53+
[venv.python, "-c", "import sys; import git; print(sys.path)"],
6654
stdout=subprocess.PIPE,
67-
cwd=self.sources,
55+
cwd=venv.sources,
6856
)
6957
syspath = result.stdout.decode("utf-8").splitlines()[0]
7058
syspath = ast.literal_eval(syspath)
@@ -73,3 +61,13 @@ def test_installation(self, rw_dir):
7361
syspath[0],
7462
msg="Failed to follow the conventions for https://docs.python.org/3/library/sys.html#sys.path",
7563
)
64+
65+
@staticmethod
66+
def _set_up_venv(rw_dir):
67+
venv = VirtualEnvironment(rw_dir, with_pip=True)
68+
os.symlink(
69+
os.path.dirname(os.path.dirname(__file__)),
70+
venv.sources,
71+
target_is_directory=True,
72+
)
73+
return venv

0 commit comments

Comments
 (0)