Skip to content

Commit dbc6a64

Browse files
committed
Add support for --resume-retries option
- Added —resume-retries option to allow resuming incomplete downloads - Setting —resume-retries=N allows pip to make N attempts to resume downloading, in case of dropped or timed out connections - Each resume attempt uses the values specified for —retries and —timeout internally Signed-off-by: gmargaritis <[email protected]>
1 parent a091ca1 commit dbc6a64

11 files changed

+183
-152
lines changed

news/11180.feature.rst

-1
This file was deleted.

news/12991.feature.rst

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add support to enable resuming incomplete downloads.
2+
3+
Control the number of retry attempts using the ``--resume-retries`` flag.

src/pip/_internal/cli/cmdoptions.py

+6-17
Original file line numberDiff line numberDiff line change
@@ -1028,23 +1028,13 @@ def check_list_path_option(options: Values) -> None:
10281028
help=("Enable deprecated functionality, that will be removed in the future."),
10291029
)
10301030

1031-
incomplete_downloads: Callable[..., Option] = partial(
1031+
resume_retries: Callable[..., Option] = partial(
10321032
Option,
1033-
"--incomplete-downloads",
1034-
dest="resume_incomplete",
1035-
choices=["resume", "discard"],
1036-
default="discard",
1037-
metavar="policy",
1038-
help="How to handle an incomplete download: resume, discard (default to %default).",
1039-
)
1040-
1041-
incomplete_download_retries: Callable[..., Option] = partial(
1042-
Option,
1043-
"--incomplete-download-retries",
1044-
dest="resume_attempts",
1033+
"--resume-retries",
1034+
dest="resume_retries",
10451035
type="int",
1046-
default=5,
1047-
help="Maximum number of resumption retries for incomplete download "
1036+
default=0,
1037+
help="Maximum number of resumption retries for incomplete downloads"
10481038
"(default %default times).",
10491039
)
10501040

@@ -1080,8 +1070,7 @@ def check_list_path_option(options: Values) -> None:
10801070
no_python_version_warning,
10811071
use_new_feature,
10821072
use_deprecated_feature,
1083-
incomplete_downloads,
1084-
incomplete_download_retries,
1073+
resume_retries,
10851074
],
10861075
}
10871076

src/pip/_internal/cli/progress_bars.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,17 @@ def get_download_progress_renderer(
9090
Returns a callable, that takes an iterable to "wrap".
9191
"""
9292
if bar_type == "on":
93-
return functools.partial(_rich_progress_bar, bar_type=bar_type, size=size, initial_progress=initial_progress,)
93+
return functools.partial(
94+
_rich_progress_bar,
95+
bar_type=bar_type,
96+
size=size,
97+
initial_progress=initial_progress,
98+
)
9499
elif bar_type == "raw":
95-
return functools.partial(_raw_progress_bar, size=size, initial_progress=initial_progress,)
100+
return functools.partial(
101+
_raw_progress_bar,
102+
size=size,
103+
initial_progress=initial_progress,
104+
)
96105
else:
97106
return iter # no-op, when passed an iterator

src/pip/_internal/cli/req_command.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,6 @@ def make_requirement_preparer(
127127
"fast-deps has no effect when used with the legacy resolver."
128128
)
129129

130-
resume_incomplete = options.resume_incomplete == "resume"
131-
132130
return RequirementPreparer(
133131
build_dir=temp_build_dir_path,
134132
src_dir=options.src_dir,
@@ -144,8 +142,7 @@ def make_requirement_preparer(
144142
lazy_wheel=lazy_wheel,
145143
verbosity=verbosity,
146144
legacy_resolver=legacy_resolver,
147-
resume_incomplete=resume_incomplete,
148-
resume_attempts=options.resume_attempts,
145+
resume_retries=options.resume_retries,
149146
)
150147

151148
@classmethod

src/pip/_internal/exceptions.py

+8-20
Original file line numberDiff line numberDiff line change
@@ -776,35 +776,23 @@ def __init__(self, *, distribution: "BaseDistribution") -> None:
776776
hint_stmt=None,
777777
)
778778

779+
779780
class IncompleteDownloadError(DiagnosticPipError):
780781
"""Raised when the downloader receives fewer bytes than advertised
781782
in the Content-Length header."""
782783

783784
reference = "incomplete-download-error"
784785

785-
def __init__(
786-
self, link: str, resume_incomplete: bool, resume_attempts: int
787-
) -> None:
788-
if resume_incomplete:
789-
message = (
790-
"Download failed after {} attempts because not enough bytes are"
791-
" received. The incomplete file has been cleaned up."
792-
).format(resume_attempts)
793-
hint = "Use --incomplete-download-retries to configure resume retry limit."
794-
else:
795-
message = (
796-
"Download failed because not enough bytes are received."
797-
" The incomplete file has been cleaned up."
798-
)
799-
hint = (
800-
"Use --incomplete-downloads=resume to make pip retry failed download."
801-
)
786+
def __init__(self, link: str, resume_retries: int) -> None:
787+
message = (
788+
f"Download failed after {resume_retries} attempts because not enough"
789+
" bytes were received. The incomplete file has been cleaned up."
790+
)
791+
hint = "Use --resume-retries to configure resume retry limit."
802792

803793
super().__init__(
804794
message=message,
805-
context="File: {}\n"
806-
"Resume failed download: {}\n"
807-
"Resume retry limit: {}".format(link, resume_incomplete, resume_attempts),
795+
context=f"File: {link}\nResume retry limit: {resume_retries}",
808796
hint_stmt=hint,
809797
note_stmt="This is an issue with network connectivity, not pip.",
810798
)

0 commit comments

Comments
 (0)