diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py index 0a2e828f1..32b7d5668 100755 --- a/piptools/scripts/compile.py +++ b/piptools/scripts/compile.py @@ -6,8 +6,9 @@ from typing import IO, Any, BinaryIO, List, Optional, Tuple, Union, cast import click +from build import BuildBackendException +from build.util import project_wheel_metadata from click.utils import LazyFile, safecall -from pep517 import meta from pip._internal.commands import create_command from pip._internal.req import InstallRequirement from pip._internal.req.constructors import install_req_from_line @@ -405,12 +406,19 @@ def cli( constraints.extend(reqs) elif is_setup_file: setup_file_found = True - dist = meta.load(os.path.dirname(os.path.abspath(src_file))) - comes_from = f"{dist.metadata.get_all('Name')[0]} ({src_file})" + try: + metadata = project_wheel_metadata( + os.path.dirname(os.path.abspath(src_file)) + ) + except BuildBackendException as e: + log.error(str(e)) + log.error(f"Failed to parse {os.path.abspath(src_file)}") + sys.exit(2) + comes_from = f"{metadata.get_all('Name')[0]} ({src_file})" constraints.extend( [ install_req_from_line(req, comes_from=comes_from) - for req in dist.requires or [] + for req in metadata.get_all("Requires-Dist") or [] ] ) else: diff --git a/setup.cfg b/setup.cfg index 9e9215efe..5d840582f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,8 +30,8 @@ packages = find: zip_safe = false install_requires = # direct dependencies + build click >= 7 - pep517 pip >= 21.2 # indirect dependencies setuptools # typically needed when pip-tools invokes setup.py diff --git a/tests/conftest.py b/tests/conftest.py index 3e59b86c6..8e868cccd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -349,6 +349,18 @@ def _make_module(fname, content): path = os.path.join(tmpdir, "sample_lib", "__init__.py") with open(path, "w") as stream: stream.write("'example module'\n__version__ = '1.2.3'") + if fname == "setup.cfg": + path = os.path.join(tmpdir, "pyproject.toml") + with open(path, "w") as stream: + stream.write( + "\n".join( + ( + "[build-system]", + 'requires = ["setuptools"]', + 'build-backend = "setuptools.build_meta"', + ) + ) + ) path = os.path.join(tmpdir, fname) with open(path, "w") as stream: stream.write(dedent(content)) diff --git a/tests/test_cli_compile.py b/tests/test_cli_compile.py index 8917d9f02..4e95f61a2 100644 --- a/tests/test_cli_compile.py +++ b/tests/test_cli_compile.py @@ -12,9 +12,6 @@ from .constants import MINIMAL_WHEELS_PATH, PACKAGES_PATH -is_pypy = "__pypy__" in sys.builtin_module_names -is_windows = sys.platform == "win32" - @pytest.fixture(autouse=True) def _temp_dep_cache(tmpdir, monkeypatch): @@ -349,9 +346,6 @@ def test_emit_index_url_option(runner, option, expected_output): @pytest.mark.network -@pytest.mark.xfail( - is_pypy and is_windows, reason="https://github.com/jazzband/pip-tools/issues/1148" -) def test_realistic_complex_sub_dependencies(runner): wheels_dir = "wheels" @@ -1017,6 +1011,16 @@ def test_filter_pip_markers(pip_conf, runner): assert "unknown_package" not in out.stderr +def test_bad_setup_file(runner): + with open("setup.py", "w") as package: + package.write("BAD SYNTAX") + + out = runner.invoke(cli, []) + + assert out.exit_code == 2 + assert f"Failed to parse {os.path.abspath('setup.py')}" in out.stderr + + def test_no_candidates(pip_conf, runner): with open("requirements", "w") as req_in: req_in.write("small-fake-a>0.3b1,<0.3b2") @@ -2027,7 +2031,6 @@ def test_triple_equal_pinned_dependency_is_used( @pytest.mark.network @pytest.mark.parametrize(("fname", "content"), METADATA_TEST_CASES) -@pytest.mark.xfail(is_pypy, reason="https://github.com/jazzband/pip-tools/issues/1375") def test_input_formats(fake_dists, runner, make_module, fname, content): """ Test different dependency formats as input file. @@ -2046,7 +2049,6 @@ def test_input_formats(fake_dists, runner, make_module, fname, content): @pytest.mark.network @pytest.mark.parametrize(("fname", "content"), METADATA_TEST_CASES) -@pytest.mark.xfail(is_pypy, reason="https://github.com/jazzband/pip-tools/issues/1375") def test_one_extra(fake_dists, runner, make_module, fname, content): """ Test one `--extra` (dev) passed, other extras (test) must be ignored. @@ -2074,7 +2076,6 @@ def test_one_extra(fake_dists, runner, make_module, fname, content): ), ) @pytest.mark.parametrize(("fname", "content"), METADATA_TEST_CASES) -@pytest.mark.xfail(is_pypy, reason="https://github.com/jazzband/pip-tools/issues/1375") def test_multiple_extras(fake_dists, runner, make_module, fname, content, extra_opts): """ Test passing multiple `--extra` params.