From 21891aed2c6b654139cd541ff4a184c8aa41eeb5 Mon Sep 17 00:00:00 2001
From: David Hotham <david.hotham@blueyonder.co.uk>
Date: Mon, 6 May 2024 12:42:32 +0100
Subject: [PATCH] remove pip-based installer

---
 docs/cli.md                             |   6 --
 docs/configuration.md                   |  15 ----
 src/poetry/config/config.py             |   2 -
 src/poetry/console/commands/config.py   |   1 -
 src/poetry/console/commands/install.py  |   4 +-
 src/poetry/installation/executor.py     | 111 ------------------------
 tests/console/commands/self/conftest.py |   1 -
 tests/console/commands/test_config.py   |   6 --
 tests/installation/test_executor.py     |  64 --------------
 9 files changed, 1 insertion(+), 209 deletions(-)

diff --git a/docs/cli.md b/docs/cli.md
index 2e6a8fdd21c..6ff3f48664a 100644
--- a/docs/cli.md
+++ b/docs/cli.md
@@ -249,12 +249,6 @@ you can use the `--compile` option:
 poetry install --compile
 ```
 
-{{% note %}}
-The `--compile` option has no effect if `installer.modern-installation`
-is set to `false` because the old installer always compiles source files to bytecode.
-{{% /note %}}
-
-
 ### Options
 
 * `--without`: The dependency groups to ignore.
diff --git a/docs/configuration.md b/docs/configuration.md
index 98f9bff2471..e2192f26713 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -196,21 +196,6 @@ the number of maximum workers is still limited at `number_of_cores + 4`.
 This configuration is ignored when `installer.parallel` is set to `false`.
 {{% /note %}}
 
-### `installer.modern-installation`
-
-**Type**: `boolean`
-
-**Default**: `true`
-
-**Environment Variable**: `POETRY_INSTALLER_MODERN_INSTALLATION`
-
-*Introduced in 1.4.0*
-
-Use a more modern and faster method for package installation.
-
-If this causes issues, you can disable it by setting it to `false` and report the problems
-you encounter on the [issue tracker](https://github.com/python-poetry/poetry/issues).
-
 ### `installer.no-binary`
 
 **Type**: `string | boolean`
diff --git a/src/poetry/config/config.py b/src/poetry/config/config.py
index 2188f8284e0..c83e7fed35b 100644
--- a/src/poetry/config/config.py
+++ b/src/poetry/config/config.py
@@ -128,7 +128,6 @@ class Config:
             "system-git-client": False,
         },
         "installer": {
-            "modern-installation": True,
             "parallel": True,
             "max-workers": None,
             "no-binary": None,
@@ -307,7 +306,6 @@ def _get_normalizer(name: str) -> Callable[[str], Any]:
             "virtualenvs.options.system-site-packages",
             "virtualenvs.options.prefer-active-python",
             "experimental.system-git-client",
-            "installer.modern-installation",
             "installer.parallel",
             "solver.lazy-wheel",
             "warnings.export",
diff --git a/src/poetry/console/commands/config.py b/src/poetry/console/commands/config.py
index 8b862226689..8fa3e352df9 100644
--- a/src/poetry/console/commands/config.py
+++ b/src/poetry/console/commands/config.py
@@ -74,7 +74,6 @@ def unique_config_values(self) -> dict[str, tuple[Any, Any]]:
             "virtualenvs.prefer-active-python": (boolean_validator, boolean_normalizer),
             "virtualenvs.prompt": (str, str),
             "experimental.system-git-client": (boolean_validator, boolean_normalizer),
-            "installer.modern-installation": (boolean_validator, boolean_normalizer),
             "installer.parallel": (boolean_validator, boolean_normalizer),
             "installer.max-workers": (lambda val: int(val) > 0, int_normalizer),
             "installer.no-binary": (
diff --git a/src/poetry/console/commands/install.py b/src/poetry/console/commands/install.py
index 7234a1cebcb..63f4f93cb48 100644
--- a/src/poetry/console/commands/install.py
+++ b/src/poetry/console/commands/install.py
@@ -65,9 +65,7 @@ class InstallCommand(InstallerCommand):
         option(
             "compile",
             None,
-            "Compile Python source files to bytecode."
-            " (This option has no effect if modern-installation is disabled"
-            " because the old installer always compiles.)",
+            "Compile Python source files to bytecode.",
         ),
     ]
 
diff --git a/src/poetry/installation/executor.py b/src/poetry/installation/executor.py
index 4747e9f2ffd..46f47a4ac39 100644
--- a/src/poetry/installation/executor.py
+++ b/src/poetry/installation/executor.py
@@ -1,6 +1,5 @@
 from __future__ import annotations
 
-import contextlib
 import csv
 import functools
 import itertools
@@ -14,7 +13,6 @@
 from typing import TYPE_CHECKING
 from typing import Any
 
-from cleo.io.null_io import NullIO
 from poetry.core.packages.utils.link import Link
 
 from poetry.installation.chef import Chef
@@ -34,13 +32,11 @@
 from poetry.utils.helpers import remove_directory
 from poetry.utils.isolated_build import IsolatedBuildError
 from poetry.utils.isolated_build import IsolatedBuildInstallError
-from poetry.utils.pip import pip_install
 
 
 if TYPE_CHECKING:
     from cleo.io.io import IO
     from cleo.io.outputs.section_output import SectionOutput
-    from poetry.core.masonry.builders.builder import Builder
     from poetry.core.packages.package import Package
 
     from poetry.config.config import Config
@@ -65,20 +61,6 @@ def __init__(
         self._enabled = True
         self._verbose = False
         self._wheel_installer = WheelInstaller(self._env)
-        self._use_modern_installation = config.get(
-            "installer.modern-installation", True
-        )
-        if not self._use_modern_installation:
-            self._io.write_line(
-                "<warning>Warning: Setting `installer.modern-installation` to `false` "
-                "is deprecated.</>"
-            )
-            self._io.write_line(
-                "<warning>The pip-based installer will be removed in a future release.</>"
-            )
-            self._io.write_line(
-                "<warning>See https://github.com/python-poetry/poetry/issues/8987.</>"
-            )
 
         if parallel is None:
             parallel = config.get("installer.parallel", True)
@@ -145,22 +127,6 @@ def verbose(self, verbose: bool = True) -> Executor:
     def enable_bytecode_compilation(self, enable: bool = True) -> None:
         self._wheel_installer.enable_bytecode_compilation(enable)
 
-    def pip_install(
-        self, req: Path, upgrade: bool = False, editable: bool = False
-    ) -> int:
-        try:
-            pip_install(req, self._env, upgrade=upgrade, editable=editable)
-        except EnvCommandError as e:
-            output = decode(e.e.output)
-            if (
-                "KeyboardInterrupt" in output
-                or "ERROR: Operation cancelled by user" in output
-            ):
-                return -2
-            raise
-
-        return 0
-
     def execute(self, operations: list[Operation]) -> int:
         for job_type in self._executed:
             self._executed[job_type] = 0
@@ -172,13 +138,6 @@ def execute(self, operations: list[Operation]) -> int:
         self._sections = {}
         self._yanked_warnings = []
 
-        # pip has to be installed first without parallelism if we install via pip
-        for i, op in enumerate(operations):
-            if op.package.name == "pip":
-                wait([self._executor.submit(self._execute_operation, op)])
-                del operations[i]
-                break
-
         # We group operations by priority
         groups = itertools.groupby(operations, key=lambda o: -o.priority)
         for _, group in groups:
@@ -535,8 +494,6 @@ def _execute_uninstall(self, operation: Uninstall) -> int:
 
     def _install(self, operation: Install | Update) -> int:
         package = operation.package
-        if package.source_type == "directory" and not self._use_modern_installation:
-            return self._install_directory_without_wheel_installer(operation)
 
         cleanup_archive: bool = False
         if package.source_type == "git":
@@ -560,9 +517,6 @@ def _install(self, operation: Install | Update) -> int:
         )
         self._write(operation, message)
 
-        if not self._use_modern_installation:
-            return self.pip_install(archive, upgrade=operation.job_type == "update")
-
         try:
             if operation.job_type == "update":
                 # Uninstall first
@@ -675,59 +629,6 @@ def _prepare_git_archive(self, operation: Install | Update) -> Path:
 
         return archive
 
-    def _install_directory_without_wheel_installer(
-        self, operation: Install | Update
-    ) -> int:
-        from poetry.factory import Factory
-        from poetry.pyproject.toml import PyProjectTOML
-
-        package = operation.package
-        operation_message = self.get_operation_message(operation)
-
-        message = (
-            f"  <fg=blue;options=bold>-</> {operation_message}:"
-            " <info>Building...</info>"
-        )
-        self._write(operation, message)
-
-        assert package.source_url is not None
-        if package.root_dir:
-            req = package.root_dir / package.source_url
-        else:
-            req = Path(package.source_url).resolve(strict=False)
-
-        if package.source_subdirectory:
-            req /= package.source_subdirectory
-
-        pyproject = PyProjectTOML(req / "pyproject.toml")
-
-        package_poetry = None
-        if pyproject.is_poetry_project():
-            with contextlib.suppress(RuntimeError):
-                package_poetry = Factory().create_poetry(pyproject.file.path.parent)
-
-        if package_poetry is not None:
-            builder: Builder
-            if package.develop and not package_poetry.package.build_script:
-                from poetry.masonry.builders.editable import EditableBuilder
-
-                # This is a Poetry package in editable mode
-                # we can use the EditableBuilder without going through pip
-                # to install it, unless it has a build script.
-                builder = EditableBuilder(package_poetry, self._env, NullIO())
-                builder.build()
-
-                return 0
-
-            if package_poetry.package.build_script:
-                from poetry.core.masonry.builders.sdist import SdistBuilder
-
-                builder = SdistBuilder(package_poetry)
-                with builder.setup_py():
-                    return self.pip_install(req, upgrade=True, editable=package.develop)
-
-        return self.pip_install(req, upgrade=True, editable=package.develop)
-
     def _download(self, operation: Install | Update) -> Path:
         link = self._chooser.choose_for(operation.package)
 
@@ -866,18 +767,6 @@ def _save_url_reference(self, operation: Operation) -> None:
         package = operation.package
 
         if not package.source_url or package.source_type == "legacy":
-            if not self._use_modern_installation:
-                # Since we are installing from our own distribution cache pip will write
-                # a `direct_url.json` file pointing to the cache distribution.
-                #
-                # That's not what we want, so we remove the direct_url.json file, if it
-                # exists.
-                for (
-                    direct_url_json
-                ) in self._env.site_packages.find_distribution_direct_url_json_files(
-                    distribution_name=package.name, writable_only=True
-                ):
-                    direct_url_json.unlink(missing_ok=True)
             return
 
         url_reference: dict[str, Any] | None = None
diff --git a/tests/console/commands/self/conftest.py b/tests/console/commands/self/conftest.py
index 19a2242ea90..14554efe924 100644
--- a/tests/console/commands/self/conftest.py
+++ b/tests/console/commands/self/conftest.py
@@ -74,7 +74,6 @@ def setup_mocks(
     mocker.patch(
         "poetry.repositories.repository_pool.RepositoryPool.package", pool.package
     )
-    mocker.patch("poetry.installation.executor.pip_install")
     mocker.patch(
         "poetry.installation.installer.Installer._get_installed",
         return_value=installed,
diff --git a/tests/console/commands/test_config.py b/tests/console/commands/test_config.py
index 218d47f8032..305007984fe 100644
--- a/tests/console/commands/test_config.py
+++ b/tests/console/commands/test_config.py
@@ -56,7 +56,6 @@ def test_list_displays_default_value_if_not_set(
     expected = f"""cache-dir = {cache_dir}
 experimental.system-git-client = false
 installer.max-workers = null
-installer.modern-installation = true
 installer.no-binary = null
 installer.only-binary = null
 installer.parallel = true
@@ -89,7 +88,6 @@ def test_list_displays_set_get_setting(
     expected = f"""cache-dir = {cache_dir}
 experimental.system-git-client = false
 installer.max-workers = null
-installer.modern-installation = true
 installer.no-binary = null
 installer.only-binary = null
 installer.parallel = true
@@ -143,7 +141,6 @@ def test_unset_setting(
     expected = f"""cache-dir = {cache_dir}
 experimental.system-git-client = false
 installer.max-workers = null
-installer.modern-installation = true
 installer.no-binary = null
 installer.only-binary = null
 installer.parallel = true
@@ -175,7 +172,6 @@ def test_unset_repo_setting(
     expected = f"""cache-dir = {cache_dir}
 experimental.system-git-client = false
 installer.max-workers = null
-installer.modern-installation = true
 installer.no-binary = null
 installer.only-binary = null
 installer.parallel = true
@@ -305,7 +301,6 @@ def test_list_displays_set_get_local_setting(
     expected = f"""cache-dir = {cache_dir}
 experimental.system-git-client = false
 installer.max-workers = null
-installer.modern-installation = true
 installer.no-binary = null
 installer.only-binary = null
 installer.parallel = true
@@ -345,7 +340,6 @@ def test_list_must_not_display_sources_from_pyproject_toml(
     expected = f"""cache-dir = {cache_dir}
 experimental.system-git-client = false
 installer.max-workers = null
-installer.modern-installation = true
 installer.no-binary = null
 installer.only-binary = null
 installer.parallel = true
diff --git a/tests/installation/test_executor.py b/tests/installation/test_executor.py
index e755a03e369..b54bcdaf022 100644
--- a/tests/installation/test_executor.py
+++ b/tests/installation/test_executor.py
@@ -1151,70 +1151,6 @@ def test_executor_should_be_initialized_with_correct_workers(
     assert executor._max_workers == expected_workers
 
 
-def test_executor_fallback_on_poetry_create_error_without_wheel_installer(
-    mocker: MockerFixture,
-    config: Config,
-    pool: RepositoryPool,
-    io: BufferedIO,
-    tmp_path: Path,
-    env: MockEnv,
-    fixture_dir: FixtureDirGetter,
-) -> None:
-    mock_pip_install = mocker.patch("poetry.installation.executor.pip_install")
-    mock_sdist_builder = mocker.patch("poetry.core.masonry.builders.sdist.SdistBuilder")
-    mock_editable_builder = mocker.patch(
-        "poetry.masonry.builders.editable.EditableBuilder"
-    )
-    mock_create_poetry = mocker.patch(
-        "poetry.factory.Factory.create_poetry", side_effect=RuntimeError
-    )
-
-    config.merge(
-        {
-            "cache-dir": str(tmp_path),
-            "installer": {"modern-installation": False},
-        }
-    )
-
-    executor = Executor(env, pool, config, io)
-    warning_lines = io.fetch_output().splitlines()
-    assert warning_lines == [
-        "Warning: Setting `installer.modern-installation` to `false` is deprecated.",
-        "The pip-based installer will be removed in a future release.",
-        "See https://github.com/python-poetry/poetry/issues/8987.",
-    ]
-
-    directory_package = Package(
-        "simple-project",
-        "1.2.3",
-        source_type="directory",
-        source_url=fixture_dir("simple_project").resolve().as_posix(),
-    )
-
-    return_code = executor.execute(
-        [
-            Install(directory_package),
-        ]
-    )
-
-    expected = f"""
-Package operations: 1 install, 0 updates, 0 removals
-
-  - Installing simple-project (1.2.3 {directory_package.source_url})
-"""
-
-    expected_lines = set(expected.splitlines())
-    output_lines = set(io.fetch_output().splitlines())
-    assert output_lines == expected_lines
-    assert return_code == 0
-    assert mock_create_poetry.call_count == 1
-    assert mock_sdist_builder.call_count == 0
-    assert mock_editable_builder.call_count == 0
-    assert mock_pip_install.call_count == 1
-    assert mock_pip_install.call_args[1].get("upgrade") is True
-    assert mock_pip_install.call_args[1].get("editable") is False
-
-
 @pytest.mark.parametrize("failing_method", ["build", "get_requires_for_build"])
 @pytest.mark.parametrize(
     "exception",
