Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove pip-based installer #9392

Merged
merged 2 commits into from
Jul 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading