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

Drop setup.py install support #11874

Merged
merged 6 commits into from
Mar 31, 2023
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
9 changes: 0 additions & 9 deletions docs/html/reference/build-system/setup-py.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ The overall process for building a package is:

- Generate the package's metadata.
- Generate a wheel for the package.
- If this fails and we're trying to install the package, attempt a direct
installation.

The wheel can then be used to perform an installation, if necessary.

Expand Down Expand Up @@ -58,13 +56,6 @@ If this wheel generation fails, pip runs `setup.py clean` to clean up any build
artifacts that may have been generated. After that, pip will attempt a direct
installation.

### Direct Installation

When all else fails, pip will invoke `setup.py install` to install a package
using setuptools' mechanisms to perform the installation. This is currently the
last-resort fallback for projects that cannot be built into wheels, and may not
be supported in the future.

### Editable Installation

For installing packages in "editable" mode
Expand Down
2 changes: 2 additions & 0 deletions news/8368.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Remove ``setup.py install`` fallback when building a wheel failed for projects without
``pyproject.toml``.
17 changes: 2 additions & 15 deletions src/pip/_internal/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
check_legacy_setup_py_options,
)
from pip._internal.utils.compat import WINDOWS
from pip._internal.utils.deprecation import LegacyInstallReasonFailedBdistWheel
from pip._internal.utils.filesystem import test_writable_dir
from pip._internal.utils.logging import getLogger
from pip._internal.utils.misc import (
Expand Down Expand Up @@ -423,26 +422,14 @@ def run(self, options: Values, args: List[str]) -> int:
global_options=global_options,
)

# If we're using PEP 517, we cannot do a legacy setup.py install
# so we fail here.
pep517_build_failure_names: List[str] = [
r.name for r in build_failures if r.use_pep517 # type: ignore
]
if pep517_build_failure_names:
if build_failures:
raise InstallationError(
"Could not build wheels for {}, which is required to "
"install pyproject.toml-based projects".format(
", ".join(pep517_build_failure_names)
", ".join(r.name for r in build_failures) # type: ignore
)
)

# For now, we just warn about failures building legacy
# requirements, as we'll fall through to a setup.py install for
# those.
for r in build_failures:
if not r.use_pep517:
r.legacy_install_reason = LegacyInstallReasonFailedBdistWheel

to_install = resolver.get_installation_order(requirement_set)

# Check for conflicts in the package set we're installing.
Expand Down
14 changes: 0 additions & 14 deletions src/pip/_internal/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,20 +361,6 @@ def __str__(self) -> str:
)


class LegacyInstallFailure(DiagnosticPipError):
"""Error occurred while executing `setup.py install`"""

reference = "legacy-install-failure"

def __init__(self, package_details: str) -> None:
super().__init__(
message="Encountered error while trying to install package.",
context=package_details,
hint_stmt="See above for output from the failure.",
note_stmt="This is an issue with the package mentioned above, not pip.",
)


class InstallationSubprocessError(DiagnosticPipError, InstallationError):
"""A subprocess call failed."""

Expand Down
117 changes: 0 additions & 117 deletions src/pip/_internal/operations/install/legacy.py

This file was deleted.

81 changes: 16 additions & 65 deletions src/pip/_internal/req/req_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from pip._vendor.pyproject_hooks import BuildBackendHookCaller

