Skip to content

Commit 2c44b08

Browse files
committed
Collect test cases for test_venv_install
Collect test cases for dev and non-dev requirements in one, more generalized test function.
1 parent 37de175 commit 2c44b08

File tree

4 files changed

+96
-112
lines changed

4 files changed

+96
-112
lines changed

tests/helpers.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import os
22
import subprocess
33
import sys
4+
from functools import wraps
45
from pathlib import Path
6+
from typing import Callable
7+
8+
from tests.types import P, RawFilesDict, RequirementsBase, RequirementsDict
59

610
RequirementFiles = dict[str, Path]
711
current_python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
@@ -31,3 +35,20 @@ def run_command(commands: str | list[str], cwd: Path = Path.cwd(), activated: bo
3135

3236
result = subprocess.run(all_commands, cwd=cwd)
3337
result.check_returncode()
38+
39+
40+
def collect_requirements(
41+
func: Callable[P, tuple[RawFilesDict, RequirementsBase]]
42+
) -> Callable[P, tuple[RequirementsDict, RequirementsBase]]:
43+
@wraps(func)
44+
def wrapper(*args: P.args, **kwargs: P.kwargs) -> tuple[RequirementsDict, RequirementsBase]:
45+
files_dict, requirements_base = func(*args, **kwargs)
46+
requirements_dict = {filename: "\n".join(requirements) for filename, requirements in files_dict.items()}
47+
return requirements_dict, requirements_base
48+
49+
return wrapper
50+
51+
52+
def write_files(files: RequirementsDict, dir: Path) -> None:
53+
for filename, contents in files.items():
54+
(dir / filename).write_text(contents)

tests/test_venv_install.py

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,62 @@
11
import re
2+
from itertools import chain
23
from pathlib import Path
34

45
import pytest
56
from pytest_cases import parametrize_with_cases
67

7-
from tests.helpers import run_command
8-
from tests.test_venv_install_cases import CasesVenvInstallDevRequirementstxt, CasesVenvInstallRequirementstxt
8+
from tests.helpers import run_command, write_files
9+
from tests.test_venv_install_cases import CasesVenvInstallRequirementstxt
10+
from tests.types import RequirementsBase, RequirementsDict
911

10-
_package_regex = re.compile(r"^([a-zA-Z0-9_-]+)\b")
12+
_package_name_regex = re.compile(r"^([a-zA-Z0-9_-]+)\b")
1113

1214

13-
@pytest.mark.order(after="test_venv_activate.py::test_venv_activate")
14-
@pytest.mark.parametrize("command_arg", ["", "requirements.txt"])
15-
@parametrize_with_cases(argnames=["files"], cases=CasesVenvInstallRequirementstxt)
16-
def test_venv_install_requirements_txt(
17-
command_arg: str,
18-
files: dict[str, str],
19-
tmp_path: Path,
20-
capfd: pytest.CaptureFixture,
21-
):
22-
(tmp_path / "requirements.txt").write_text(files["requirements.txt"])
23-
24-
# Install the requirements
25-
run_command(f"venv install {command_arg} --skip-lock", cwd=tmp_path, activated=True)
26-
27-
# Check pip install log output
28-
output: str = capfd.readouterr().out
29-
assert "Installing requirements from requirements.txt" in output
30-
31-
installed_line = [line for line in output.splitlines() if line.startswith("Successfully installed")][0]
32-
for requirement in files["requirements.txt"].splitlines():
33-
re_match = _package_regex.match(requirement)
34-
if re_match is None:
35-
raise ValueError(f"Could not extract package name from requirement '{requirement}'")
15+
def _check_package_was_installed(requirement: str, installed_line: str) -> None:
16+
"""Check the 'Succesfully installed ...' output from 'pip install' to see that requirement was installed"""
17+
re_match = _package_name_regex.match(requirement)
18+
if re_match is None:
19+
raise ValueError(f"Could not extract package name from requirement '{requirement}'")
3620

37-
package_name = re_match.group()
38-
assert package_name in installed_line
21+
package_name = re_match.group()
22+
assert package_name in installed_line, f"Package {package_name} was not installed succesfully"
3923

4024

4125
@pytest.mark.order(after="test_venv_activate.py::test_venv_activate")
42-
@parametrize_with_cases(argnames=["files"], cases=CasesVenvInstallDevRequirementstxt)
43-
def test_venv_install_dev_requirements_txt(
44-
files: dict[str, str],
26+
@parametrize_with_cases(argnames=["files", "requirements_base"], cases=CasesVenvInstallRequirementstxt)
27+
@pytest.mark.parametrize("use_file_name", [True, False])
28+
def test_venv_install_requirements(
29+
files: RequirementsDict,
30+
requirements_base: RequirementsBase,
31+
use_file_name: bool,
4532
tmp_path: Path,
4633
capfd: pytest.CaptureFixture,
4734
):
48-
for file_name, contents in files.items():
49-
(tmp_path / file_name).write_text(contents)
35+
write_files(files=files, dir=tmp_path)
5036

5137
# Install the requirements
52-
run_command("venv install dev-requirements.txt --skip-lock", cwd=tmp_path, activated=True)
38+
if not (requirements_base is RequirementsBase.requirements or use_file_name):
39+
pytest.skip(f"Empty file name case only valid for requirements.txt, not {requirements_base}")
40+
41+
install_file_name = ""
42+
if use_file_name:
43+
install_file_name = f"{requirements_base.value}.txt"
44+
45+
run_command(
46+
f"venv install {install_file_name} --skip-lock",
47+
cwd=tmp_path,
48+
activated=True,
49+
)
5350

5451
# Check pip install log output
5552
output: str = capfd.readouterr().out
56-
assert "Installing requirements from dev-requirements.txt" in output
53+
assert f"Installing requirements from {requirements_base.value}.txt" in output
5754

5855
installed_line = [line for line in output.splitlines() if line.startswith("Successfully installed")][0]
59-
for requirement in [
60-
*files["requirements.txt"].splitlines(),
61-
*files["dev-requirements.txt"].splitlines(),
62-
]:
56+
requirement_lines = chain.from_iterable(contents.splitlines() for contents in files.values())
57+
for requirement in requirement_lines:
6358
if requirement.startswith("-r"):
6459
# Skip '-r requirements.txt' line
6560
continue
6661

6762
_check_package_was_installed(requirement=requirement, installed_line=installed_line)
68-
69-
70-
def _check_package_was_installed(requirement: str, installed_line: str) -> None:
71-
re_match = _package_regex.match(requirement)
72-
if re_match is None:
73-
raise ValueError(f"Could not extract package name from requirement '{requirement}'")
74-
75-
package_name = re_match.group()
76-
assert package_name in installed_line

tests/test_venv_install_cases.py

Lines changed: 28 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,56 @@
1+
from tests.helpers import collect_requirements
2+
from tests.types import RawFilesDict, RequirementsBase
3+
4+
15
class CasesVenvInstallRequirementstxt:
2-
def case_pypi(self):
3-
requirements = [
6+
@collect_requirements
7+
def case_pypi(self) -> tuple[RawFilesDict, RequirementsBase]:
8+
requirements_txt = [
49
"python-json-logger==2.0.7",
510
]
611

7-
return {"requirements.txt": "\n".join(requirements)}
12+
files = {"requirements.txt": requirements_txt}
13+
return files, RequirementsBase.requirements
814

9-
def case_git(self):
10-
requirements = [
15+
@collect_requirements
16+
def case_git(self) -> tuple[RawFilesDict, RequirementsBase]:
17+
requirements_txt = [
1118
"python-json-logger @ git+https://github.com/madzak/[email protected]",
1219
]
1320

14-
return {"requirements.txt": "\n".join(requirements)}
15-
16-
def case_git_token(self, create_test_credentials: None):
17-
requirements = ["python-json-logger @ git+https://${TEST_TOKEN}@github.com/madzak/[email protected]"]
18-
19-
return {"requirements.txt": "\n".join(requirements)}
20-
21-
def case_git_user_pass(self, create_test_credentials: None):
22-
requirements = [
23-
"python-json-logger @ git+https://${TEST_USER}:${TEST_PASS}@github.com/madzak/[email protected]"
24-
]
25-
26-
return {"requirements.txt": "\n".join(requirements)}
21+
files = {"requirements.txt": requirements_txt}
22+
return files, RequirementsBase.requirements
2723

28-
29-
class CasesVenvInstallDevRequirementstxt:
30-
def case_pypi_dev(self):
31-
requirements = [
24+
@collect_requirements
25+
def case_pypi_dev(self) -> tuple[RawFilesDict, RequirementsBase]:
26+
requirements_txt = [
3227
"python-json-logger==2.0.7",
3328
]
3429

35-
dev_requirements = [
30+
dev_requirements_txt = [
3631
"-r requirements.txt",
3732
"numpy==1.26.0",
3833
]
3934

4035
files = {
41-
"requirements.txt": "\n".join(requirements),
42-
"dev-requirements.txt": "\n".join(dev_requirements),
36+
"requirements.txt": requirements_txt,
37+
"dev-requirements.txt": dev_requirements_txt,
4338
}
44-
return files
39+
return files, RequirementsBase.dev_requirements
4540

46-
def case_git_dev(self):
47-
requirements = [
41+
@collect_requirements
42+
def case_git_dev(self) -> tuple[RawFilesDict, RequirementsBase]:
43+
requirements_txt = [
4844
"python-json-logger @ git+https://github.com/madzak/[email protected]",
4945
]
5046

51-
dev_requirements = [
52-
"-r requirements.txt",
53-
"numpy==1.26.0",
54-
]
55-
56-
files = {
57-
"requirements.txt": "\n".join(requirements),
58-
"dev-requirements.txt": "\n".join(dev_requirements),
59-
}
60-
return files
61-
62-
def case_git_token_dev(self, create_test_credentials: None):
63-
requirements = [
64-
"python-json-logger @ git+https://${TEST_TOKEN}@github.com/madzak/[email protected]",
65-
]
66-
67-
dev_requirements = [
68-
"-r requirements.txt",
69-
"numpy==1.26.0",
70-
]
71-
72-
files = {
73-
"requirements.txt": "\n".join(requirements),
74-
"dev-requirements.txt": "\n".join(dev_requirements),
75-
}
76-
return files
77-
78-
def case_git_user_pass_dev(self, create_test_credentials: None):
79-
requirements = [
80-
"python-json-logger @ git+https://${TEST_USER}:${TEST_PASS}@github.com/madzak/[email protected]",
81-
]
82-
83-
dev_requirements = [
47+
dev_requirements_txt = [
8448
"-r requirements.txt",
8549
"numpy==1.26.0",
8650
]
8751

8852
files = {
89-
"requirements.txt": "\n".join(requirements),
90-
"dev-requirements.txt": "\n".join(dev_requirements),
53+
"requirements.txt": requirements_txt,
54+
"dev-requirements.txt": dev_requirements_txt,
9155
}
92-
return files
56+
return files, RequirementsBase.dev_requirements

tests/types.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from enum import Enum
2+
from pathlib import Path
3+
from typing import ParamSpec
4+
5+
P = ParamSpec("P")
6+
RawFilesDict = dict[str, list[str]]
7+
RequirementsDict = dict[str, str]
8+
RequirementFiles = dict[str, Path]
9+
10+
11+
class RequirementsBase(str, Enum):
12+
requirements = "requirements"
13+
dev_requirements = "dev-requirements"

0 commit comments

Comments
 (0)