Skip to content

Commit e7c80c7

Browse files
authored
Merge pull request #10535 from lukasjuhrich/main
2 parents 71151fa + a51a644 commit e7c80c7

File tree

7 files changed

+45
-6
lines changed

7 files changed

+45
-6
lines changed

news/10535.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Present a better error message when an invalid wheel file is encountered, providing more context where the invalid wheel file is.

src/pip/_internal/exceptions.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,17 @@ class UnsupportedWheel(InstallationError):
250250
"""Unsupported wheel."""
251251

252252

253+
class InvalidWheel(InstallationError):
254+
"""Invalid (e.g. corrupt) wheel."""
255+
256+
def __init__(self, location: str, name: str):
257+
self.location = location
258+
self.name = name
259+
260+
def __str__(self) -> str:
261+
return f"Wheel '{self.name}' located at {self.location} is invalid."
262+
263+
253264
class MetadataInconsistent(InstallationError):
254265
"""Built metadata contains inconsistent information.
255266

src/pip/_internal/metadata/pkg_resources.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import email.message
22
import logging
33
from typing import Collection, Iterable, Iterator, List, NamedTuple, Optional
4+
from zipfile import BadZipFile
45

56
from pip._vendor import pkg_resources
67
from pip._vendor.packaging.requirements import Requirement
78
from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
89
from pip._vendor.packaging.version import parse as parse_version
910

11+
from pip._internal.exceptions import InvalidWheel
1012
from pip._internal.utils import misc # TODO: Move definition here.
1113
from pip._internal.utils.packaging import get_installer, get_metadata
1214
from pip._internal.utils.wheel import pkg_resources_distribution_for_wheel
@@ -34,8 +36,16 @@ def __init__(self, dist: pkg_resources.Distribution) -> None:
3436

3537
@classmethod
3638
def from_wheel(cls, wheel: Wheel, name: str) -> "Distribution":
37-
with wheel.as_zipfile() as zf:
38-
dist = pkg_resources_distribution_for_wheel(zf, name, wheel.location)
39+
"""Load the distribution from a given wheel.
40+
41+
:raises InvalidWheel: Whenever loading of the wheel causes a
42+
:py:exc:`zipfile.BadZipFile` exception to be thrown.
43+
"""
44+
try:
45+
with wheel.as_zipfile() as zf:
46+
dist = pkg_resources_distribution_for_wheel(zf, name, wheel.location)
47+
except BadZipFile as e:
48+
raise InvalidWheel(wheel.location, name) from e
3949
return cls(dist)
4050

4151
@property
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is a corrupt wheel which _clearly_ is not a zip file.

tests/functional/test_install_wheel.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,20 @@ def test_install_from_future_wheel_version(script, tmpdir):
4545
result.assert_installed("futurewheel", without_egg_link=True, editable=False)
4646

4747

48-
def test_install_from_broken_wheel(script, data):
48+
@pytest.mark.parametrize(
49+
"wheel_name",
50+
[
51+
"brokenwheel-1.0-py2.py3-none-any.whl",
52+
"corruptwheel-1.0-py2.py3-none-any.whl",
53+
],
54+
)
55+
def test_install_from_broken_wheel(script, data, wheel_name):
4956
"""
5057
Test that installing a broken wheel fails properly
5158
"""
5259
from tests.lib import TestFailure
5360

54-
package = data.packages.joinpath("brokenwheel-1.0-py2.py3-none-any.whl")
61+
package = data.packages.joinpath(wheel_name)
5562
result = script.pip("install", package, "--no-index", expect_error=True)
5663
with pytest.raises(TestFailure):
5764
result.assert_installed("futurewheel", without_egg_link=True, editable=False)

tests/unit/test_network_lazy_wheel.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from typing import Iterator
2-
from zipfile import BadZipfile
32

43
from pip._vendor.packaging.version import Version
54
from pytest import fixture, mark, raises
65

6+
from pip._internal.exceptions import InvalidWheel
77
from pip._internal.network.lazy_wheel import (
88
HTTPRangeRequestUnsupported,
99
dist_from_wheel_url,
@@ -62,5 +62,5 @@ def test_dist_from_wheel_url_no_range(
6262
@mark.network
6363
def test_dist_from_wheel_url_not_zip(session: PipSession) -> None:
6464
"""Test handling with the given URL does not point to a ZIP."""
65-
with raises(BadZipfile):
65+
with raises(InvalidWheel):
6666
dist_from_wheel_url("python", "https://www.python.org/", session)

tests/unit/test_wheel.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,15 @@ def test_wheel_root_is_purelib(text: str, expected: bool) -> None:
252252
assert wheel.wheel_root_is_purelib(message_from_string(text)) == expected
253253

254254

255+
def test_dist_from_broken_wheel_fails(data: TestData) -> None:
256+
from pip._internal.exceptions import InvalidWheel
257+
from pip._internal.metadata import FilesystemWheel, get_wheel_distribution
258+
259+
package = data.packages.joinpath("corruptwheel-1.0-py2.py3-none-any.whl")
260+
with pytest.raises(InvalidWheel):
261+
get_wheel_distribution(FilesystemWheel(package), "brokenwheel")
262+
263+
255264
class TestWheelFile:
256265
def test_unpack_wheel_no_flatten(self, tmpdir: Path) -> None:
257266
filepath = os.path.join(DATA_DIR, "packages", "meta-1.0-py2.py3-none-any.whl")

0 commit comments

Comments
 (0)