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

Permit --no-use-pep517 with editable mode in more cases. #6442

Merged
merged 1 commit into from
Apr 25, 2019
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
7 changes: 7 additions & 0 deletions news/6434.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Allow ``--no-use-pep517`` to be used as a work-around when installing a
project in editable mode, even when `PEP 517
<https://www.python.org/dev/peps/pep-0517/>`_ mandates
``pyproject.toml``-style processing (i.e. when the project has a
``pyproject.toml`` file as well as a ``"build-backend"`` key for the
``"build_system"`` value). Since this option conflicts with the PEP 517 spec,
this mode of operation is officially unsupported.
55 changes: 41 additions & 14 deletions src/pip/_internal/pyproject.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import absolute_import

import io
import logging
import os
import sys

Expand All @@ -15,6 +16,9 @@
Pep517Data = Tuple[str, List[str]]


logger = logging.getLogger(__name__)


def _is_list_of_str(obj):
# type: (Any) -> bool
return (
Expand Down Expand Up @@ -133,7 +137,11 @@ def resolve_pyproject_toml(
# opposed to False can occur when the value is provided via an
# environment variable or config file option (due to the quirk of
# strtobool() returning an integer in pip's configuration code).
if has_pyproject and not has_setup:
if editable and use_pep517:
raise make_editable_error(
req_name, 'PEP 517 processing was explicitly requested'
)
elif has_pyproject and not has_setup:
if use_pep517 is not None and not use_pep517:
raise InstallationError(
"Disabling PEP 517 processing is invalid: "
Expand All @@ -145,26 +153,45 @@ def resolve_pyproject_toml(
)
use_pep517 = True
elif build_system and "build-backend" in build_system:
if use_pep517 is not None and not use_pep517:
if editable:
if use_pep517 is None:
message = (
'Error installing {!r}: editable mode is not supported '
'for pyproject.toml-style projects. '
'This project is pyproject.toml-style because it has a '
'pyproject.toml file and a "build-backend" key for the '
'"build_system" value, but editable mode is undefined '
'for pyproject.toml-style projects. '
'Since the project has a setup.py, you may pass '
'--no-use-pep517 to opt out of pyproject.toml-style '
'processing. However, this is an unsupported combination. '
'See PEP 517 for details on pyproject.toml-style projects.'
).format(req_name)
raise InstallationError(message)

# The case of `editable and use_pep517` being true was already
# handled above.
assert not use_pep517
message = (
'Installing {!r} in editable mode, which is not supported '
'for pyproject.toml-style projects: '
'this project is pyproject.toml-style because it has a '
'pyproject.toml file and a "build-backend" key for the '
'"build_system" value, but editable mode is undefined '
'for pyproject.toml-style projects. '
'See PEP 517 for details on pyproject.toml-style projects.'
).format(req_name)
logger.warning(message)
elif use_pep517 is not None and not use_pep517:
raise InstallationError(
"Disabling PEP 517 processing is invalid: "
"project specifies a build backend of {} "
"in pyproject.toml".format(
build_system["build-backend"]
)
)
if editable:
reason = (
'it has a pyproject.toml file with a "build-backend" key '
'in the "build_system" value'
)
raise make_editable_error(req_name, reason)
use_pep517 = True
elif use_pep517:
if editable:
raise make_editable_error(
req_name, 'PEP 517 processing was explicitly requested'
)
else:
use_pep517 = True

# If we haven't worked out whether to use PEP 517 yet, and the user
# hasn't explicitly stated a preference, we do so if the project has
Expand Down
52 changes: 49 additions & 3 deletions tests/unit/test_pep517.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,6 @@ def test_resolve_pyproject_toml__editable_without_use_pep517_false():
'has_pyproject, has_setup, use_pep517, build_system, expected_err', [
# Test pyproject.toml with no setup.py.
(True, False, None, None, 'has a pyproject.toml file and no setup.py'),
# Test "build-backend" present.
(True, True, None, {'build-backend': 'foo'},
'has a pyproject.toml file with a "build-backend" key'),
# Test explicitly requesting PEP 517 processing.
(True, True, True, None,
'PEP 517 processing was explicitly requested'),
Expand Down Expand Up @@ -115,6 +112,55 @@ def test_resolve_pyproject_toml__editable_and_pep_517_required(
)


def test_resolve_pyproject_toml__editable_build_backend_use_pep517_none():
"""
Test editable=True with "build-backend" and use_pep517=None.
"""
expected_start = (
"Error installing 'my-package': editable mode is not supported "
)
expected_substr = 'you may pass --no-use-pep517 to opt out'

with assert_error_startswith(
InstallationError, expected_start, expected_substr=expected_substr,
):
resolve_pyproject_toml(
build_system={'requires': ['my-package'], 'build-backend': 'foo'},
has_pyproject=True,
has_setup=True,
use_pep517=None,
editable=True,
req_name='my-package',
)


def test_resolve_pyproject_toml__editable_build_backend_use_pep517_false(
caplog
):
"""
Test editable=True with "build-backend" and use_pep517=False.
"""
resolve_pyproject_toml(
build_system={'requires': ['my-package'], 'build-backend': 'foo'},
has_pyproject=True,
has_setup=True,
use_pep517=False,
editable=True,
req_name='my-package',
)

records = caplog.records
assert len(records) == 1
record = records[0]
assert record.levelname == 'WARNING'
expected_start = (
"Installing 'my-package' in editable mode, which is not supported "
)
assert record.message.startswith(expected_start), (
'full message: {}'.format(record.message)
)


@pytest.mark.parametrize(
'has_pyproject, has_setup, use_pep517, editable, build_system, '
'expected_err', [
Expand Down