from pip._internal.build_env import BuildEnvironment, NoOpBuildEnvironment
from pip._internal.exceptions import InstallationError, LegacyInstallFailure
from pip._internal.exceptions import InstallationError
from pip._internal.locations import get_scheme
from pip._internal.metadata import (
BaseDistribution,
Expand All @@ -39,11 +39,10 @@
from pip._internal.operations.install.editable_legacy import (
install_editable as install_editable_legacy,
)
from pip._internal.operations.install.legacy import install as install_legacy
from pip._internal.operations.install.wheel import install_wheel
from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path
from pip._internal.req.req_uninstall import UninstallPathSet
from pip._internal.utils.deprecation import LegacyInstallReason, deprecated
from pip._internal.utils.deprecation import deprecated
from pip._internal.utils.hashes import Hashes
from pip._internal.utils.misc import (
ConfiguredBuildBackendHookCaller,
Expand Down Expand Up @@ -93,7 +92,6 @@ def __init__(
self.constraint = constraint
self.editable = editable
self.permit_editable_wheels = permit_editable_wheels
self.legacy_install_reason: Optional[LegacyInstallReason] = None

# source_dir is the local directory where the linked requirement is
# located, or unpacked. In case unpacking is needed, creating and
Expand Down Expand Up @@ -757,10 +755,9 @@ def install(
prefix=prefix,
)

global_options = global_options if global_options is not None else []
if self.editable and not self.is_wheel:
install_editable_legacy(
global_options=global_options,
global_options=global_options if global_options is not None else [],
Comment on lines -763 to +760
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this change needed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cosmetics only. Since the variable is not used anywhere else, I figured I'd inline it.

prefix=prefix,
home=home,
use_user_site=use_user_site,
Expand All @@ -773,66 +770,20 @@ def install(
self.install_succeeded = True
return

if self.is_wheel:
assert self.local_file_path
install_wheel(
self.name,
self.local_file_path,
scheme=scheme,
req_description=str(self.req),
pycompile=pycompile,
warn_script_location=warn_script_location,
direct_url=self.download_info if self.original_link else None,
requested=self.user_supplied,
)
self.install_succeeded = True
return

# TODO: Why don't we do this for editable installs?

# Extend the list of global options passed on to
# the setup.py call with the ones from the requirements file.
# Options specified in requirements file override those
# specified on the command line, since the last option given
# to setup.py is the one that is used.
global_options = list(global_options) + self.global_options

try:
if (
self.legacy_install_reason is not None
and self.legacy_install_reason.emit_before_install
):
self.legacy_install_reason.emit_deprecation(self.name)
success = install_legacy(
global_options=global_options,
root=root,
home=home,
prefix=prefix,
use_user_site=use_user_site,
pycompile=pycompile,
scheme=scheme,
setup_py_path=self.setup_py_path,
isolated=self.isolated,
req_name=self.name,
build_env=self.build_env,
unpacked_source_directory=self.unpacked_source_directory,
req_description=str(self.req),
)
except LegacyInstallFailure as exc:
self.install_succeeded = False
raise exc
except Exception:
self.install_succeeded = True
raise
assert self.is_wheel
assert self.local_file_path

self.install_succeeded = success

if (
success
and self.legacy_install_reason is not None
and self.legacy_install_reason.emit_after_success
):
self.legacy_install_reason.emit_deprecation(self.name)
install_wheel(
self.name,
self.local_file_path,
scheme=scheme,
req_description=str(self.req),
pycompile=pycompile,
warn_script_location=warn_script_location,
direct_url=self.download_info if self.original_link else None,
requested=self.user_supplied,
)
self.install_succeeded = True


def check_invalid_constraint_type(req: InstallRequirement) -> str:
Expand Down
41 changes: 0 additions & 41 deletions src/pip/_internal/utils/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,44 +118,3 @@ def deprecated(
raise PipDeprecationWarning(message)

warnings.warn(message, category=PipDeprecationWarning, stacklevel=2)


class LegacyInstallReason:
def __init__(
self,
reason: str,
replacement: Optional[str] = None,
gone_in: Optional[str] = None,
feature_flag: Optional[str] = None,
issue: Optional[int] = None,
emit_after_success: bool = False,
emit_before_install: bool = False,
):
self._reason = reason
self._replacement = replacement
self._gone_in = gone_in
self._feature_flag = feature_flag
self._issue = issue
self.emit_after_success = emit_after_success
self.emit_before_install = emit_before_install

def emit_deprecation(self, name: str) -> None:
deprecated(
reason=self._reason.format(name=name),
replacement=self._replacement,
gone_in=self._gone_in,
feature_flag=self._feature_flag,
issue=self._issue,
)


LegacyInstallReasonFailedBdistWheel = LegacyInstallReason(
reason=(
"{name} was installed using the legacy 'setup.py install' "
"method, because a wheel could not be built for it."
),
replacement="to fix the wheel build issue reported above",
gone_in="23.1",
issue=8368,
emit_after_success=True,
)
Loading