From fd6d5e54aa633a3a45629ac121ec57575227230e Mon Sep 17 00:00:00 2001 From: Todd Jacobsen Date: Thu, 5 Sep 2024 00:48:54 -0600 Subject: [PATCH 1/2] Closes #1525 preinstall packages from requirements.txt files --- changelog.d/1525.feature.md | 1 + src/pipx/commands/install.py | 4 ++++ src/pipx/commands/reinstall.py | 1 + src/pipx/commands/upgrade.py | 1 + src/pipx/main.py | 9 +++++++++ src/pipx/venv.py | 10 ++++++++++ tests/test_install.py | 12 ++++++++++++ 7 files changed, 38 insertions(+) create mode 100644 changelog.d/1525.feature.md diff --git a/changelog.d/1525.feature.md b/changelog.d/1525.feature.md new file mode 100644 index 0000000000..540aa42afc --- /dev/null +++ b/changelog.d/1525.feature.md @@ -0,0 +1 @@ +add `pipx install --preinstall-from-file requirements.txt ` option diff --git a/src/pipx/commands/install.py b/src/pipx/commands/install.py index dbf26ba28f..effc15a8db 100644 --- a/src/pipx/commands/install.py +++ b/src/pipx/commands/install.py @@ -32,6 +32,7 @@ def install( reinstall: bool, include_dependencies: bool, preinstall_packages: Optional[List[str]], + preinstall_from_file: Optional[List[str]], suffix: str = "", python_flag_passed=False, ) -> ExitCode: @@ -96,6 +97,8 @@ def install( venv.create_venv(venv_args, pip_args, override_shared) for dep in preinstall_packages or []: venv.upgrade_package_no_metadata(dep, []) + if preinstall_from_file: + venv.install_packages_from_file(preinstall_from_file, pip_args) venv.install_package( package_name=package_name, package_or_url=package_spec, @@ -213,6 +216,7 @@ def install_all( reinstall=False, include_dependencies=main_package.include_dependencies, preinstall_packages=[], + preinstall_from_file=[], suffix=main_package.suffix, ) diff --git a/src/pipx/commands/reinstall.py b/src/pipx/commands/reinstall.py index 72011c5deb..0104cc894e 100644 --- a/src/pipx/commands/reinstall.py +++ b/src/pipx/commands/reinstall.py @@ -74,6 +74,7 @@ def reinstall( reinstall=True, include_dependencies=venv.pipx_metadata.main_package.include_dependencies, preinstall_packages=[], + preinstall_from_file=[], suffix=venv.pipx_metadata.main_package.suffix, python_flag_passed=python_flag_passed, ) diff --git a/src/pipx/commands/upgrade.py b/src/pipx/commands/upgrade.py index c5ea6f4d24..7d0389249b 100644 --- a/src/pipx/commands/upgrade.py +++ b/src/pipx/commands/upgrade.py @@ -136,6 +136,7 @@ def _upgrade_venv( reinstall=False, include_dependencies=False, preinstall_packages=None, + preinstall_from_file=None, python_flag_passed=python_flag_passed, ) return 0 diff --git a/src/pipx/main.py b/src/pipx/main.py index 4800f64313..63b186cec6 100644 --- a/src/pipx/main.py +++ b/src/pipx/main.py @@ -293,6 +293,7 @@ def run_pipx_command(args: argparse.Namespace, subparsers: Dict[str, argparse.Ar reinstall=False, include_dependencies=args.include_deps, preinstall_packages=args.preinstall, + preinstall_from_file=args.preinstall_from_file, suffix=args.suffix, python_flag_passed=python_flag_passed, ) @@ -502,6 +503,14 @@ def _add_install(subparsers: argparse._SubParsersAction, shared_parser: argparse ), ) add_pip_venv_args(p) + p.add_argument( + "--preinstall-from-file", + action="append", + help=( + "Path to Requirements File Format file listing optional packages to be installed " + "into the Virtual Environment before installing the main package." + ), + ) def _add_install_all(subparsers: argparse._SubParsersAction, shared_parser: argparse.ArgumentParser) -> None: diff --git a/src/pipx/venv.py b/src/pipx/venv.py index 422de3da08..36ef407509 100644 --- a/src/pipx/venv.py +++ b/src/pipx/venv.py @@ -345,6 +345,16 @@ def install_package_no_deps(self, package_or_url: str, pip_args: List[str]) -> s return package_name + def install_packages_from_file(self, requirements_files: List[str], pip_args: List[str]) -> None: + msg = f"Preinstalling requirements from '{requirements_files}'" + logger.info(msg) + pip_cmd = ["--no-input", "install", "--no-deps"] + pip_args + for requirements_file in requirements_files: + pip_cmd += ["--requirement", requirements_file] + with animate(msg, self.do_animation): + pip_process = self._run_pip(pip_cmd) + subprocess_post_check(pip_process) + def get_venv_metadata_for_package(self, package_name: str, package_extras: Set[str]) -> VenvMetadata: data_start = time.time() venv_metadata = inspect_venv(package_name, package_extras, self.bin_path, self.python_path, self.man_path) diff --git a/tests/test_install.py b/tests/test_install.py index 2cff936880..a73e65ba4b 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -395,6 +395,18 @@ def test_preinstall_specific_version(pipx_temp_env, caplog): assert "black==22.8.0" in caplog.text +def test_preinstall_from_file(pipx_temp_env, tmp_path, caplog): + package = "black" + version = "22.8.0" + requirements_file_name = "requirements.txt" + requirements_file = tmp_path / requirements_file_name + requirements_file.write_text(f"{package}=={version}") + requirements_file.touch() + assert not run_pipx_cli(["install", "--preinstall-from-file", str(requirements_file), "nox"]) + assert "nox" in caplog.text + assert str(requirements_file) in caplog.text + + @pytest.mark.xfail def test_do_not_wait_for_input(pipx_temp_env, pipx_session_shared_dir, monkeypatch): monkeypatch.setenv("PIP_INDEX_URL", "http://127.0.0.1:8080/simple") From 383ed2b11426f4bdb69ca1d65bb38e93adcd7ad4 Mon Sep 17 00:00:00 2001 From: Todd Jacobsen Date: Thu, 5 Sep 2024 18:59:43 -0600 Subject: [PATCH 2/2] Closes #1525 preinstall packages from requirements.txt files --- src/pipx/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pipx/main.py b/src/pipx/main.py index 63b186cec6..4a05443ea4 100644 --- a/src/pipx/main.py +++ b/src/pipx/main.py @@ -507,8 +507,8 @@ def _add_install(subparsers: argparse._SubParsersAction, shared_parser: argparse "--preinstall-from-file", action="append", help=( - "Path to Requirements File Format file listing optional packages to be installed " - "into the Virtual Environment before installing the main package." + "Absolute path to requirements file listing optional packages to be preinstalled into the " + "Virtual Environment before installing the main package. Use this flag multiple times for multiple files." ), )