Skip to content

Commit ea279f7

Browse files
committed
Use pkg_resources.Distribution derived from wheel directly
We now extract all metadata files from the wheel directly into memory and make them available to the wrapping pkg_resources.Distribution via the DictMetadata introduced earlier.
1 parent d1c1264 commit ea279f7

File tree

2 files changed

+53
-4
lines changed

2 files changed

+53
-4
lines changed

src/pip/_internal/distributions/wheel.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
from pip._vendor import pkg_resources
1+
from zipfile import ZipFile
22

33
from pip._internal.distributions.base import AbstractDistribution
44
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
5+
from pip._internal.utils.wheel import pkg_resources_distribution_for_wheel
56

67
if MYPY_CHECK_RUNNING:
78
from pip._vendor.pkg_resources import Distribution
@@ -16,8 +17,15 @@ class WheelDistribution(AbstractDistribution):
1617

1718
def get_pkg_resources_distribution(self):
1819
# type: () -> Distribution
19-
return list(pkg_resources.find_distributions(
20-
self.req.source_dir))[0]
20+
# Set as part of preparation during download.
21+
assert self.req.local_file_path
22+
# Wheels are never unnamed.
23+
assert self.req.name
24+
25+
with ZipFile(self.req.local_file_path, allowZip64=True) as z:
26+
return pkg_resources_distribution_for_wheel(
27+
z, self.req.name, self.req.local_file_path
28+
)
2129

2230
def prepare_distribution_metadata(self, finder, build_isolation):
2331
# type: (PackageFinder, bool) -> None

src/pip/_internal/utils/wheel.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,18 @@
88
from zipfile import ZipFile
99

1010
from pip._vendor.packaging.utils import canonicalize_name
11+
from pip._vendor.pkg_resources import DistInfoDistribution
1112
from pip._vendor.six import PY2, ensure_str
1213

1314
from pip._internal.exceptions import UnsupportedWheel
15+
from pip._internal.utils.pkg_resources import DictMetadata
1416
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
1517

1618
if MYPY_CHECK_RUNNING:
1719
from email.message import Message
18-
from typing import Tuple
20+
from typing import Dict, Tuple
21+
22+
from pip._vendor.pkg_resources import Distribution
1923

2024
if PY2:
2125
from zipfile import BadZipfile as BadZipFile
@@ -29,6 +33,43 @@
2933
logger = logging.getLogger(__name__)
3034

3135

36+
def pkg_resources_distribution_for_wheel(wheel_zip, name, location):
37+
# type: (ZipFile, str, str) -> Distribution
38+
"""Get a pkg_resources distribution given a wheel.
39+
40+
:raises UnsupportedWheel on any errors
41+
"""
42+
info_dir, _ = parse_wheel(wheel_zip, name)
43+
44+
metadata_files = [
45+
p for p in wheel_zip.namelist() if p.startswith("{}/".format(info_dir))
46+
]
47+
48+
metadata_text = {} # type: Dict[str, str]
49+
for path in metadata_files:
50+
# If a flag is set, namelist entries may be unicode in Python 2.
51+
# We coerce them to native str type to match the types used in the rest
52+
# of the code. This cannot fail because unicode can always be encoded
53+
# with UTF-8.
54+
full_path = ensure_str(path)
55+
_, metadata_name = full_path.split("/", 1)
56+
57+
try:
58+
metadata_text[metadata_name] = read_wheel_metadata_file(
59+
wheel_zip, full_path
60+
)
61+
except UnsupportedWheel as e:
62+
raise UnsupportedWheel(
63+
"{} has an invalid wheel, {}".format(name, str(e))
64+
)
65+
66+
metadata = DictMetadata(metadata_text)
67+
68+
return DistInfoDistribution(
69+
location=location, metadata=metadata, project_name=name
70+
)
71+
72+
3273
def parse_wheel(wheel_zip, name):
3374
# type: (ZipFile, str) -> Tuple[str, Message]
3475
"""Extract information from the provided wheel, ensuring it meets basic

0 commit comments

Comments
 (0)