Skip to content

Commit 6178f96

Browse files
authored
Merge pull request #6540 from cjerdonek/issue-6121-incompatible-wheel-message
Improve the debug log message when installing an incompatible wheel
2 parents f44344f + a9a9cfd commit 6178f96

File tree

7 files changed

+67
-8
lines changed

7 files changed

+67
-8
lines changed

news/6121.feature

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Include the wheel's tags in the log message explanation when a candidate
2+
wheel link is found incompatible.

src/pip/_internal/index.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,15 @@ def evaluate_link(self, link, search):
384384
return (False, reason)
385385

386386
if not self._is_wheel_supported(wheel):
387-
return (False, 'it is not compatible with this Python')
387+
# Include the wheel's tags in the reason string to
388+
# simplify troubleshooting compatibility issues.
389+
file_tags = wheel.get_formatted_file_tags()
390+
reason = (
391+
"none of the wheel's tags match: {}".format(
392+
', '.join(file_tags)
393+
)
394+
)
395+
return (False, reason)
388396

389397
version = wheel.version
390398

@@ -1066,7 +1074,9 @@ def _sort_links(self, links):
10661074
def _log_skipped_link(self, link, reason):
10671075
# type: (Link, str) -> None
10681076
if link not in self._logged_links:
1069-
logger.debug('Skipping link %s; %s', link, reason)
1077+
# Put the link at the end so the reason is more visible and
1078+
# because the link string is usually very long.
1079+
logger.debug('Skipping link: %s: %s', reason, link)
10701080
self._logged_links.add(link)
10711081

10721082
def get_install_candidate(self, link, search):

src/pip/_internal/wheel.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,16 @@ def check_compatibility(version, name):
663663
)
664664

665665

666+
def format_tag(file_tag):
667+
# type: (Tuple[str, ...]) -> str
668+
"""
669+
Format three tags in the form "<python_tag>-<abi_tag>-<platform_tag>".
670+
671+
:param file_tag: A 3-tuple of tags (python_tag, abi_tag, platform_tag).
672+
"""
673+
return '-'.join(file_tag)
674+
675+
666676
class Wheel(object):
667677
"""A wheel file"""
668678

@@ -702,6 +712,13 @@ def __init__(self, filename):
702712
for y in self.abis for z in self.plats
703713
}
704714

715+
def get_formatted_file_tags(self):
716+
# type: () -> List[str]
717+
"""
718+
Return the wheel's tags as a sorted list of strings.
719+
"""
720+
return sorted(format_tag(tag) for tag in self.file_tags)
721+
705722
def support_index_min(self, tags=None):
706723
# type: (Optional[List[Pep425Tag]]) -> Optional[int]
707724
"""

tests/functional/test_install_config.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,10 @@ def test_command_line_append_flags(script, virtualenv, data):
105105
"Analyzing links from page https://test.pypi.org"
106106
in result.stdout
107107
)
108-
assert "Skipping link %s" % data.find_links in result.stdout
108+
assert (
109+
'Skipping link: not a file: {}'.format(data.find_links) in
110+
result.stdout
111+
), 'stdout: {}'.format(result.stdout)
109112

110113

111114
@pytest.mark.network
@@ -127,7 +130,10 @@ def test_command_line_appends_correctly(script, data):
127130
"Analyzing links from page https://test.pypi.org"
128131
in result.stdout
129132
), result.stdout
130-
assert "Skipping link %s" % data.find_links in result.stdout
133+
assert (
134+
'Skipping link: not a file: {}'.format(data.find_links) in
135+
result.stdout
136+
), 'stdout: {}'.format(result.stdout)
131137

132138

133139
def test_config_file_override_stack(script, virtualenv):

tests/unit/test_finder.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,7 @@ def test_skip_invalid_wheel_link(self, caplog, data):
133133
with pytest.raises(DistributionNotFound):
134134
finder.find_requirement(req, True)
135135

136-
assert (
137-
"invalid.whl; invalid wheel filename"
138-
in caplog.text
139-
)
136+
assert 'Skipping link: invalid wheel filename:' in caplog.text
140137

141138
def test_not_find_wheel_not_supported(self, data, monkeypatch):
142139
"""

tests/unit/test_index.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,24 @@ def test_evaluate_link(
130130
actual = evaluator.evaluate_link(link, search=search)
131131
assert actual == expected
132132

133+
def test_evaluate_link__incompatible_wheel(self):
134+
"""
135+
Test an incompatible wheel.
136+
"""
137+
link = Link('https://example.com/sample-1.0-py2.py3-none-any.whl')
138+
search = Search(
139+
supplied='sample', canonical='sample', formats=['binary'],
140+
)
141+
# Pass an empty list for the valid tags to make sure nothing matches.
142+
evaluator = CandidateEvaluator(
143+
[], py_version_info=(3, 6, 4),
144+
)
145+
actual = evaluator.evaluate_link(link, search=search)
146+
expected = (
147+
False, "none of the wheel's tags match: py2-none-any, py3-none-any"
148+
)
149+
assert actual == expected
150+
133151

134152
def test_sort_locations_file_expand_dir(data):
135153
"""

tests/unit/test_wheel.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,15 @@ def make_test_install_req(base_name=None):
6868
return req
6969

7070

71+
@pytest.mark.parametrize('file_tag, expected', [
72+
(('py27', 'none', 'any'), 'py27-none-any'),
73+
(('cp33', 'cp32dmu', 'linux_x86_64'), 'cp33-cp32dmu-linux_x86_64'),
74+
])
75+
def test_format_tag(file_tag, expected):
76+
actual = wheel.format_tag(file_tag)
77+
assert actual == expected
78+
79+
7180
@pytest.mark.parametrize(
7281
"base_name, autobuilding, cache_available, expected",
7382
[

0 commit comments

Comments
 (0)