Skip to content

Commit 350cf98

Browse files
committed
Rename and wrap LazyZipOverHTTP
1 parent 62d2c14 commit 350cf98

File tree

1 file changed

+32
-15
lines changed

1 file changed

+32
-15
lines changed

src/pip/_internal/network/lazy_wheel.py

+32-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Lazy ZIP over HTTP"""
22

3-
__all__ = ['LazyZip']
3+
__all__ = ['dist_from_wheel_url']
44

55
from bisect import bisect_left, bisect_right
66
from contextlib import contextmanager
@@ -12,24 +12,44 @@
1212

1313
from pip._internal.network.utils import HEADERS, response_chunks
1414
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
15+
from pip._internal.utils.wheel import pkg_resources_distribution_for_wheel
1516

1617
if MYPY_CHECK_RUNNING:
1718
from typing import Any, Dict, Iterator, List, Optional, Tuple
1819

20+
from pip._vendor.pkg_resources import Distribution
1921
from pip._vendor.requests.models import Response
2022

2123
from pip._internal.network.session import PipSession
2224

2325

24-
class LazyZip:
26+
def dist_from_wheel_url(name, url, session):
27+
# type: (str, str, PipSession) -> Distribution
28+
"""Return a pkg_resources.Distribution from the given wheel URL.
29+
30+
This uses HTTP range requests to only fetch the potion of the wheel
31+
containing metadata, just enough for the object to be constructed.
32+
If such requests are not supported, RuntimeError is raised.
33+
"""
34+
with LazyZipOverHTTP(url, session) as wheel:
35+
# For read-only ZIP files, ZipFile only needs methods read,
36+
# seek, seekable and tell, not the whole IO protocol.
37+
zip_file = ZipFile(wheel) # type: ignore
38+
# After context manager exit, wheel.name
39+
# is an invalid file by intention.
40+
return pkg_resources_distribution_for_wheel(zip_file, name, wheel.name)
41+
42+
43+
class LazyZipOverHTTP:
2544
"""File-like object mapped to a ZIP file over HTTP.
2645
2746
This uses HTTP range requests to lazily fetch the file's content,
28-
which is supposed to be fed to ZipFile.
47+
which is supposed to be fed to ZipFile. If such requests are not
48+
supported by the server, raise RuntimeError during initialization.
2949
"""
3050

31-
def __init__(self, session, url, chunk_size=CONTENT_CHUNK_SIZE):
32-
# type: (PipSession, str, int) -> None
51+
def __init__(self, url, session, chunk_size=CONTENT_CHUNK_SIZE):
52+
# type: (str, PipSession, int) -> None
3353
head = session.head(url, headers=HEADERS)
3454
head.raise_for_status()
3555
assert head.status_code == 200
@@ -39,7 +59,9 @@ def __init__(self, session, url, chunk_size=CONTENT_CHUNK_SIZE):
3959
self.truncate(self._length)
4060
self._left = [] # type: List[int]
4161
self._right = [] # type: List[int]
42-
self._check_zip('bytes' in head.headers.get('Accept-Ranges', 'none'))
62+
if 'bytes' not in head.headers.get('Accept-Ranges', 'none'):
63+
raise RuntimeError('range request is not supported')
64+
self._check_zip()
4365

4466
@property
4567
def mode(self):
@@ -50,7 +72,7 @@ def mode(self):
5072
@property
5173
def name(self):
5274
# type: () -> str
53-
"""File name."""
75+
"""Path to the underlying file."""
5476
return self._file.name
5577

5678
def seekable(self):
@@ -120,7 +142,7 @@ def writable(self):
120142
return False
121143

122144
def __enter__(self):
123-
# type: () -> LazyZip
145+
# type: () -> LazyZipOverHTTP
124146
self._file.__enter__()
125147
return self
126148

@@ -141,21 +163,16 @@ def _stay(self):
141163
finally:
142164
self.seek(pos)
143165

144-
def _check_zip(self, range_request):
145-
# type: (bool) -> None
166+
def _check_zip(self):
167+
# type: () -> None
146168
"""Check and download until the file is a valid ZIP."""
147169
end = self._length - 1
148-
if not range_request:
149-
self._download(0, end)
150-
return
151170
for start in reversed(range(0, end, self._chunk_size)):
152171
self._download(start, end)
153172
with self._stay():
154173
try:
155174
# For read-only ZIP files, ZipFile only needs
156175
# methods read, seek, seekable and tell.
157-
# The best way to type-hint in this case is to use
158-
# Python 3.8+ typing.Protocol.
159176
ZipFile(self) # type: ignore
160177
except BadZipfile:
161178
pass

0 commit comments

Comments
 (0)