Skip to content

Commit d33539c

Browse files
authored
Merge pull request #2253 from shifqu/fix/remove-opt-pep517
Implement compatibility with pip 25.3
2 parents e94b3f5 + 43e1159 commit d33539c

File tree

11 files changed

+162
-15
lines changed

11 files changed

+162
-15
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ jobs:
124124
#
125125
# Ref: https://github.com/tox-dev/tox/issues/3193
126126
run: tox -vv --notest -p auto --parallel-live
127+
- name: Set PYTEST_ADDOPTS for py38
128+
if: matrix.python-version == '3.8'
129+
shell: bash
130+
run: |
131+
echo "PYTEST_ADDOPTS=--cov-fail-under=98" >> $GITHUB_ENV
127132
- name: Test pip ${{ matrix.pip-version }}
128133
# NOTE: `--parallel-live` is a workaround for the regression in
129134
# NOTE: the upstream tox project that made the

changelog.d/2252.feature.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pip-tools is now compatible with pip 25.3 -- by {user}`shifqu`.

changelog.d/2253.feature.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2252.feature.md

piptools/resolver.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from .exceptions import PipToolsError
3131
from .logging import log
3232
from .utils import (
33+
PIP_VERSION,
3334
UNSAFE_PACKAGES,
3435
as_tuple,
3536
copy_install_requirement,
@@ -605,6 +606,11 @@ def resolve(self, max_rounds: int = 10) -> set[InstallRequirement]:
605606
}
606607
preparer = self.command.make_requirement_preparer(**preparer_kwargs)
607608

609+
extra_resolver_kwargs = {}
610+
if PIP_VERSION[:2] < (25, 3): # pragma: <3.9 cover
611+
# Ref: https://github.com/jazzband/pip-tools/issues/2252
612+
extra_resolver_kwargs["use_pep517"] = self.options.use_pep517
613+
608614
resolver = self.command.make_resolver(
609615
preparer=preparer,
610616
finder=self.finder,
@@ -614,8 +620,8 @@ def resolve(self, max_rounds: int = 10) -> set[InstallRequirement]:
614620
ignore_installed=True,
615621
ignore_requires_python=False,
616622
force_reinstall=False,
617-
use_pep517=self.options.use_pep517,
618623
upgrade_strategy="to-satisfy-only",
624+
**extra_resolver_kwargs,
619625
)
620626

621627
self.command.trace_basic_info(self.finder)

