From 434479f6eab54c569d77bca6e034f3ec482ac4fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Wed, 18 Sep 2024 20:20:45 -0700 Subject: [PATCH] Separate list depeendencies to a separate installer class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows other installers (such as uv) to reuse this code. Signed-off-by: Bernát Gábor --- docs/changelog/3347.feature.rst | 2 + src/tox/tox_env/python/pip/pip_install.py | 50 +++++++++++++++-------- 2 files changed, 35 insertions(+), 17 deletions(-) create mode 100644 docs/changelog/3347.feature.rst diff --git a/docs/changelog/3347.feature.rst b/docs/changelog/3347.feature.rst new file mode 100644 index 000000000..06cf93270 --- /dev/null +++ b/docs/changelog/3347.feature.rst @@ -0,0 +1,2 @@ +Separate the list dependencies functionality to a separate abstract class allowing code reuse in plugins (such as +``tox-uv``) - by :gaborbernat`. diff --git a/src/tox/tox_env/python/pip/pip_install.py b/src/tox/tox_env/python/pip/pip_install.py index 38b39bd6f..3ef4501f1 100644 --- a/src/tox/tox_env/python/pip/pip_install.py +++ b/src/tox/tox_env/python/pip/pip_install.py @@ -2,6 +2,7 @@ import logging import operator +from abc import ABC, abstractmethod from collections import defaultdict from pathlib import Path from typing import TYPE_CHECKING, Any, Callable, Sequence @@ -21,14 +22,36 @@ from tox.tox_env.package import PathPackage -class Pip(Installer[Python]): - """Pip is a python installer that can install packages as defined by PEP-508 and PEP-517.""" - +class PythonInstallerList(Installer[Python], ABC): def __init__(self, tox_env: Python, with_list_deps: bool = True) -> None: # noqa: FBT001, FBT002 self._with_list_deps = with_list_deps super().__init__(tox_env) def _register_config(self) -> None: + if self._with_list_deps: # pragma: no branch + self._env.conf.add_config( + keys=["list_dependencies_command"], + of_type=Command, + default=Command(self.freeze_cmd()), + desc="command used to list installed packages", + ) + + @abstractmethod + def freeze_cmd(self) -> list[str]: + raise NotImplementedError + + def installed(self) -> list[str]: + cmd: Command = self._env.conf["list_dependencies_command"] + result = self._env.execute(cmd=cmd.args, stdin=StdinSource.OFF, run_id="freeze", show=False) + result.assert_success() + return result.out.splitlines() + + +class Pip(PythonInstallerList): + """Pip is a python installer that can install packages as defined by PEP-508 and PEP-517.""" + + def _register_config(self) -> None: + super()._register_config() self._env.conf.add_config( keys=["pip_pre"], of_type=bool, @@ -54,13 +77,9 @@ def _register_config(self) -> None: default=False, desc="Use the exact versions of installed deps as constraints, otherwise use the listed deps.", ) - if self._with_list_deps: # pragma: no branch - self._env.conf.add_config( - keys=["list_dependencies_command"], - of_type=Command, - default=Command(["python", "-m", "pip", "freeze", "--all"]), - desc="command used to list installed packages", - ) + + def freeze_cmd(self) -> list[str]: # noqa: PLR6301 + return ["python", "-m", "pip", "freeze", "--all"] def default_install_command(self, conf: Config, env_name: str | None) -> Command: # noqa: ARG002 isolated_flag = "-E" if self._env.base_python.version_info.major == 2 else "-I" # noqa: PLR2004 @@ -82,12 +101,6 @@ def post_process_install_command(self, cmd: Command) -> Command: install_command.pop(opts_at) return cmd - def installed(self) -> list[str]: - cmd: Command = self._env.conf["list_dependencies_command"] - result = self._env.execute(cmd=cmd.args, stdin=StdinSource.OFF, run_id="freeze", show=False) - result.assert_success() - return result.out.splitlines() - def install(self, arguments: Any, section: str, of_type: str) -> None: if isinstance(arguments, PythonDeps): self._install_requirement_file(arguments, section, of_type) @@ -239,4 +252,7 @@ def build_install_cmd(self, args: Sequence[str]) -> list[str]: return install_command[:opts_at] + list(args) + install_command[opts_at + 1 :] -__all__ = ("Pip",) +__all__ = [ + "Pip", + "PythonInstallerList", +]