Skip to content

Commit dfd685a

Browse files
authored
Merge branch 'main' into add-docs-for-platform-and-python-version
2 parents 68adf73 + 354e9d4 commit dfd685a

File tree

18 files changed

+545
-74
lines changed

18 files changed

+545
-74
lines changed

docs/html/conf.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,29 @@
1414
# -- General configuration ------------------------------------------------------------
1515

1616
extensions = [
17-
# first-party extensions
18-
"sphinx.ext.autodoc",
19-
"sphinx.ext.todo",
20-
"sphinx.ext.intersphinx",
21-
# our extensions
17+
# extensions common to all builds
2218
"pip_sphinxext",
23-
# third-party extensions
24-
"myst_parser",
25-
"sphinx_copybutton",
26-
"sphinx_inline_tabs",
27-
"sphinxcontrib.towncrier",
28-
"sphinx_issues",
2919
]
3020

21+
# 'tags' is a injected by sphinx
22+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-tags
23+
if "man" not in tags: # type: ignore[name-defined] # noqa: F821
24+
# extensions not needed for building man pages
25+
extensions.extend(
26+
(
27+
# first-party extensions
28+
"sphinx.ext.autodoc",
29+
"sphinx.ext.todo",
30+
"sphinx.ext.intersphinx",
31+
# third-party extensions
32+
"myst_parser",
33+
"sphinx_copybutton",
34+
"sphinx_inline_tabs",
35+
"sphinxcontrib.towncrier",
36+
"sphinx_issues",
37+
),
38+
)
39+
3140
# General information about the project.
3241
project = "pip"
3342
copyright = "The pip developers"

news/12963.feature.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
- Add a ``--group`` option which allows installation from PEP 735 Dependency
2-
Groups. ``--group`` accepts arguments of the form ``group`` or
3-
``path:group``, where the default path is ``pyproject.toml``, and installs
4-
the named Dependency Group from the provided ``pyproject.toml`` file.
1+
Add a ``--group`` option which allows installation from :pep:`735` Dependency
2+
Groups. ``--group`` accepts arguments of the form ``group`` or
3+
``path:group``, where the default path is ``pyproject.toml``, and installs
4+
the named Dependency Group from the provided ``pyproject.toml`` file.

news/12991.feature.rst

Lines changed: 3 additions & 0 deletions
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.

news/13168.doc.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Added support for building only the man pages with minimal dependencies using
2+
the sphinx-build ``--tag man`` option. This enables distributors to generate man
3+
pages without requiring HTML documentation dependencies.

news/13318.removal.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
A warning is emitted when the deprecated ``pkg_resources`` library is used to
2+
inspect and discover installed packages. This warning should only be visible to
3+
users who set an undocumented environment variable to disable the default
4+
``importlib.metadata`` backend.

noxfile.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ def get_sphinx_build_command(kind: str) -> List[str]:
145145
return [
146146
"sphinx-build",
147147
"--keep-going",
148+
"--tag", kind,
148149
"-W",
149150
"-c", "docs/html", # see note above
150151
"-d", "docs/build/doctrees/" + kind,

src/pip/_internal/cli/cmdoptions.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,17 @@ class PipOption(Option):
281281
dest="retries",
282282
type="int",
283283
default=5,
284-
help="Maximum number of retries each connection should attempt "
285-
"(default %default times).",
284+
help="Maximum attempts to establish a new HTTP connection. (default: %default)",
285+
)
286+
287+
resume_retries: Callable[..., Option] = partial(
288+
Option,
289+
"--resume-retries",
290+
dest="resume_retries",
291+
type="int",
292+
default=0,
293+
help="Maximum attempts to resume or restart an incomplete download. "
294+
"(default: %default)",
286295
)
287296

288297
timeout: Callable[..., Option] = partial(
@@ -1077,7 +1086,6 @@ def check_list_path_option(options: Values) -> None:
10771086
help=("Enable deprecated functionality, that will be removed in the future."),
10781087
)
10791088

1080-
10811089
##########
10821090
# groups #
10831091
##########
@@ -1110,6 +1118,7 @@ def check_list_path_option(options: Values) -> None:
11101118
no_python_version_warning,
11111119
use_new_feature,
11121120
use_deprecated_feature,
1121+
resume_retries,
11131122
],
11141123
}
11151124

