Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the debug log message when installing an incompatible wheel #6540

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions news/6121.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Include the wheel's tags in the log message explanation when a candidate
wheel link is found incompatible.
14 changes: 12 additions & 2 deletions src/pip/_internal/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,15 @@ def evaluate_link(self, link, search):
return (False, reason)

if not self._is_wheel_supported(wheel):
return (False, 'it is not compatible with this Python')
# Include the wheel's tags in the reason string to
# simplify troubleshooting compatibility issues.
file_tags = wheel.get_formatted_file_tags()
reason = (
"none of the wheel's tags match: {}".format(
', '.join(file_tags)
)
)
return (False, reason)

version = wheel.version

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

def get_install_candidate(self, link, search):
Expand Down
17 changes: 17 additions & 0 deletions src/pip/_internal/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,16 @@ def check_compatibility(version, name):
)


def format_tag(file_tag):
# type: (Tuple[str, ...]) -> str
"""
Format three tags in the form "<python_tag>-<abi_tag>-<platform_tag>".

:param file_tag: A 3-tuple of tags (python_tag, abi_tag, platform_tag).
"""
return '-'.join(file_tag)


class Wheel(object):
"""A wheel file"""

Expand Down Expand Up @@ -702,6 +712,13 @@ def __init__(self, filename):
for y in self.abis for z in self.plats
}

def get_formatted_file_tags(self):
# type: () -> List[str]
"""
Return the wheel's tags as a sorted list of strings.
"""
return sorted(format_tag(tag) for tag in self.file_tags)

def support_index_min(self, tags=None):
# type: (Optional[List[Pep425Tag]]) -> Optional[int]
"""
Expand Down
10 changes: 8 additions & 2 deletions tests/functional/test_install_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ def test_command_line_append_flags(script, virtualenv, data):
"Analyzing links from page https://test.pypi.org"
in result.stdout
)
assert "Skipping link %s" % data.find_links in result.stdout
assert (
'Skipping link: not a file: {}'.format(data.find_links) in
result.stdout
), 'stdout: {}'.format(result.stdout)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC this can just be , result, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried this out, and what happens is it adds other sections of info like -- stderr: ---, -- created: ----, and -- updated: --- (in addition to -- stdout: ----). Since those other sections can also be long and aren't needed, I think it might be better not to include them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say they're useful diagnostic information (like an error getting logged on stderr by the networking stuff) or something like that.

I'll leave it to you to decide on what to include here since it's not worth too long a discussion anyway.

Copy link
Member Author

@cjerdonek cjerdonek May 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll just leave it off. Normally, the test runner includes lots of surrounding info already. It's just when you can't see the string being checked against where it gets annoying (which was the reason for adding it) -- because it truncates long strings.



@pytest.mark.network
Expand All @@ -127,7 +130,10 @@ def test_command_line_appends_correctly(script, data):
"Analyzing links from page https://test.pypi.org"
in result.stdout
), result.stdout
assert "Skipping link %s" % data.find_links in result.stdout
assert (
'Skipping link: not a file: {}'.format(data.find_links) in
result.stdout
), 'stdout: {}'.format(result.stdout)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above.



def test_config_file_override_stack(script, virtualenv):
Expand Down
5 changes: 1 addition & 4 deletions tests/unit/test_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,7 @@ def test_skip_invalid_wheel_link(self, caplog, data):
with pytest.raises(DistributionNotFound):
finder.find_requirement(req, True)

assert (
"invalid.whl; invalid wheel filename"
in caplog.text
)
assert 'Skipping link: invalid wheel filename:' in caplog.text

def test_not_find_wheel_not_supported(self, data, monkeypatch):
"""
Expand Down
18 changes: 18 additions & 0 deletions tests/unit/test_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,24 @@ def test_evaluate_link(
actual = evaluator.evaluate_link(link, search=search)
assert actual == expected

def test_evaluate_link__incompatible_wheel(self):
"""
Test an incompatible wheel.
"""
link = Link('https://example.com/sample-1.0-py2.py3-none-any.whl')
search = Search(
supplied='sample', canonical='sample', formats=['binary'],
)
# Pass an empty list for the valid tags to make sure nothing matches.
evaluator = CandidateEvaluator(
[], py_version_info=(3, 6, 4),
)
actual = evaluator.evaluate_link(link, search=search)
expected = (
False, "none of the wheel's tags match: py2-none-any, py3-none-any"
)
assert actual == expected


def test_sort_locations_file_expand_dir(data):
"""
Expand Down
9 changes: 9 additions & 0 deletions tests/unit/test_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ def make_test_install_req(base_name=None):
return req


@pytest.mark.parametrize('file_tag, expected', [
(('py27', 'none', 'any'), 'py27-none-any'),
(('cp33', 'cp32dmu', 'linux_x86_64'), 'cp33-cp32dmu-linux_x86_64'),
])
def test_format_tag(file_tag, expected):
actual = wheel.format_tag(file_tag)
assert actual == expected


@pytest.mark.parametrize(
"base_name, autobuilding, cache_available, expected",
[
Expand Down