diff --git a/news/6434.feature b/news/6434.feature new file mode 100644 index 000000000..958d75165 --- /dev/null +++ b/news/6434.feature @@ -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 +`_ 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. diff --git a/src/pip/_internal/pyproject.py b/src/pip/_internal/pyproject.py index 13a8f35a9..2e76c399a 100644 --- a/src/pip/_internal/pyproject.py +++ b/src/pip/_internal/pyproject.py @@ -1,6 +1,7 @@ from __future__ import absolute_import import io +import logging import os import sys @@ -15,6 +16,9 @@ if MYPY_CHECK_RUNNING: Pep517Data = Tuple[str, List[str]] +logger = logging.getLogger(__name__) + + def _is_list_of_str(obj): # type: (Any) -> bool return ( @@ -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: " @@ -145,7 +153,36 @@ 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 {} " @@ -153,18 +190,8 @@ def resolve_pyproject_toml( 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 diff --git a/tests/unit/test_pep517.py b/tests/unit/test_pep517.py index d539d7b20..83787d56c 100644 --- a/tests/unit/test_pep517.py +++ b/tests/unit/test_pep517.py @@ -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'), @@ -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', [