From 2e3a42174ce247a9b18250f4ad683e77ba1b1579 Mon Sep 17 00:00:00 2001 From: David Hotham Date: Sun, 21 Jul 2024 19:17:05 +0100 Subject: [PATCH] remove pip-based installer (#9392) --- 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 4d64337290c..a3824761225 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: Setting `installer.modern-installation` to `false` " - "is deprecated." - ) - self._io.write_line( - "The pip-based installer will be removed in a future release." - ) - self._io.write_line( - "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" - {operation_message}:" - " Building..." - ) - 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",