Skip to content

Commit 3ff2513

Browse files
authored
Merge pull request #7384 from chrahunt/refactor/cleanup-prepare-3
Cleanup operations.prepare more
2 parents 81f0572 + 59f2206 commit 3ff2513

File tree

2 files changed

+68
-48
lines changed

2 files changed

+68
-48
lines changed

src/pip/_internal/operations/prepare.py

+61-44
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
from pip._internal.utils.misc import (
4141
ask_path_exists,
4242
backup_dir,
43-
consume,
4443
display_path,
4544
format_size,
4645
hide_url,
@@ -58,7 +57,7 @@
5857

5958
if MYPY_CHECK_RUNNING:
6059
from typing import (
61-
Any, Callable, IO, List, Optional, Tuple,
60+
Callable, Iterable, List, Optional, Tuple,
6261
)
6362

6463
from mypy_extensions import TypedDict
@@ -122,14 +121,12 @@ def _get_http_response_size(resp):
122121
return None
123122

124123

125-
def _download_url(
124+
def _prepare_download(
126125
resp, # type: Response
127126
link, # type: Link
128-
content_file, # type: IO[Any]
129-
hashes, # type: Optional[Hashes]
130127
progress_bar # type: str
131128
):
132-
# type: (...) -> None
129+
# type: (...) -> Iterable[bytes]
133130
total_length = _get_http_response_size(resp)
134131

135132
if link.netloc == PyPI.file_storage_domain:
@@ -159,27 +156,16 @@ def _download_url(
159156
else:
160157
show_progress = False
161158

162-
def written_chunks(chunks):
163-
for chunk in chunks:
164-
content_file.write(chunk)
165-
yield chunk
166-
167159
progress_indicator = _progress_indicator
168160

169161
if show_progress: # We don't show progress on cached responses
170162
progress_indicator = DownloadProgressProvider(
171163
progress_bar, max=total_length
172164
)
173165

174-
downloaded_chunks = written_chunks(
175-
progress_indicator(
176-
response_chunks(resp, CONTENT_CHUNK_SIZE)
177-
)
166+
return progress_indicator(
167+
response_chunks(resp, CONTENT_CHUNK_SIZE)
178168
)
179-
if hashes:
180-
hashes.check_against_chunks(downloaded_chunks)
181-
else:
182-
consume(downloaded_chunks)
183169

184170

185171
def _copy_file(filename, location, link):
@@ -215,10 +201,9 @@ def _copy_file(filename, location, link):
215201
def unpack_http_url(
216202
link, # type: Link
217203
location, # type: str
218-
session, # type: PipSession
204+
downloader, # type: Downloader
219205
download_dir=None, # type: Optional[str]
220206
hashes=None, # type: Optional[Hashes]
221-
progress_bar="on" # type: str
222207
):
223208
# type: (...) -> None
224209
with TempDirectory(kind="unpack") as temp_dir:
@@ -235,7 +220,7 @@ def unpack_http_url(
235220
else:
236221
# let's download to a tmp dir
237222
from_path, content_type = _download_http_url(
238-
link, session, temp_dir.path, hashes, progress_bar
223+
link, downloader, temp_dir.path, hashes
239224
)
240225

241226
# unpack the archive to the build dir location. even when only
@@ -346,10 +331,9 @@ def unpack_file_url(
346331
def unpack_url(
347332
link, # type: Link
348333
location, # type: str
349-
session, # type: PipSession
334+
downloader, # type: Downloader
350335
download_dir=None, # type: Optional[str]
351336
hashes=None, # type: Optional[Hashes]
352-
progress_bar="on" # type: str
353337
):
354338
# type: (...) -> None
355339
"""Unpack link.
@@ -379,10 +363,9 @@ def unpack_url(
379363
unpack_http_url(
380364
link,
381365
location,
382-
session,
366+
downloader,
383367
download_dir,
384368
hashes=hashes,
385-
progress_bar=progress_bar
386369
)
387370

388371

@@ -464,28 +447,65 @@ def _http_get_download(session, link):
464447
return resp
465448

466449

450+
class Download(object):
451+
def __init__(
452+
self,
453+
response, # type: Response
454+
filename, # type: str
455+
chunks, # type: Iterable[bytes]
456+
):
457+
# type: (...) -> None
458+
self.response = response
459+
self.filename = filename
460+
self.chunks = chunks
461+
462+
463+
class Downloader(object):
464+
def __init__(
465+
self,
466+
session, # type: PipSession
467+
progress_bar, # type: str
468+
):
469+
# type: (...) -> None
470+
self._session = session
471+
self._progress_bar = progress_bar
472+
473+
def __call__(self, link):
474+
# type: (Link) -> Download
475+
try:
476+
resp = _http_get_download(self._session, link)
477+
except requests.HTTPError as e:
478+
logger.critical(
479+
"HTTP error %s while getting %s", e.response.status_code, link
480+
)
481+
raise
482+
483+
return Download(
484+
resp,
485+
_get_http_response_filename(resp, link),
486+
_prepare_download(resp, link, self._progress_bar),
487+
)
488+
489+
467490
def _download_http_url(
468491
link, # type: Link
469-
session, # type: PipSession
492+
downloader, # type: Downloader
470493
temp_dir, # type: str
471494
hashes, # type: Optional[Hashes]
472-
progress_bar # type: str
473495
):
474496
# type: (...) -> Tuple[str, str]
475497
"""Download link url into temp_dir using provided session"""
476-
try:
477-
resp = _http_get_download(session, link)
478-
except requests.HTTPError as exc:
479-
logger.critical(
480-
"HTTP error %s while getting %s", exc.response.status_code, link,
481-
)
482-
raise
498+
download = downloader(link)
483499

484-
filename = _get_http_response_filename(resp, link)
485-
file_path = os.path.join(temp_dir, filename)
500+
file_path = os.path.join(temp_dir, download.filename)
486501
with open(file_path, 'wb') as content_file:
487-
_download_url(resp, link, content_file, hashes, progress_bar)
488-
return file_path, resp.headers.get('content-type', '')
502+
for chunk in download.chunks:
503+
content_file.write(chunk)
504+
505+
if hashes:
506+
hashes.check_against_path(file_path)
507+
508+
return file_path, download.response.headers.get('content-type', '')
489509

490510

491511
def _check_download_dir(link, download_dir, hashes):
@@ -538,7 +558,7 @@ def __init__(
538558
self.src_dir = src_dir
539559
self.build_dir = build_dir
540560
self.req_tracker = req_tracker
541-
self.session = session
561+
self.downloader = Downloader(session, progress_bar)
542562
self.finder = finder
543563

544564
# Where still-packed archives should be written to. If None, they are
@@ -559,8 +579,6 @@ def __init__(
559579
# be combined if we're willing to have non-wheel archives present in
560580
# the wheelhouse output by 'pip wheel'.
561581

562-
self.progress_bar = progress_bar
563-
564582
# Is build isolation allowed?
565583
self.build_isolation = build_isolation
566584

@@ -662,9 +680,8 @@ def prepare_linked_requirement(
662680

663681
try:
664682
unpack_url(
665-
link, req.source_dir, self.session, download_dir,
683+
link, req.source_dir, self.downloader, download_dir,
666684
hashes=hashes,
667-
progress_bar=self.progress_bar
668685
)
669686
except requests.HTTPError as exc:
670687
logger.critical(

tests/unit/test_operations_prepare.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from pip._internal.models.link import Link
1414
from pip._internal.network.session import PipSession
1515
from pip._internal.operations.prepare import (
16+
Downloader,
1617
_copy_source_tree,
1718
_download_http_url,
1819
parse_content_disposition,
@@ -44,6 +45,7 @@ def _fake_session_get(*args, **kwargs):
4445

4546
session = Mock()
4647
session.get = _fake_session_get
48+
downloader = Downloader(session, progress_bar="on")
4749

4850
uri = path_to_url(data.packages.joinpath("simple-1.0.tar.gz"))
4951
link = Link(uri)
@@ -52,7 +54,7 @@ def _fake_session_get(*args, **kwargs):
5254
unpack_http_url(
5355
link,
5456
temp_dir,
55-
session=session,
57+
downloader=downloader,
5658
download_dir=None,
5759
)
5860
assert set(os.listdir(temp_dir)) == {
@@ -131,6 +133,7 @@ def test_unpack_http_url_bad_downloaded_checksum(mock_unpack_file):
131133
response = session.get.return_value = MockResponse(contents)
132134
response.headers = {'content-type': 'application/x-tar'}
133135
response.url = base_url
136+
downloader = Downloader(session, progress_bar="on")
134137

135138
download_dir = mkdtemp()
136139
try:
@@ -140,7 +143,7 @@ def test_unpack_http_url_bad_downloaded_checksum(mock_unpack_file):
140143
unpack_http_url(
141144
link,
142145
'location',
143-
session=session,
146+
downloader=downloader,
144147
download_dir=download_dir,
145148
hashes=Hashes({'sha1': [download_hash.hexdigest()]})
146149
)
@@ -228,15 +231,15 @@ def test_download_http_url__no_directory_traversal(tmpdir):
228231
'content-disposition': 'attachment;filename="../out_dir_file"'
229232
}
230233
session.get.return_value = resp
234+
downloader = Downloader(session, progress_bar="on")
231235

232236
download_dir = tmpdir.joinpath('download')
233237
os.mkdir(download_dir)
234238
file_path, content_type = _download_http_url(
235239
link,
236-
session,
240+
downloader,
237241
download_dir,
238242
hashes=None,
239-
progress_bar='on',
240243
)
241244
# The file should be downloaded to download_dir.
242245
actual = os.listdir(download_dir)

0 commit comments

Comments
 (0)