Skip to content

Commit 4d938a4

Browse files
committed
Rename and wrap LazyZipOverHTTP
1 parent 62d2c14 commit 4d938a4

File tree

1 file changed

+27
-14
lines changed

1 file changed

+27
-14
lines changed

src/pip/_internal/network/lazy_wheel.py

Lines changed: 27 additions & 14 deletions
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,40 @@
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+
"""
31+
with LazyZipOverHTTP(url, session) as wheel:
32+
# For read-only ZIP files, ZipFile only needs methods read,
33+
# seek, seekable and tell, not the whole IO protocol.
34+
zip_file = ZipFile(wheel) # type: ignore
35+
# After context manager exit, wheel.name
36+
# is an invalid file by intention.
37+
return pkg_resources_distribution_for_wheel(zip_file, name, wheel.name)
38+
39+
40+
class LazyZipOverHTTP:
2541
"""File-like object mapped to a ZIP file over HTTP.
2642
2743
This uses HTTP range requests to lazily fetch the file's content,
2844
which is supposed to be fed to ZipFile.
2945
"""
3046

31-
def __init__(self, session, url, chunk_size=CONTENT_CHUNK_SIZE):
32-
# type: (PipSession, str, int) -> None
47+
def __init__(self, url, session, chunk_size=CONTENT_CHUNK_SIZE):
48+
# type: (str, PipSession, int) -> None
3349
head = session.head(url, headers=HEADERS)
3450
head.raise_for_status()
3551
assert head.status_code == 200
@@ -39,7 +55,9 @@ def __init__(self, session, url, chunk_size=CONTENT_CHUNK_SIZE):
3955
self.truncate(self._length)
4056
self._left = [] # type: List[int]
4157
self._right = [] # type: List[int]
42-
self._check_zip('bytes' in head.headers.get('Accept-Ranges', 'none'))
58+
if 'bytes' not in head.headers.get('Accept-Ranges', 'none'):
59+
raise RuntimeError('range request is not supported')
60+
self._check_zip()
4361

4462
@property
4563
def mode(self):
@@ -50,7 +68,7 @@ def mode(self):
5068
@property
5169
def name(self):
5270
# type: () -> str
53-
"""File name."""
71+
"""Path to the underlying file."""
5472
return self._file.name
5573

5674
def seekable(self):
@@ -120,7 +138,7 @@ def writable(self):
120138
return False
121139

122140
def __enter__(self):
123-
# type: () -> LazyZip
141+
# type: () -> LazyZipOverHTTP
124142
self._file.__enter__()
125143
return self
126144

@@ -141,21 +159,16 @@ def _stay(self):
141159
finally:
142160
self.seek(pos)
143161

144-
def _check_zip(self, range_request):
145-
# type: (bool) -> None
162+
def _check_zip(self):
163+
# type: () -> None
146164
"""Check and download until the file is a valid ZIP."""
147165
end = self._length - 1
148-
if not range_request:
149-
self._download(0, end)
150-
return
151166
for start in reversed(range(0, end, self._chunk_size)):
152167
self._download(start, end)
153168
with self._stay():
154169
try:
155170
# For read-only ZIP files, ZipFile only needs
156171
# 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.
159172
ZipFile(self) # type: ignore
160173
except BadZipfile:
161174
pass

0 commit comments

Comments
 (0)