From 77f7ce4f542717ce64d1dfa3682af16958dc9ec9 Mon Sep 17 00:00:00 2001 From: Andy Kluger Date: Wed, 25 May 2022 13:01:41 -0400 Subject: [PATCH 1/6] Replace use of pep517 directly with build The build module is better supported at this time and going forward --- piptools/scripts/compile.py | 10 ++++++---- setup.cfg | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py index 0a2e828f1..224bfdc0c 100755 --- a/piptools/scripts/compile.py +++ b/piptools/scripts/compile.py @@ -6,8 +6,8 @@ from typing import IO, Any, BinaryIO, List, Optional, Tuple, Union, cast import click +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 +405,14 @@ 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})" + metadata = project_wheel_metadata( + os.path.dirname(os.path.abspath(src_file)) + ) + 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 From 0869c09048e4c4ac78d1a734e9eb2692d26db3c0 Mon Sep 17 00:00:00 2001 From: Andy Kluger Date: Wed, 25 May 2022 13:53:24 -0400 Subject: [PATCH 2/6] make_module: Add minimal pyproject.toml when otherwise setup.cfg-only From the `build` changelog: > ... projects not containing either a `pyproject.toml` or `setup.py` will be reported as invalid. This affects projects specifying only a `setup.cfg`, such projects are recommended to add a `pyproject.toml`. --- tests/conftest.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 09750512e..0c64978a7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -337,6 +337,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)) From dbfb66d79be57520300ee01f43f6d745781be4ed Mon Sep 17 00:00:00 2001 From: Andy Kluger Date: Wed, 25 May 2022 14:21:53 -0400 Subject: [PATCH 3/6] Expect success for pypy tests affected by #1375 --- tests/test_cli_compile.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_cli_compile.py b/tests/test_cli_compile.py index cb3ce1f6b..a693677b3 100644 --- a/tests/test_cli_compile.py +++ b/tests/test_cli_compile.py @@ -2027,7 +2027,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 +2045,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 +2072,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. From 084d2bcd89e9bf7b66b3be6c27214ec02da18078 Mon Sep 17 00:00:00 2001 From: Andy Kluger Date: Wed, 25 May 2022 14:23:48 -0400 Subject: [PATCH 4/6] Expect success for pypy test affected by #1148 --- tests/test_cli_compile.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/test_cli_compile.py b/tests/test_cli_compile.py index a693677b3..30a641701 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" From bbf51216de06c7da2f5093efcbdb15aa95e2d895 Mon Sep 17 00:00:00 2001 From: Andy Kluger Date: Wed, 25 May 2022 16:35:35 -0400 Subject: [PATCH 5/6] Catch BuildBackendException; plainly report error --- piptools/scripts/compile.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py index 224bfdc0c..32b7d5668 100755 --- a/piptools/scripts/compile.py +++ b/piptools/scripts/compile.py @@ -6,6 +6,7 @@ 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 pip._internal.commands import create_command @@ -405,9 +406,14 @@ def cli( constraints.extend(reqs) elif is_setup_file: setup_file_found = True - metadata = project_wheel_metadata( - os.path.dirname(os.path.abspath(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( [ From e3b29a85cc1031b275ad01790df8b90416333d4d Mon Sep 17 00:00:00 2001 From: Andy Kluger Date: Sun, 29 May 2022 13:20:24 -0400 Subject: [PATCH 6/6] Add test: invalid setup.py parse failure handling --- tests/test_cli_compile.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_cli_compile.py b/tests/test_cli_compile.py index 30a641701..f28724c04 100644 --- a/tests/test_cli_compile.py +++ b/tests/test_cli_compile.py @@ -1011,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")