piptools/scripts/_deprecations.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""Module to deprecate script arguments."""
2+
3+
from __future__ import annotations
4+
5+
from ..logging import log
6+
from ..utils import PIP_VERSION
7+
8+
9+
def filter_deprecated_pip_args(args: list[str]) -> list[str]:
10+
"""
11+
Warn about and drop pip args that are no longer supported by pip.
12+
13+
Currently drops:
14+
15+
- ``--use-pep517``
16+
- ``--no-use-pep517``
17+
- ``--global-option``
18+
- ``--build-option``
19+
"""
20+
if PIP_VERSION < (25, 3): # pragma: <3.9 cover
21+
return args
22+
23+
deprecation_mapping = {
24+
"--use-pep517": "Pip always uses PEP 517 for building projects now.",
25+
"--no-use-pep517": "Pip always uses PEP 517 for building projects now.",
26+
"--global-option": (
27+
"--config-setting is now the only way to pass options to the build backend."
28+
),
29+
"--build-option": (
30+
"--config-setting is now the only way to pass options to the build backend."
31+
),
32+
}
33+
supported_args = []
34+
for arg in args:
35+
opt_key = arg.split("=")[0]
36+
try:
37+
warn_msg = deprecation_mapping[opt_key]
38+
except KeyError:
39+
supported_args.append(arg)
40+
else:
41+
log.warning(
42+
"WARNING: "
43+
f"{arg} is no longer supported by pip and is deprecated in pip-tools. "
44+
"This option is ignored and will result in errors in a future release. "
45+
f"{warn_msg}"
46+
)
47+
48+
return supported_args

piptools/scripts/compile.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
)
3232
from ..writer import OutputWriter
3333
from . import options
34+
from ._deprecations import filter_deprecated_pip_args
3435
from .options import BuildTargetT
3536

3637
DEFAULT_REQUIREMENTS_FILES = (
@@ -287,6 +288,7 @@ def cli(
287288
if resolver_name == "backtracking" and cache_dir:
288289
pip_args.extend(["--cache-dir", cache_dir])
289290
pip_args.extend(right_args)
291+
pip_args = filter_deprecated_pip_args(pip_args)
290292

291293
repository: BaseRepository
292294
repository = PyPIRepository(pip_args, cache_dir=cache_dir)

piptools/scripts/sync.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
get_sys_path_for_python_executable,
2727
)
2828
from . import options
29+
from ._deprecations import filter_deprecated_pip_args
2930

3031
DEFAULT_REQUIREMENTS_FILE = "requirements.txt"
3132

@@ -141,6 +142,8 @@ def cli(
141142
cert=cert,
142143
client_cert=client_cert,
143144
) + shlex.split(pip_args_str or "")
145+
install_flags = filter_deprecated_pip_args(install_flags)
146+
144147
sys.exit(
145148
sync.sync(
146149
to_install,

piptools/utils.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -500,16 +500,23 @@ def copy_install_requirement(
500500
"editable": template.editable,
501501
"link": template.link,
502502
"markers": template.markers,
503-
"use_pep517": template.use_pep517,
504503
"isolated": template.isolated,
505-
"global_options": template.global_options,
506504
"hash_options": template.hash_options,
507505
"constraint": template.constraint,
508506
"extras": template.extras,
509507
"user_supplied": template.user_supplied,
510508
}
509+
if PIP_VERSION[:2] < (25, 3): # pragma: <3.9 cover
510+
# Ref: https://github.com/jazzband/pip-tools/issues/2252
511+
kwargs["use_pep517"] = template.use_pep517
512+
kwargs["global_options"] = template.global_options
511513
kwargs.update(extra_kwargs)
512514

515+
if PIP_VERSION[:2] >= (25, 3): # pragma: >=3.9 cover
516+
# Ref: https://github.com/jazzband/pip-tools/issues/2252
517+
kwargs.pop("use_pep517", None)
518+
kwargs.pop("global_options", None)
519+
513520
if PIP_VERSION[:2] <= (23, 0):
514521
kwargs["install_options"] = template.install_options
515522

tests/conftest.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import json
44
import os
55
import platform
6+
import shutil
67
import subprocess
78
import sys
89
from contextlib import contextmanager
@@ -266,26 +267,26 @@ def _make_pip_conf(content):
266267

267268

268269
@pytest.fixture
269-
def pip_conf(make_pip_conf):
270+
def pip_conf(make_pip_conf, minimal_wheels_path):
270271
return make_pip_conf(
271272
dedent(
272273
f"""\
273274
[global]
274275
no-index = true
275-
find-links = {MINIMAL_WHEELS_PATH}
276+
find-links = {minimal_wheels_path.as_posix()}
276277
"""
277278
)
278279
)
279280

280281

281282
@pytest.fixture
282-
def pip_with_index_conf(make_pip_conf):
283+
def pip_with_index_conf(make_pip_conf, minimal_wheels_path):
283284
return make_pip_conf(
284285
dedent(
285286
f"""\
286287
[global]
287288
index-url = http://example.com
288-
find-links = {MINIMAL_WHEELS_PATH}
289+
find-links = {minimal_wheels_path.as_posix()}
289290
"""
290291
)
291292
)
@@ -524,3 +525,32 @@ def _maker(
524525
return cast(Path, config_file.relative_to(tmpdir_cwd))
525526

526527
return _maker
528+
529+
530+
@pytest.fixture(scope="session")
531+
def setuptools_wheel_path(tmp_path_factory):
532+
"""
533+
Ensure setuptools is downloaded and return the path to the download directory.
534+
"""
535+
tmp_wheels_path = tmp_path_factory.mktemp("tmp_wheels")
536+
subprocess.check_call(
537+
[
538+
sys.executable,
539+
"-Im",
540+
"pip",
541+
"download",
542+
f"--dest={tmp_wheels_path.as_posix()}",
543+
"--no-deps",
544+
"setuptools",
545+
],
546+
)
547+
return tmp_wheels_path
548+
549+
550+
@pytest.fixture(scope="session")
551+
def minimal_wheels_path(setuptools_wheel_path):
552+
"""
553+
Ensure minimal wheels and setuptools are downloaded and return the path.
554+
"""
555+
shutil.copytree(MINIMAL_WHEELS_PATH, setuptools_wheel_path, dirs_exist_ok=True)
556+
return setuptools_wheel_path

tests/test_cli_compile.py

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os
66
import pathlib
77
import re
8+
import shlex
89
import shutil
910
import subprocess
1011
import sys
@@ -165,7 +166,7 @@ def test_command_line_overrides_pip_conf(pip_with_index_conf, runner):
165166
),
166167
)
167168
def test_command_line_setuptools_read(
168-
runner, make_package, install_requires, expected_output
169+
runner, make_package, minimal_wheels_path, install_requires, expected_output
169170
):
170171
package_dir = make_package(
171172
name="fake-setuptools-a",
@@ -177,7 +178,7 @@ def test_command_line_setuptools_read(
177178
(
178179
str(package_dir / "setup.py"),
179180
"--find-links",
180-
MINIMAL_WHEELS_PATH,
181+
minimal_wheels_path.as_posix(),
181182
"--no-build-isolation",
182183
),
183184
)
@@ -1794,6 +1795,41 @@ def test_forwarded_args(PyPIRepository, runner):
17941795
assert set(pip_args).issubset(set(args[0]))
17951796

17961797

1798+
@pytest.mark.parametrize(
1799+
"pip_args",
1800+
(
1801+
pytest.param(
1802+
("--use-pep517", "--global-option=build_ext"),
1803+
id="use-pep517 and global-option",
1804+
),
1805+
pytest.param(
1806+
("--no-use-pep517", "--build-option=build_ext"),
1807+
id="no-use-pep517 and build-option",
1808+
),
1809+
),
1810+
)
1811+
@mock.patch("piptools.scripts.compile.PyPIRepository")
1812+
def test_forwarded_args_filter_deprecated(PyPIRepository, runner, pip_args):
1813+
"""
1814+
Test the cli args (``--pip-args 'arg...'``) are filtered out if pip no longer supports them.
1815+
"""
1816+
pathlib.Path("requirements.in").write_text("", encoding="utf-8")
1817+
1818+
cli_args = ("--no-annotate", "--generate-hashes")
1819+
runner.invoke(cli, [*cli_args, "--pip-args", shlex.join(pip_args)])
1820+
pip_option_keys = {pip_arg.split("=")[0] for pip_arg in pip_args}
1821+
1822+
(first_posarg, *_tail_args), _kwargs = PyPIRepository.call_args
1823+
1824+
pip_current_version = get_pip_version_for_python_executable(sys.executable)
1825+
pip_breaking_version = Version("25.3")
1826+
1827+
if pip_current_version >= pip_breaking_version: # pragma: >=3.9 cover
1828+
assert set(first_posarg) ^ pip_option_keys
1829+
else:
1830+
assert set(first_posarg) & pip_option_keys
1831+
1832+
17971833
@pytest.mark.parametrize(
17981834
("cli_option", "infile_option", "expected_package"),
17991835
(
@@ -3430,7 +3466,12 @@ def test_pass_pip_cache_to_pip_args(tmpdir, runner, current_resolver):
34303466

34313467

34323468
@backtracking_resolver_only
3433-
def test_compile_recursive_extras_static(runner, tmp_path, current_resolver):
3469+
def test_compile_recursive_extras_static(
3470+
runner,
3471+
tmp_path,
3472+
minimal_wheels_path,
3473+
current_resolver,
3474+
):
34343475
(tmp_path / "pyproject.toml").write_text(
34353476
dedent(
34363477
"""
@@ -3454,7 +3495,7 @@ def test_compile_recursive_extras_static(runner, tmp_path, current_resolver):
34543495
"--extra",
34553496
"dev",
34563497
"--find-links",
3457-
os.fspath(MINIMAL_WHEELS_PATH),
3498+
minimal_wheels_path.as_posix(),
34583499
os.fspath(tmp_path / "pyproject.toml"),
34593500
"--output-file",
34603501
"-",
@@ -3474,7 +3515,9 @@ def test_compile_recursive_extras_static(runner, tmp_path, current_resolver):
34743515

