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

Deprecate setup.py install fallback when wheel package is absent #11331

Merged
merged 4 commits into from
Aug 10, 2022
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
2 changes: 2 additions & 0 deletions news/8559.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Deprecate installation with 'setup.py install' when the 'wheel' package is absent for
source distributions without 'pyproject.toml'.
3 changes: 2 additions & 1 deletion src/pip/_internal/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from pip._internal.req import install_given_reqs
from pip._internal.req.req_install import InstallRequirement
from pip._internal.utils.compat import WINDOWS
from pip._internal.utils.deprecation import LegacyInstallReasonFailedBdistWheel
from pip._internal.utils.distutils_args import parse_distutils_args
from pip._internal.utils.filesystem import test_writable_dir
from pip._internal.utils.logging import getLogger
Expand Down Expand Up @@ -440,7 +441,7 @@ def run(self, options: Values, args: List[str]) -> int:
# those.
for r in build_failures:
if not r.use_pep517:
r.legacy_install_reason = 8368
r.legacy_install_reason = LegacyInstallReasonFailedBdistWheel

to_install = resolver.get_installation_order(requirement_set)

Expand Down
27 changes: 13 additions & 14 deletions src/pip/_internal/req/req_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
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 deprecated
from pip._internal.utils.deprecation import LegacyInstallReason, deprecated
from pip._internal.utils.direct_url_helpers import (
direct_url_for_editable,
direct_url_from_link,
Expand Down Expand Up @@ -96,7 +96,7 @@ def __init__(
self.constraint = constraint
self.editable = editable
self.permit_editable_wheels = permit_editable_wheels
self.legacy_install_reason: Optional[int] = None
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 @@ -811,6 +811,11 @@ def install(
install_options = list(install_options) + self.install_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(
install_options=install_options,
global_options=global_options,
Expand All @@ -836,18 +841,12 @@ def install(

self.install_succeeded = success

if success and self.legacy_install_reason == 8368:
deprecated(
reason=(
"{} was installed using the legacy 'setup.py install' "
"method, because a wheel could not be built for it.".format(
self.name
)
),
replacement="to fix the wheel build issue reported above",
gone_in=None,
issue=8368,
)
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)


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

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


class LegacyInstallReason:
def __init__(
self,
reason: str,
replacement: Optional[str],
gone_in: Optional[str],
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=None,
issue=8368,
emit_after_success=True,
)


LegacyInstallReasonMissingWheelPackage = LegacyInstallReason(
reason=(
"{name} is being installed using the legacy "
"'setup.py install' method, because it does not have a "
"'pyproject.toml' and the 'wheel' package "
"is not installed."
),
replacement="to enable the '--use-pep517' option",
gone_in=None,
issue=8559,
emit_before_install=True,
)
7 changes: 2 additions & 5 deletions src/pip/_internal/wheel_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from pip._internal.operations.build.wheel_editable import build_wheel_editable
from pip._internal.operations.build.wheel_legacy import build_wheel_legacy
from pip._internal.req.req_install import InstallRequirement
from pip._internal.utils.deprecation import LegacyInstallReasonMissingWheelPackage
from pip._internal.utils.logging import indent_log
from pip._internal.utils.misc import ensure_dir, hash_file, is_wheel_installed
from pip._internal.utils.setuptools_build import make_setuptools_clean_args
Expand Down Expand Up @@ -86,11 +87,7 @@ def _should_build(

if not is_wheel_installed():
# we don't build legacy requirements if wheel is not installed
logger.info(
"Using legacy 'setup.py install' for %s, "
"since package 'wheel' is not installed.",
req.name,
)
req.legacy_install_reason = LegacyInstallReasonMissingWheelPackage
return False

return True
Expand Down
30 changes: 30 additions & 0 deletions tests/functional/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from pip._internal.cli.status_codes import ERROR, SUCCESS
from pip._internal.models.index import PyPI, TestPyPI
from pip._internal.utils.deprecation import DEPRECATION_MSG_PREFIX
from pip._internal.utils.misc import rmtree
from tests.conftest import CertFactory
from tests.lib import (
Expand Down Expand Up @@ -2286,3 +2287,32 @@ def test_install_dry_run(script: PipTestEnvironment, data: TestData) -> None:
)
assert "Would install simple-3.0" in result.stdout
assert "Successfully installed" not in result.stdout


def test_install_8559_missing_wheel_package(
script: PipTestEnvironment, shared_data: TestData
) -> None:
result = script.pip(
"install",
"--find-links",
shared_data.find_links,
"simple",
allow_stderr_warning=True,
)
assert DEPRECATION_MSG_PREFIX in result.stderr
assert "'wheel' package is not installed" in result.stderr
assert "using the legacy 'setup.py install' method" in result.stderr


@pytest.mark.usefixtures("with_wheel")
def test_install_8559_wheel_package_present(
script: PipTestEnvironment, shared_data: TestData
) -> None:
result = script.pip(
"install",
"--find-links",
shared_data.find_links,
"simple",
allow_stderr_warning=False,
)
assert DEPRECATION_MSG_PREFIX not in result.stderr
1 change: 1 addition & 0 deletions tests/functional/test_install_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def test_find_links_relative_path(script: PipTestEnvironment, data: TestData) ->
result.did_create(initools_folder)


@pytest.mark.usefixtures("with_wheel")
def test_find_links_no_doctype(script: PipTestEnvironment, data: TestData) -> None:
shutil.copy(data.packages / "simple-1.0.tar.gz", script.scratch_path)
html = script.scratch_path.joinpath("index.html")
Expand Down