diff --git a/src/pip_deepfreeze/__main__.py b/src/pip_deepfreeze/__main__.py index 88cfd9e..05fda1b 100644 --- a/src/pip_deepfreeze/__main__.py +++ b/src/pip_deepfreeze/__main__.py @@ -7,7 +7,7 @@ from packaging.utils import canonicalize_name from packaging.version import Version -from .pip import InstallerFlavor +from .pip import Installer, InstallerFlavor from .pyproject_toml import load_pyproject_toml from .sanity import check_env from .sync import sync as sync_operation @@ -91,6 +91,7 @@ def sync( constraints. Optionally uninstall unneeded dependencies. """ sync_operation( + Installer.create(flavor=installer, python=ctx.obj.python), ctx.obj.python, upgrade_all, comma_split(to_upgrade), @@ -99,7 +100,6 @@ def sync( project_root=ctx.obj.project_root, pre_sync_commands=pre_sync_commands, post_sync_commands=post_sync_commands, - installer_flavor=installer, ) diff --git a/src/pip_deepfreeze/pip.py b/src/pip_deepfreeze/pip.py index 839430b..871c9b2 100644 --- a/src/pip_deepfreeze/pip.py +++ b/src/pip_deepfreeze/pip.py @@ -92,11 +92,11 @@ def uninstall_cmd(self, python: str) -> List[str]: def pip_upgrade_project( + installer: Installer, python: str, constraints_filename: Path, project_root: Path, extras: Optional[Sequence[NormalizedName]] = None, - installer: Installer | None = None, installer_options: Optional[List[str]] = None, ) -> None: """Upgrade a project. @@ -125,8 +125,6 @@ def pip_upgrade_project( update the version specifier in requirements.txt, and reinstalling the project with this function. """ - if installer is None: - installer = PipInstaller() constraints_without_editables_filename = get_temp_path_in_dir( dir=project_root, prefix="requirements.", suffix=".txt.df" ) diff --git a/src/pip_deepfreeze/sync.py b/src/pip_deepfreeze/sync.py index 03c3001..4a774ed 100644 --- a/src/pip_deepfreeze/sync.py +++ b/src/pip_deepfreeze/sync.py @@ -6,7 +6,6 @@ from .pip import ( Installer, - InstallerFlavor, pip_fixup_vcs_direct_urls, pip_freeze_dependencies_by_extra, pip_uninstall, @@ -54,6 +53,7 @@ def _constraints_path(project_root: Path) -> Path: def sync( + installer: Installer, python: str, upgrade_all: bool, to_upgrade: List[str], @@ -62,9 +62,7 @@ def sync( project_root: Path, pre_sync_commands: Sequence[str] = (), post_sync_commands: Sequence[str] = (), - installer_flavor: InstallerFlavor = InstallerFlavor.pip, ) -> None: - installer = Installer.create(installer_flavor, python) # run pre-sync commands run_commands(pre_sync_commands, project_root, "pre-sync") # sync @@ -88,11 +86,11 @@ def sync( else: print(req_line.raw_line, file=constraints) pip_upgrade_project( + installer, python, merged_constraints_path, project_root, extras=extras, - installer=installer, installer_options=installer_options, ) # freeze dependencies diff --git a/tests/test_pip.py b/tests/test_pip.py index ed4e95a..a1d0fa6 100644 --- a/tests/test_pip.py +++ b/tests/test_pip.py @@ -6,6 +6,9 @@ from packaging.requirements import Requirement from pip_deepfreeze.pip import ( + Installer, + PipInstaller, + UvpipInstaller, _pip_list__env_info_json, _pip_list__pip_inspect, pip_freeze, @@ -174,21 +177,26 @@ def test_pip_freeze_dependencies_by_extra( ([], [], []), ], ) -def test_pip_uninstall(to_install, to_uninstall, expected, virtualenv_python, testpkgs): +@pytest.mark.parametrize("installer", [PipInstaller(), UvpipInstaller()]) +def test_pip_uninstall( + to_install, + to_uninstall, + expected, + installer: Installer, + virtualenv_python, + testpkgs, +): if to_install: subprocess.call( [ - virtualenv_python, - "-m", - "pip", - "install", + *installer.install_cmd(virtualenv_python), "--no-index", "--find-links", testpkgs, *to_install, ] ) - pip_uninstall(virtualenv_python, to_uninstall) + pip_uninstall(installer, virtualenv_python, to_uninstall) assert list(_freeze_filter(pip_freeze(virtualenv_python))) == expected @@ -201,7 +209,10 @@ def _freeze_filter(reqs: Iterable[str]) -> Iterator[str]: yield req -def test_pip_upgrade_project(virtualenv_python, testpkgs, tmp_path): +@pytest.mark.parametrize("installer", [PipInstaller(), UvpipInstaller()]) +def test_pip_upgrade_project( + installer: Installer, virtualenv_python, testpkgs, tmp_path +): constraints = tmp_path / "requirements.txt.df" # First install, pkgc frozen to 0.0.1. (tmp_path / "setup.py").write_text( @@ -217,15 +228,21 @@ def test_pip_upgrade_project(virtualenv_python, testpkgs, tmp_path): ) ) constraints.write_text(f"--no-index\n--find-links {testpkgs}\npkgc==0.0.1") - pip_upgrade_project(virtualenv_python, constraints, project_root=tmp_path) + pip_upgrade_project( + installer, virtualenv_python, constraints, project_root=tmp_path + ) assert list(_freeze_filter(pip_freeze(virtualenv_python))) == ["pkgc==0.0.1"] # Upgrade pkgc by adding a different constraint. constraints.write_text(f"--no-index\n--find-links {testpkgs}\npkgc<=0.0.2") - pip_upgrade_project(virtualenv_python, constraints, project_root=tmp_path) + pip_upgrade_project( + installer, virtualenv_python, constraints, project_root=tmp_path + ) assert list(_freeze_filter(pip_freeze(virtualenv_python))) == ["pkgc==0.0.2"] # Upgrade pkgc to latest version by removing it from constraints. constraints.write_text(f"--no-index\n--find-links {testpkgs}") - pip_upgrade_project(virtualenv_python, constraints, project_root=tmp_path) + pip_upgrade_project( + installer, virtualenv_python, constraints, project_root=tmp_path + ) assert list(_freeze_filter(pip_freeze(virtualenv_python))) == ["pkgc==0.0.3"] # Remove dependency from setup.py but it is still in frozen requirements, # the upgrade procedure does not remove it. @@ -242,16 +259,23 @@ def test_pip_upgrade_project(virtualenv_python, testpkgs, tmp_path): ) ) constraints.write_text(f"--no-index\n--find-links {testpkgs}\npkgc==0.0.3") - pip_upgrade_project(virtualenv_python, constraints, project_root=tmp_path) + pip_upgrade_project( + installer, virtualenv_python, constraints, project_root=tmp_path + ) assert list(_freeze_filter(pip_freeze(virtualenv_python))) == ["pkgc==0.0.3"] # Remove dependency from frozen requirements, check the upgrade procedure # does not remove it (it is now an unrelated package which we leave alone). constraints.write_text(f"--no-index\n--find-links {testpkgs}") - pip_upgrade_project(virtualenv_python, constraints, project_root=tmp_path) + pip_upgrade_project( + installer, virtualenv_python, constraints, project_root=tmp_path + ) assert list(_freeze_filter(pip_freeze(virtualenv_python))) == ["pkgc==0.0.3"] -def test_pip_upgrade_constraint_not_a_dep(virtualenv_python, testpkgs, tmp_path): +@pytest.mark.parametrize("installer", [PipInstaller(), UvpipInstaller()]) +def test_pip_upgrade_constraint_not_a_dep( + installer: Installer, virtualenv_python, testpkgs, tmp_path +): """Test upgrading does not install constraints that are not dependencies.""" constraints = tmp_path / "requirements.txt.df" # First install, pkgc frozen to 0.0.1. @@ -265,11 +289,16 @@ def test_pip_upgrade_constraint_not_a_dep(virtualenv_python, testpkgs, tmp_path) ) ) constraints.write_text(f"--no-index\n--find-links {testpkgs}\npkgc==0.0.1") - pip_upgrade_project(virtualenv_python, constraints, project_root=tmp_path) + pip_upgrade_project( + installer, virtualenv_python, constraints, project_root=tmp_path + ) assert list(_freeze_filter(pip_freeze(virtualenv_python))) == [] -def test_pip_upgrade_vcs_url(virtualenv_python, tmp_path, capfd): +@pytest.mark.parametrize("installer", [PipInstaller(), UvpipInstaller()]) +def test_pip_upgrade_vcs_url( + installer: Installer, virtualenv_python, testpkgs, tmp_path, capfd +): """Test upgrading a VCS URL.""" constraints = tmp_path / "requirements.txt.df" (tmp_path / "setup.py").write_text( @@ -285,8 +314,14 @@ def test_pip_upgrade_vcs_url(virtualenv_python, tmp_path, capfd): ) ) # install tag 0.10.0 - constraints.write_text("--no-index\ntoml @ git+https://github.com/uiri/toml@0.10.0") - pip_upgrade_project(virtualenv_python, constraints, project_root=tmp_path) + constraints.write_text( + "--no-index\n" + f"--find-links {testpkgs}\n" + "toml @ git+https://github.com/uiri/toml@0.10.0" + ) + pip_upgrade_project( + installer, virtualenv_python, constraints, project_root=tmp_path + ) assert list(_freeze_filter(pip_freeze(virtualenv_python))) == [ "toml @ git+https://github.com/uiri/toml" "@4935f616ef78c35a968b2473e806d7049eba9af1" @@ -295,17 +330,26 @@ def test_pip_upgrade_vcs_url(virtualenv_python, tmp_path, capfd): # reinstall, no change but different @url syntax constraints.write_text( "--no-index\n" + f"--find-links {testpkgs}\n" "toml@git+https://github.com/uiri/toml@4935f616ef78c35a968b2473e806d7049eba9af1" ) - pip_upgrade_project(virtualenv_python, constraints, project_root=tmp_path) + pip_upgrade_project( + installer, virtualenv_python, constraints, project_root=tmp_path + ) assert list(_freeze_filter(pip_freeze(virtualenv_python))) == [ "toml @ git+https://github.com/uiri/toml" "@4935f616ef78c35a968b2473e806d7049eba9af1" ] assert "Uninstalling dependencies to update" not in capfd.readouterr().err # upgrade to tag 0.10.1 - constraints.write_text("toml @ git+https://github.com/uiri/toml@0.10.1") - pip_upgrade_project(virtualenv_python, constraints, project_root=tmp_path) + constraints.write_text( + "--no-index\n" + f"--find-links {testpkgs}\n" + "toml @ git+https://github.com/uiri/toml@0.10.1" + ) + pip_upgrade_project( + installer, virtualenv_python, constraints, project_root=tmp_path + ) assert list(_freeze_filter(pip_freeze(virtualenv_python))) == [ "toml @ git+https://github.com/uiri/toml" "@a86fc1fbd650a19eba313c3f642c9e2c679dc8d6" diff --git a/tests/test_sync.py b/tests/test_sync.py index 3c7ec70..7a5fe30 100644 --- a/tests/test_sync.py +++ b/tests/test_sync.py @@ -6,7 +6,13 @@ from typer.testing import CliRunner from pip_deepfreeze.__main__ import app -from pip_deepfreeze.pip import pip_freeze, pip_list +from pip_deepfreeze.pip import ( + Installer, + PipInstaller, + UvpipInstaller, + pip_freeze, + pip_list, +) from pip_deepfreeze.sync import sync @@ -134,8 +140,12 @@ def test_editable_default_install(virtualenv_python, editable_foobar_path): assert "-e " in "\n".join(pip_freeze(virtualenv_python)) -def test_sync_project_root(virtualenv_python, editable_foobar_path): +@pytest.mark.parametrize("installer", [PipInstaller(), UvpipInstaller()]) +def test_sync_project_root( + installer: Installer, virtualenv_python, editable_foobar_path +): sync( + installer, virtualenv_python, upgrade_all=False, to_upgrade=[], @@ -177,7 +187,8 @@ def test_sync_editable_dep(virtualenv_python, tmp_path): assert "-e " in requirements_path.read_text(), requirements_path.read_text() -def test_sync_uninstall(virtualenv_python, tmp_path, testpkgs): +@pytest.mark.parametrize("installer", [PipInstaller(), UvpipInstaller()]) +def test_sync_uninstall(installer: Installer, virtualenv_python, tmp_path, testpkgs): setup_py = tmp_path / "setup.py" setup_py.write_text( textwrap.dedent( @@ -192,6 +203,7 @@ def test_sync_uninstall(virtualenv_python, tmp_path, testpkgs): in_reqs = tmp_path / "constraints.txt" in_reqs.write_text(f"--no-index\n-f {testpkgs}") sync( + installer, virtualenv_python, upgrade_all=False, to_upgrade=[], @@ -212,6 +224,7 @@ def test_sync_uninstall(virtualenv_python, tmp_path, testpkgs): ) # sync with uninstall=False, pkga remains sync( + installer, virtualenv_python, upgrade_all=False, to_upgrade=[], @@ -222,6 +235,7 @@ def test_sync_uninstall(virtualenv_python, tmp_path, testpkgs): assert "pkga==" in "\n".join(pip_freeze(virtualenv_python)) # sync with uninstall=True, pkga removed sync( + installer, virtualenv_python, upgrade_all=False, to_upgrade=[], @@ -233,7 +247,10 @@ def test_sync_uninstall(virtualenv_python, tmp_path, testpkgs): @pytest.mark.xfail(reason="https://github.com/sbidoul/pip-deepfreeze/issues/24") -def test_sync_update_new_dep(virtualenv_python, testpkgs, tmp_path): +@pytest.mark.parametrize("installer", [PipInstaller(), UvpipInstaller()]) +def test_sync_update_new_dep( + installer: Installer, virtualenv_python, testpkgs, tmp_path +): """Test that a preinstalled dependency is updated when project is not installed before sync. @@ -241,10 +258,7 @@ def test_sync_update_new_dep(virtualenv_python, testpkgs, tmp_path): """ subprocess.check_call( [ - virtualenv_python, - "-m", - "pip", - "install", + *installer.install_cmd(virtualenv_python), "--no-index", "-f", testpkgs, @@ -270,6 +284,7 @@ def test_sync_update_new_dep(virtualenv_python, testpkgs, tmp_path): ) ) sync( + installer, virtualenv_python, upgrade_all=False, to_upgrade=["pkgc"], @@ -281,7 +296,10 @@ def test_sync_update_new_dep(virtualenv_python, testpkgs, tmp_path): @pytest.mark.xfail(reason="https://github.com/sbidoul/pip-deepfreeze/issues/24") -def test_sync_update_all_new_dep(virtualenv_python, testpkgs, tmp_path): +@pytest.mark.parametrize("installer", [PipInstaller(), UvpipInstaller()]) +def test_sync_update_all_new_dep( + installer: Installer, virtualenv_python, testpkgs, tmp_path +): """Test that a preinstalled dependency is updated when project is not installed before sync. @@ -289,10 +307,7 @@ def test_sync_update_all_new_dep(virtualenv_python, testpkgs, tmp_path): """ subprocess.check_call( [ - virtualenv_python, - "-m", - "pip", - "install", + *installer.install_cmd(virtualenv_python), "--no-index", "-f", testpkgs, @@ -318,6 +333,7 @@ def test_sync_update_all_new_dep(virtualenv_python, testpkgs, tmp_path): ) ) sync( + installer, virtualenv_python, upgrade_all=True, to_upgrade=[], @@ -328,7 +344,8 @@ def test_sync_update_all_new_dep(virtualenv_python, testpkgs, tmp_path): assert "pkgc==0.0.3" in "\n".join(pip_freeze(virtualenv_python)) -def test_sync_extras(virtualenv_python, testpkgs, tmp_path): +@pytest.mark.parametrize("installer", [PipInstaller(), UvpipInstaller()]) +def test_sync_extras(installer: Installer, virtualenv_python, testpkgs, tmp_path): (tmp_path / "setup.py").write_text( textwrap.dedent( """\ @@ -353,6 +370,7 @@ def test_sync_extras(virtualenv_python, testpkgs, tmp_path): ) ) sync( + installer, virtualenv_python, upgrade_all=False, to_upgrade=[], @@ -371,6 +389,7 @@ def test_sync_extras(virtualenv_python, testpkgs, tmp_path): # now sync again with a different frozen extra dependency (tmp_path / "requirements-c.txt").write_text("pkgc==0.0.2") sync( + installer, virtualenv_python, upgrade_all=False, to_upgrade=[],