Skip to content

Commit 9c804ed

Browse files
authored
Merge branch 'main' into add-docs-for-platform-and-python-version
2 parents eb949e2 + 2014c69 commit 9c804ed

File tree

9 files changed

+55
-57
lines changed

9 files changed

+55
-57
lines changed

news/13252.bugfix.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
When choosing a preferred requirement for resolving dependencies
2+
do not consider a specifier with a * in it, e.g. "==1.*", to be a
3+
pinned specifier.

news/5210.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Display wheel build tag in ``pip list`` columns output if set.

src/pip/_internal/commands/list.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22
import logging
3+
from email.parser import Parser
34
from optparse import Values
45
from typing import TYPE_CHECKING, Generator, List, Optional, Sequence, Tuple, cast
56

@@ -323,17 +324,29 @@ def format_for_columns(
323324
if running_outdated:
324325
header.extend(["Latest", "Type"])
325326

326-
has_editables = any(x.editable for x in pkgs)
327-
if has_editables:
328-
header.append("Editable project location")
327+
def wheel_build_tag(dist: BaseDistribution) -> Optional[str]:
328+
try:
329+
wheel_file = dist.read_text("WHEEL")
330+
except FileNotFoundError:
331+
return None
332+
return Parser().parsestr(wheel_file).get("Build")
333+
334+
build_tags = [wheel_build_tag(p) for p in pkgs]
335+
has_build_tags = any(build_tags)
336+
if has_build_tags:
337+
header.append("Build")
329338

330339
if options.verbose >= 1:
331340
header.append("Location")
332341
if options.verbose >= 1:
333342
header.append("Installer")
334343

344+
has_editables = any(x.editable for x in pkgs)
345+
if has_editables:
346+
header.append("Editable project location")
347+
335348
data = []
336-
for proj in pkgs:
349+
for i, proj in enumerate(pkgs):
337350
# if we're working on the 'outdated' list, separate out the
338351
# latest_version and type
339352
row = [proj.raw_name, proj.raw_version]
@@ -342,6 +355,9 @@ def format_for_columns(
342355
row.append(str(proj.latest_version))
343356
row.append(proj.latest_filetype)
344357

358+
if has_build_tags:
359+
row.append(build_tags[i] or "")
360+
345361
if has_editables:
346362
row.append(proj.editable_project_location or "")
347363

src/pip/_internal/commands/wheel.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
)
1717
from pip._internal.utils.misc import ensure_dir, normalize_path
1818
from pip._internal.utils.temp_dir import TempDirectory
19-
from pip._internal.wheel_builder import build, should_build_for_wheel_command
19+
from pip._internal.wheel_builder import build
2020

2121
logger = logging.getLogger(__name__)
2222

@@ -150,7 +150,7 @@ def run(self, options: Values, args: List[str]) -> int:
150150
for req in requirement_set.requirements.values():
151151
if req.is_wheel:
152152
preparer.save_linked_requirement(req)
153-
elif should_build_for_wheel_command(req):
153+
else:
154154
reqs_to_build.append(req)
155155

156156
preparer.prepare_linked_requirements_more(requirement_set.requirements.values())

src/pip/_internal/resolution/resolvelib/provider.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,14 @@ def get_preference(
142142
else:
143143
candidate, ireqs = None, ()
144144

145-
operators = [
146-
specifier.operator
145+
operators: list[tuple[str, str]] = [
146+
(specifier.operator, specifier.version)
147147
for specifier_set in (ireq.specifier for ireq in ireqs if ireq)
148148
for specifier in specifier_set
149149
]
150150

151151
direct = candidate is not None
152-
pinned = any(op[:2] == "==" for op in operators)
152+
pinned = any(((op[:2] == "==") and ("*" not in ver)) for op, ver in operators)
153153
unfree = bool(operators)
154154
requested_order = self._user_requested.get(identifier, math.inf)
155155

src/pip/_internal/wheel_builder.py

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -43,29 +43,14 @@ def _contains_egg_info(s: str) -> bool:
4343

4444
def _should_build(
4545
req: InstallRequirement,
46-
need_wheel: bool,
4746
) -> bool:
4847
"""Return whether an InstallRequirement should be built into a wheel."""
49-
if req.constraint:
50-
# never build requirements that are merely constraints
51-
return False
48+
assert not req.constraint
49+
5250
if req.is_wheel:
53-
if need_wheel:
54-
logger.info(
55-
"Skipping %s, due to already being wheel.",
56-
req.name,
57-
)
5851
return False
5952

60-
if need_wheel:
61-
# i.e. pip wheel, not pip install
62-
return True
63-
64-
# From this point, this concerns the pip install command only
65-
# (need_wheel=False).
66-
67-
if not req.source_dir:
68-
return False
53+
assert req.source_dir
6954

7055
if req.editable:
7156
# we only build PEP 660 editable requirements
@@ -74,16 +59,10 @@ def _should_build(
7459
return True
7560

7661

77-
def should_build_for_wheel_command(
78-
req: InstallRequirement,
79-
) -> bool:
80-
return _should_build(req, need_wheel=True)
81-
82-
8362
def should_build_for_install_command(
8463
req: InstallRequirement,
8564
) -> bool:
86-
return _should_build(req, need_wheel=False)
65+
return _should_build(req)
8766

8867

8968
def _should_cache(

tests/functional/test_list.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
TestData,
1313
_create_test_package,
1414
create_test_package_with_setup,
15+
make_wheel,
1516
wheel,
1617
)
1718
from tests.lib.direct_url import get_created_direct_url_path
@@ -751,3 +752,16 @@ def test_list_pep610_editable(script: PipTestEnvironment) -> None:
751752
break
752753
else:
753754
pytest.fail("package 'testpkg' not found in pip list result")
755+
756+
757+
def test_list_wheel_build(script: PipTestEnvironment) -> None:
758+
package = make_wheel(
759+
name="package",
760+
version="3.0",
761+
wheel_metadata_updates={"Build": "123"},
762+
).save_to_dir(script.scratch_path)
763+
script.pip("install", package, "--no-index")
764+
765+
result = script.pip("list")
766+
assert "Build" in result.stdout, str(result)
767+
assert "123" in result.stdout, str(result)

tests/unit/resolution_resolvelib/test_provider.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ def build_req_info(
5252
{},
5353
(True, False, False, True, math.inf, False, "pinned-package"),
5454
),
55+
# Star-specified package, i.e. with "*"
56+
(
57+
"star-specified-package",
58+
{"star-specified-package": [build_req_info("star-specified-package==1.*")]},
59+
[],
60+
{},
61+
(True, False, True, True, math.inf, False, "star-specified-package"),
62+
),
5563
# Package that caused backtracking
5664
(
5765
"backtrack-package",

tests/unit/test_wheel_builder.py

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ class ReqMock:
5151
# We build, whether pep 517 is enabled or not.
5252
(ReqMock(use_pep517=True), True),
5353
(ReqMock(use_pep517=False), True),
54-
# We don't build constraints.
55-
(ReqMock(constraint=True), False),
5654
# We don't build reqs that are already wheels.
5755
(ReqMock(is_wheel=True), False),
5856
# We build editables if the backend supports PEP 660.
@@ -65,8 +63,6 @@ class ReqMock:
6563
ReqMock(editable=True, use_pep517=True, supports_pyproject_editable=False),
6664
False,
6765
),
68-
# We don't build if there is no source dir (whatever that means!).
69-
(ReqMock(source_dir=None), False),
7066
# By default (i.e. when binaries are allowed), VCS requirements
7167
# should be built in install mode.
7268
(
@@ -86,25 +82,6 @@ def test_should_build_for_install_command(req: ReqMock, expected: bool) -> None:
8682
assert should_build is expected
8783

8884

89-
@pytest.mark.parametrize(
90-
"req, expected",
91-
[
92-
(ReqMock(), True),
93-
(ReqMock(constraint=True), False),
94-
(ReqMock(is_wheel=True), False),
95-
(ReqMock(editable=True, use_pep517=False), True),
96-
(ReqMock(editable=True, use_pep517=True), True),
97-
(ReqMock(source_dir=None), True),
98-
(ReqMock(link=Link("git+https://g.c/org/repo")), True),
99-
],
100-
)
101-
def test_should_build_for_wheel_command(req: ReqMock, expected: bool) -> None:
102-
should_build = wheel_builder.should_build_for_wheel_command(
103-
cast(InstallRequirement, req)
104-
)
105-
assert should_build is expected
106-
107-
10885
@pytest.mark.parametrize(
10986
"req, expected",
11087
[

0 commit comments

Comments
 (0)