1+ import itertools
12import re
23import subprocess
4+ from collections .abc import Collection
35from itertools import chain
46from pathlib import Path
57
68import pytest
7- from pytest_cases import parametrize_with_cases
9+ from pytest_cases import parametrize , parametrize_with_cases
810
911from tests .helpers import run_command , write_files
10- from tests .test_venv_install_cases import CasesVenvInstallRequirementstxt , CasesVenvInstallWithLock
11- from tests .types import RequirementsDict , RequirementsStem
12+ from tests .test_venv_install_cases import (
13+ CasesVenvAddPackagesToRequirements ,
14+ CasesVenvInstallRequirementstxt ,
15+ CasesVenvInstallWithLock ,
16+ )
17+ from tests .types import PackageName , PackageSpec , RequirementsDict , RequirementsStem
1218
1319_package_name_regex = re .compile (r"^([a-zA-Z0-9_-]+)\b" )
1420
@@ -23,34 +29,100 @@ def _check_package_was_installed(requirement: str, installed_line: str) -> None:
2329 assert package_name in installed_line , f"Package { package_name } was not installed succesfully"
2430
2531
32+ def _check_packages_in_requirements_txt (packages : Collection [str ], requirements_file : Path ) -> None :
33+ """Check that the package was added to the requirements file"""
34+ requirements = requirements_file .read_text ().strip ()
35+ for package in packages :
36+ assert package in requirements , f"Package { package } was not added to requirements.txt"
37+
38+
2639def test_venv_install_not_activated (tmp_path : Path , monkeypatch : pytest .MonkeyPatch ):
2740 with pytest .raises (subprocess .CalledProcessError ), monkeypatch .context () as m :
2841 m .delenv ("VIRTUAL_ENV" , raising = False )
2942 run_command (["venv install" ], cwd = tmp_path , activated = False )
3043
3144
45+ _pjl = ["python-json-logger" , "python-json-logger==2.0.7" , "'python-json-logger == 2.0.7'" ]
46+ _urllib = ["urllib3" , "urllib3==2.2.1" , "'urllib3 == 2.2.1'" ]
47+ _wheel = ["wheel" , "wheel==0.42.0" , "'wheel == 0.42.0'" ]
48+
49+
50+ @pytest .mark .order (after = "test_venv_activate.py::test_venv_activate" )
51+ @parametrize (
52+ ["package_spec" , "expected_packages" ],
53+ [
54+ * itertools .product (itertools .product (_pjl ), [("python-json-logger" ,)]),
55+ * itertools .product (itertools .product (_pjl , _urllib ), [("python-json-logger" , "urllib3" )]),
56+ * itertools .product (itertools .product (_pjl , _urllib , _wheel ), [("python-json-logger" , "urllib3" , "wheel" )]),
57+ ],
58+ )
59+ def test_venv_install_packages (
60+ package_spec : tuple [str , ...],
61+ expected_packages : tuple [str , ...],
62+ tmp_path : Path ,
63+ capfd : pytest .CaptureFixture [str ],
64+ ):
65+ # Install the requirements
66+ run_command (
67+ f"venv install { ' ' .join (package_spec )} --skip-lock" ,
68+ cwd = tmp_path ,
69+ activated = True ,
70+ )
71+
72+ # Check pip install log output
73+ output = capfd .readouterr ().out
74+ assert f"Installing" in output
75+
76+ # Check that the expected packages were installed
77+ installed_line = [line for line in output .splitlines () if line .startswith ("Successfully installed" )][0 ]
78+ for package in expected_packages :
79+ _check_package_was_installed (requirement = package , installed_line = installed_line )
80+
81+ # Check that the expected packages were added to requirements.txt
82+ _check_packages_in_requirements_txt (packages = expected_packages , requirements_file = tmp_path / "requirements.txt" )
83+
84+
85+ @parametrize_with_cases (argnames = ["files" , "requirements" ], cases = CasesVenvAddPackagesToRequirements )
86+ def test_add_packages_to_requirements (
87+ files : RequirementsDict ,
88+ requirements : tuple [RequirementsStem , list [tuple [PackageName , PackageSpec ]]],
89+ tmp_path : Path ,
90+ capfd : pytest .CaptureFixture [str ],
91+ ):
92+ write_files (files = files , dir = tmp_path )
93+
94+ requirements_stem , name_spec = requirements
95+ requirements_filename = f"{ requirements_stem .value } .txt"
96+
97+ _ , package_specs = zip (* name_spec )
98+ package_spec_str = " " .join (f"'{ package_spec } '" for package_spec in package_specs )
99+
100+ run_command (
101+ f"venv::_add_packages_to_requirements { requirements_filename } { package_spec_str } " ,
102+ cwd = tmp_path ,
103+ activated = True ,
104+ )
105+ new_contents = (tmp_path / requirements_filename ).read_text ().strip ()
106+
107+ output = capfd .readouterr ().out
108+ for package_name , package_spec in name_spec :
109+ assert f"Adding '{ package_spec } ' to { requirements_filename } " in output
110+ assert package_spec in new_contents , f"Package { package_name } was not added to { requirements_filename } "
111+
112+
32113@pytest .mark .order (after = "test_venv_activate.py::test_venv_activate" )
33114@parametrize_with_cases (argnames = ["files" , "requirements_stem" ], cases = CasesVenvInstallRequirementstxt )
34- @pytest .mark .parametrize ("use_file_name" , [True , False ])
35115def test_venv_install_requirements (
36116 files : RequirementsDict ,
37117 requirements_stem : RequirementsStem ,
38- use_file_name : bool ,
39118 tmp_path : Path ,
40119 capfd : pytest .CaptureFixture [str ],
41120):
42121 write_files (files = files , dir = tmp_path )
43122
44123 # Install the requirements
45- if not (requirements_stem is RequirementsStem .requirements or use_file_name ):
46- pytest .skip (f"Empty file name case only valid for requirements.txt, not { requirements_stem .value } .txt" )
47-
48- install_file_name = ""
49- if use_file_name :
50- install_file_name = f"{ requirements_stem .value } .txt"
51-
52124 run_command (
53- f"venv install { install_file_name } --skip-lock" ,
125+ f"venv install -r { requirements_stem . value } .txt --skip-lock" ,
54126 cwd = tmp_path ,
55127 activated = True ,
56128 )
@@ -71,15 +143,17 @@ def test_venv_install_requirements(
71143
72144@pytest .mark .order (after = "test_venv_activate.py::test_venv_activate" )
73145@parametrize_with_cases (argnames = ["files" , "requirements_stem" ], cases = CasesVenvInstallWithLock )
74- def test_venv_install_with_lock (
146+ def test_venv_install_requirements_with_lock (
75147 files : RequirementsDict ,
76148 requirements_stem : RequirementsStem ,
77149 tmp_path : Path ,
78150):
79151 write_files (files = files , dir = tmp_path )
80152
81153 run_command (
82- f"venv install { requirements_stem } .txt" ,
154+ f"venv install -r { requirements_stem } .txt" ,
83155 cwd = tmp_path ,
84156 activated = True ,
85157 )
158+
159+ assert (tmp_path / f"{ requirements_stem } .lock" ).exists ()
0 commit comments