34753516

34763517
@backtracking_resolver_only
3477-
def test_compile_recursive_extras_build_targets(runner, tmp_path, current_resolver):
3518+
def test_compile_recursive_extras_build_targets(
3519+
runner, tmp_path, minimal_wheels_path, current_resolver
3520+
):
34783521
(tmp_path / "pyproject.toml").write_text(
34793522
dedent(
34803523
"""
@@ -3500,7 +3543,7 @@ def test_compile_recursive_extras_build_targets(runner, tmp_path, current_resolv
35003543
"--build-deps-for",
35013544
"wheel",
35023545
"--find-links",
3503-
os.fspath(MINIMAL_WHEELS_PATH),
3546+
minimal_wheels_path.as_posix(),
35043547
os.fspath(tmp_path / "pyproject.toml"),
35053548
"--output-file",
35063549
"-",
@@ -3526,6 +3569,7 @@ def test_compile_recursive_extras_build_targets(runner, tmp_path, current_resolv
35263569
def test_compile_build_targets_setuptools_no_wheel_dep(
35273570
runner,
35283571
tmp_path,
3572+
minimal_wheels_path,
35293573
current_resolver,
35303574
):
35313575
"""Check that user requests apply to build dependencies.
@@ -3566,7 +3610,7 @@ def test_compile_build_targets_setuptools_no_wheel_dep(
35663610
"--build-deps-for",
35673611
"wheel",
35683612
"--find-links",
3569-
os.fspath(MINIMAL_WHEELS_PATH),
3613+
minimal_wheels_path.as_posix(),
35703614
os.fspath(tmp_path / "pyproject.toml"),
35713615
"--constraint",
35723616
os.fspath(tmp_path / "constraints.txt"),

0 commit comments

Comments
 (0)