import os from pathlib import Path from textwrap import dedent import pytest from pip._internal.exceptions import InstallationError, InvalidPyProjectBuildRequires from pip._internal.req import InstallRequirement from tests.lib import TestData @pytest.mark.parametrize( ("source", "expected"), [ ("pep517_setup_and_pyproject", True), ("pep517_setup_only", False), ("pep517_pyproject_only", True), ], ) def test_use_pep517(shared_data: TestData, source: str, expected: bool) -> None: """ Test that we choose correctly between PEP 517 and legacy code paths """ src = shared_data.src.joinpath(source) req = InstallRequirement(None, None) req.source_dir = os.fspath(src) # make req believe it has been unpacked req.load_pyproject_toml() assert req.use_pep517 is expected def test_use_pep517_rejects_setup_cfg_only(shared_data: TestData) -> None: """ Test that projects with setup.cfg but no pyproject.toml are rejected. """ src = shared_data.src.joinpath("pep517_setup_cfg_only") req = InstallRequirement(None, None) req.source_dir = os.fspath(src) # make req believe it has been unpacked with pytest.raises(InstallationError) as e: req.load_pyproject_toml() err_msg = e.value.args[0] assert ( "does not appear to be a Python project: " "neither 'setup.py' nor 'pyproject.toml' found" in err_msg ) @pytest.mark.parametrize( ("source", "msg"), [ ("pep517_setup_and_pyproject", "specifies a build backend"), ("pep517_pyproject_only", "does not have a setup.py"), ], ) def test_disabling_pep517_invalid(shared_data: TestData, source: str, msg: str) -> None: """ Test that we fail if we try to disable PEP 517 when it's not acceptable """ src = shared_data.src.joinpath(source) req = InstallRequirement(None, None) req.source_dir = os.fspath(src) # make req believe it has been unpacked # Simulate --no-use-pep517 req.use_pep517 = False with pytest.raises(InstallationError) as e: req.load_pyproject_toml() err_msg = e.value.args[0] assert "Disabling PEP 517 processing is invalid" in err_msg assert msg in err_msg @pytest.mark.parametrize( ("spec",), [("./foo",), ("git+https://example.com/pkg@dev#egg=myproj",)] ) def test_pep517_parsing_checks_requirements(tmpdir: Path, spec: str) -> None: tmpdir.joinpath("pyproject.toml").write_text( dedent( f""" [build-system] requires = [{spec!r}] build-backend = "foo" """ ) ) req = InstallRequirement(None, None) req.source_dir = os.fspath(tmpdir) # make req believe it has been unpacked with pytest.raises(InvalidPyProjectBuildRequires) as e: req.load_pyproject_toml() error = e.value assert str(req) in error.message assert error.context assert "build-system.requires" in error.context assert "contains an invalid requirement" in error.context assert error.hint_stmt assert "PEP 518" in error.hint_stmt