Skip to content

Commit

Permalink
remove pip-based installer (python-poetry#9392)
Browse files Browse the repository at this point in the history
  • Loading branch information
dimbleby committed Jul 21, 2024
1 parent a74d3a7 commit 2e3a421
Show file tree
Hide file tree
Showing 9 changed files with 1 addition and 209 deletions.
6 changes: 0 additions & 6 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
15 changes: 0 additions & 15 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
2 changes: 0 additions & 2 deletions src/poetry/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ class Config:
"system-git-client": False,
},
"installer": {
"modern-installation": True,
"parallel": True,
"max-workers": None,
"no-binary": None,
Expand Down Expand Up @@ -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",
Expand Down
1 change: 0 additions & 1 deletion src/poetry/console/commands/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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": (
Expand Down
4 changes: 1 addition & 3 deletions src/poetry/console/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
),
]

Expand Down
111 changes: 0 additions & 111 deletions src/poetry/installation/executor.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import contextlib
import csv
import functools
import itertools
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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":
Expand All @@ -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
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion tests/console/commands/self/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 0 additions & 6 deletions tests/console/commands/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
64 changes: 0 additions & 64 deletions tests/installation/test_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 2e3a421

Please sign in to comment.