src/pip/_internal/cli/progress_bars.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def _rich_download_progress_bar(
2929
*,
3030
bar_type: str,
3131
size: Optional[int],
32+
initial_progress: Optional[int] = None,
3233
) -> Generator[bytes, None, None]:
3334
assert bar_type == "on", "This should only be used in the default mode."
3435

@@ -54,6 +55,8 @@ def _rich_download_progress_bar(
5455

5556
progress = Progress(*columns, refresh_per_second=5)
5657
task_id = progress.add_task(" " * (get_indentation() + 2), total=total)
58+
if initial_progress is not None:
59+
progress.update(task_id, advance=initial_progress)
5760
with progress:
5861
for chunk in iterable:
5962
yield chunk
@@ -86,12 +89,13 @@ def _raw_progress_bar(
8689
iterable: Iterable[bytes],
8790
*,
8891
size: Optional[int],
92+
initial_progress: Optional[int] = None,
8993
) -> Generator[bytes, None, None]:
9094
def write_progress(current: int, total: int) -> None:
9195
sys.stdout.write(f"Progress {current} of {total}\n")
9296
sys.stdout.flush()
9397

94-
current = 0
98+
current = initial_progress or 0
9599
total = size or 0
96100
rate_limiter = RateLimiter(0.25)
97101

@@ -105,18 +109,25 @@ def write_progress(current: int, total: int) -> None:
105109

106110

107111
def get_download_progress_renderer(
108-
*, bar_type: str, size: Optional[int] = None
112+
*, bar_type: str, size: Optional[int] = None, initial_progress: Optional[int] = None
109113
) -> ProgressRenderer[bytes]:
110114
"""Get an object that can be used to render the download progress.
111115
112116
Returns a callable, that takes an iterable to "wrap".
113117
"""
114118
if bar_type == "on":
115119
return functools.partial(
116-
_rich_download_progress_bar, bar_type=bar_type, size=size
120+
_rich_download_progress_bar,
121+
bar_type=bar_type,
122+
size=size,
123+
initial_progress=initial_progress,
117124
)
118125
elif bar_type == "raw":
119-
return functools.partial(_raw_progress_bar, size=size)
126+
return functools.partial(
127+
_raw_progress_bar,
128+
size=size,
129+
initial_progress=initial_progress,
130+
)
120131
else:
121132
return iter # no-op, when passed an iterator
122133

src/pip/_internal/cli/req_command.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ def make_requirement_preparer(
144144
lazy_wheel=lazy_wheel,
145145
verbosity=verbosity,
146146
legacy_resolver=legacy_resolver,
147+
resume_retries=options.resume_retries,
147148
)
148149

149150
@classmethod

src/pip/_internal/exceptions.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from pip._vendor.requests.models import Request, Response
2828

2929
from pip._internal.metadata import BaseDistribution
30+
from pip._internal.models.link import Link
3031
from pip._internal.req.req_install import InstallRequirement
3132

3233
logger = logging.getLogger(__name__)
@@ -809,6 +810,38 @@ def __init__(
809810
)
810811

811812

813+
class IncompleteDownloadError(DiagnosticPipError):
814+
"""Raised when the downloader receives fewer bytes than advertised
815+
in the Content-Length header."""
816+
817+
reference = "incomplete-download"
818+
819+
def __init__(
820+
self, link: "Link", received: int, expected: int, *, retries: int
821+
) -> None:
822+
# Dodge circular import.
823+
from pip._internal.utils.misc import format_size
824+
825+
download_status = f"{format_size(received)}/{format_size(expected)}"
826+
if retries:
827+
retry_status = f"after {retries} attempts "
828+
hint = "Use --resume-retries to configure resume attempt limit."
829+
else:
830+
retry_status = ""
831+
hint = "Consider using --resume-retries to enable download resumption."
832+
message = Text(
833+
f"Download failed {retry_status}because not enough bytes "
834+
f"were received ({download_status})"
835+
)
836+
837+
super().__init__(
838+
message=message,
839+
context=f"URL: {link.redacted_url}",
840+
hint_stmt=hint,
841+
note_stmt="This is an issue with network connectivity, not pip.",
842+
)
843+
844+
812845
class ResolutionTooDeepError(DiagnosticPipError):
813846
"""Raised when the dependency resolver exceeds the maximum recursion depth."""
814847

0 commit comments

Comments
 (0)