Skip to content

Commit

Permalink
Extract venv management from test_installation
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
EliahKagan committed Jan 9, 2024
1 parent 66ff4c1 commit 7751436
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 22 deletions.
41 changes: 41 additions & 0 deletions test/lib/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import textwrap
import time
import unittest
import venv

import gitdb

Expand All @@ -36,6 +37,7 @@
"with_rw_repo",
"with_rw_and_rw_remote_repo",
"TestBase",
"VirtualEnvironment",
"TestCase",
"SkipTest",
"skipIf",
Expand Down Expand Up @@ -390,3 +392,42 @@ def _make_file(self, rela_path, data, repo=None):
with open(abs_path, "w") as fp:
fp.write(data)
return abs_path


class VirtualEnvironment:
"""A newly created Python virtual environment for use in a test."""

__slots__ = ("_env_dir",)

def __init__(self, env_dir, *, with_pip):
self._env_dir = env_dir
venv.create(env_dir, symlinks=(os.name != "nt"), with_pip=with_pip)

@property
def env_dir(self):
"""The top-level directory of the environment."""
return self._env_dir

@property
def python(self):
"""Path to the Python executable in the environment."""
return self._executable("python")

@property
def pip(self):
"""Path to the pip executable in the environment, or RuntimeError if absent."""
return self._executable("pip")

@property
def sources(self):
"""Path to a src directory in the environment, which may not exist yet."""
return os.path.join(self.env_dir, "src")

def _executable(self, basename):
if os.name == "nt":
path = osp.join(self.env_dir, "Scripts", basename + ".exe")
else:
path = osp.join(self.env_dir, "bin", basename)
if osp.isfile(path) or osp.islink(path):
return path
raise RuntimeError(f"no regular file or symlink {path!r}")
42 changes: 20 additions & 22 deletions test/test_installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,19 @@
import ast
import os
import subprocess
import sys

from test.lib import TestBase
from test.lib.helper import with_rw_directory
from test.lib import TestBase, VirtualEnvironment, with_rw_directory


class TestInstallation(TestBase):
def setUp_venv(self, rw_dir):
self.venv = rw_dir
subprocess.run([sys.executable, "-m", "venv", self.venv], stdout=subprocess.PIPE)
bin_name = "Scripts" if os.name == "nt" else "bin"
self.python = os.path.join(self.venv, bin_name, "python")
self.pip = os.path.join(self.venv, bin_name, "pip")
self.sources = os.path.join(self.venv, "src")
self.cwd = os.path.dirname(os.path.dirname(__file__))
os.symlink(self.cwd, self.sources, target_is_directory=True)

@with_rw_directory
def test_installation(self, rw_dir):
self.setUp_venv(rw_dir)
venv = self._set_up_venv(rw_dir)

result = subprocess.run(
[self.pip, "install", "."],
[venv.pip, "install", "."],
stdout=subprocess.PIPE,
cwd=self.sources,
cwd=venv.sources,
)
self.assertEqual(
0,
Expand All @@ -37,9 +25,9 @@ def test_installation(self, rw_dir):
)

result = subprocess.run(
[self.python, "-c", "import git"],
[venv.python, "-c", "import git"],
stdout=subprocess.PIPE,
cwd=self.sources,
cwd=venv.sources,
)
self.assertEqual(
0,
Expand All @@ -48,9 +36,9 @@ def test_installation(self, rw_dir):
)

result = subprocess.run(
[self.python, "-c", "import gitdb; import smmap"],
[venv.python, "-c", "import gitdb; import smmap"],
stdout=subprocess.PIPE,
cwd=self.sources,
cwd=venv.sources,
)
self.assertEqual(
0,
Expand All @@ -62,9 +50,9 @@ def test_installation(self, rw_dir):
# by inserting its location into PYTHONPATH or otherwise patched into
# sys.path, make sure it is not wrongly inserted as the *first* entry.
result = subprocess.run(
[self.python, "-c", "import sys; import git; print(sys.path)"],
[venv.python, "-c", "import sys; import git; print(sys.path)"],
stdout=subprocess.PIPE,
cwd=self.sources,
cwd=venv.sources,
)
syspath = result.stdout.decode("utf-8").splitlines()[0]
syspath = ast.literal_eval(syspath)
Expand All @@ -73,3 +61,13 @@ def test_installation(self, rw_dir):
syspath[0],
msg="Failed to follow the conventions for https://docs.python.org/3/library/sys.html#sys.path",
)

@staticmethod
def _set_up_venv(rw_dir):
venv = VirtualEnvironment(rw_dir, with_pip=True)
os.symlink(
os.path.dirname(os.path.dirname(__file__)),
venv.sources,
target_is_directory=True,
)
return venv

0 comments on commit 7751436

Please sign in to comment.