pip 25.0.1__py3-none-any.whl → 25.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. pip/__init__.py +1 -1
  2. pip/__pip-runner__.py +1 -1
  3. pip/_internal/build_env.py +5 -2
  4. pip/_internal/cache.py +1 -2
  5. pip/_internal/cli/__init__.py +1 -2
  6. pip/_internal/cli/autocompletion.py +1 -2
  7. pip/_internal/cli/base_command.py +2 -9
  8. pip/_internal/cli/cmdoptions.py +64 -6
  9. pip/_internal/cli/index_command.py +2 -0
  10. pip/_internal/cli/main.py +1 -2
  11. pip/_internal/cli/main_parser.py +1 -2
  12. pip/_internal/cli/progress_bars.py +59 -9
  13. pip/_internal/cli/req_command.py +19 -1
  14. pip/_internal/commands/__init__.py +5 -0
  15. pip/_internal/commands/completion.py +11 -5
  16. pip/_internal/commands/freeze.py +0 -1
  17. pip/_internal/commands/index.py +24 -10
  18. pip/_internal/commands/install.py +9 -0
  19. pip/_internal/commands/list.py +21 -5
  20. pip/_internal/commands/lock.py +171 -0
  21. pip/_internal/commands/search.py +14 -10
  22. pip/_internal/commands/show.py +9 -5
  23. pip/_internal/commands/wheel.py +2 -2
  24. pip/_internal/exceptions.py +53 -0
  25. pip/_internal/index/__init__.py +1 -2
  26. pip/_internal/index/package_finder.py +37 -16
  27. pip/_internal/locations/__init__.py +1 -18
  28. pip/_internal/metadata/__init__.py +47 -13
  29. pip/_internal/metadata/base.py +3 -1
  30. pip/_internal/metadata/importlib/_envs.py +11 -60
  31. pip/_internal/models/__init__.py +1 -2
  32. pip/_internal/models/direct_url.py +1 -1
  33. pip/_internal/models/link.py +7 -3
  34. pip/_internal/models/pylock.py +183 -0
  35. pip/_internal/models/wheel.py +64 -43
  36. pip/_internal/network/__init__.py +1 -2
  37. pip/_internal/network/cache.py +1 -2
  38. pip/_internal/network/download.py +170 -43
  39. pip/_internal/network/xmlrpc.py +1 -2
  40. pip/_internal/operations/build/metadata.py +1 -2
  41. pip/_internal/operations/build/metadata_editable.py +1 -2
  42. pip/_internal/operations/build/metadata_legacy.py +1 -2
  43. pip/_internal/operations/build/wheel_legacy.py +16 -0
  44. pip/_internal/operations/check.py +1 -2
  45. pip/_internal/operations/install/__init__.py +1 -2
  46. pip/_internal/operations/install/editable_legacy.py +1 -2
  47. pip/_internal/operations/install/wheel.py +10 -14
  48. pip/_internal/operations/prepare.py +10 -5
  49. pip/_internal/req/__init__.py +14 -1
  50. pip/_internal/req/req_dependency_group.py +74 -0
  51. pip/_internal/req/req_install.py +2 -2
  52. pip/_internal/req/req_uninstall.py +7 -4
  53. pip/_internal/resolution/resolvelib/candidates.py +6 -1
  54. pip/_internal/resolution/resolvelib/factory.py +1 -1
  55. pip/_internal/resolution/resolvelib/found_candidates.py +10 -20
  56. pip/_internal/resolution/resolvelib/provider.py +88 -65
  57. pip/_internal/resolution/resolvelib/reporter.py +6 -4
  58. pip/_internal/resolution/resolvelib/resolver.py +5 -2
  59. pip/_internal/utils/appdirs.py +2 -1
  60. pip/_internal/utils/compatibility_tags.py +14 -2
  61. pip/_internal/utils/datetime.py +1 -2
  62. pip/_internal/utils/entrypoints.py +4 -1
  63. pip/_internal/utils/filetypes.py +1 -2
  64. pip/_internal/utils/logging.py +20 -13
  65. pip/_internal/utils/misc.py +0 -18
  66. pip/_internal/utils/packaging.py +2 -17
  67. pip/_internal/utils/setuptools_build.py +5 -4
  68. pip/_internal/utils/unpacking.py +1 -3
  69. pip/_internal/utils/wheel.py +1 -2
  70. pip/_internal/vcs/git.py +10 -1
  71. pip/_internal/wheel_builder.py +5 -27
  72. pip/_vendor/__init__.py +1 -0
  73. pip/_vendor/cachecontrol/__init__.py +1 -1
  74. pip/_vendor/cachecontrol/adapter.py +13 -6
  75. pip/_vendor/cachecontrol/caches/file_cache.py +10 -47
  76. pip/_vendor/cachecontrol/controller.py +12 -1
  77. pip/_vendor/certifi/__init__.py +1 -1
  78. pip/_vendor/certifi/cacert.pem +122 -154
  79. pip/_vendor/dependency_groups/__init__.py +13 -0
  80. pip/_vendor/dependency_groups/__main__.py +65 -0
  81. pip/_vendor/dependency_groups/_implementation.py +213 -0
  82. pip/_vendor/dependency_groups/_lint_dependency_groups.py +59 -0
  83. pip/_vendor/dependency_groups/_pip_wrapper.py +62 -0
  84. pip/_vendor/dependency_groups/_toml_compat.py +9 -0
  85. pip/_vendor/packaging/__init__.py +1 -1
  86. pip/_vendor/packaging/_elffile.py +1 -2
  87. pip/_vendor/packaging/_manylinux.py +1 -2
  88. pip/_vendor/packaging/_parser.py +1 -2
  89. pip/_vendor/packaging/_tokenizer.py +5 -4
  90. pip/_vendor/packaging/licenses/__init__.py +1 -1
  91. pip/_vendor/packaging/markers.py +53 -22
  92. pip/_vendor/packaging/metadata.py +1 -2
  93. pip/_vendor/packaging/specifiers.py +1 -2
  94. pip/_vendor/packaging/tags.py +39 -0
  95. pip/_vendor/platformdirs/__init__.py +20 -20
  96. pip/_vendor/platformdirs/android.py +3 -3
  97. pip/_vendor/platformdirs/api.py +3 -2
  98. pip/_vendor/platformdirs/unix.py +4 -1
  99. pip/_vendor/platformdirs/version.py +9 -4
  100. pip/_vendor/pygments/__init__.py +2 -2
  101. pip/_vendor/pygments/__main__.py +1 -1
  102. pip/_vendor/pygments/console.py +1 -1
  103. pip/_vendor/pygments/filter.py +1 -1
  104. pip/_vendor/pygments/filters/__init__.py +1 -1
  105. pip/_vendor/pygments/formatter.py +1 -1
  106. pip/_vendor/pygments/formatters/__init__.py +1 -1
  107. pip/_vendor/pygments/lexer.py +1 -1
  108. pip/_vendor/pygments/lexers/__init__.py +1 -1
  109. pip/_vendor/pygments/lexers/_mapping.py +16 -3
  110. pip/_vendor/pygments/lexers/python.py +27 -24
  111. pip/_vendor/pygments/modeline.py +1 -1
  112. pip/_vendor/pygments/plugin.py +1 -1
  113. pip/_vendor/pygments/regexopt.py +1 -1
  114. pip/_vendor/pygments/scanner.py +1 -1
  115. pip/_vendor/pygments/sphinxext.py +1 -1
  116. pip/_vendor/pygments/style.py +1 -1
  117. pip/_vendor/pygments/styles/__init__.py +1 -1
  118. pip/_vendor/pygments/token.py +1 -1
  119. pip/_vendor/pygments/unistring.py +1 -1
  120. pip/_vendor/pygments/util.py +1 -1
  121. pip/_vendor/resolvelib/__init__.py +3 -2
  122. pip/_vendor/resolvelib/providers.py +103 -40
  123. pip/_vendor/resolvelib/reporters.py +21 -9
  124. pip/_vendor/resolvelib/resolvers/__init__.py +27 -0
  125. pip/_vendor/resolvelib/resolvers/abstract.py +47 -0
  126. pip/_vendor/resolvelib/resolvers/criterion.py +48 -0
  127. pip/_vendor/resolvelib/resolvers/exceptions.py +57 -0
  128. pip/_vendor/resolvelib/{resolvers.py → resolvers/resolution.py} +211 -217
  129. pip/_vendor/resolvelib/structs.py +93 -54
  130. pip/_vendor/rich/console.py +21 -7
  131. pip/_vendor/rich/default_styles.py +3 -1
  132. pip/_vendor/rich/diagnose.py +7 -6
  133. pip/_vendor/rich/panel.py +1 -1
  134. pip/_vendor/rich/style.py +1 -1
  135. pip/_vendor/rich/table.py +0 -1
  136. pip/_vendor/rich/traceback.py +129 -42
  137. pip/_vendor/tomli_w/__init__.py +4 -0
  138. pip/_vendor/tomli_w/_writer.py +229 -0
  139. pip/_vendor/tomli_w/py.typed +1 -0
  140. pip/_vendor/truststore/__init__.py +2 -2
  141. pip/_vendor/truststore/_api.py +18 -1
  142. pip/_vendor/typing_extensions.py +1027 -84
  143. pip/_vendor/vendor.txt +11 -9
  144. {pip-25.0.1.dist-info → pip-25.1.dist-info}/METADATA +4 -4
  145. {pip-25.0.1.dist-info → pip-25.1.dist-info}/RECORD +151 -149
  146. {pip-25.0.1.dist-info → pip-25.1.dist-info}/WHEEL +1 -1
  147. {pip-25.0.1.dist-info → pip-25.1.dist-info/licenses}/AUTHORS.txt +15 -0
  148. pip/_vendor/pygments/cmdline.py +0 -668
  149. pip/_vendor/pygments/formatters/bbcode.py +0 -108
  150. pip/_vendor/pygments/formatters/groff.py +0 -170
  151. pip/_vendor/pygments/formatters/html.py +0 -987
  152. pip/_vendor/pygments/formatters/img.py +0 -685
  153. pip/_vendor/pygments/formatters/irc.py +0 -154
  154. pip/_vendor/pygments/formatters/latex.py +0 -518
  155. pip/_vendor/pygments/formatters/other.py +0 -160
  156. pip/_vendor/pygments/formatters/pangomarkup.py +0 -83
  157. pip/_vendor/pygments/formatters/rtf.py +0 -349
  158. pip/_vendor/pygments/formatters/svg.py +0 -185
  159. pip/_vendor/pygments/formatters/terminal.py +0 -127
  160. pip/_vendor/pygments/formatters/terminal256.py +0 -338
  161. pip/_vendor/resolvelib/compat/collections_abc.py +0 -6
  162. /pip/_vendor/{resolvelib/compat/__init__.py → dependency_groups/py.typed} +0 -0
  163. {pip-25.0.1.dist-info → pip-25.1.dist-info}/entry_points.txt +0 -0
  164. {pip-25.0.1.dist-info → pip-25.1.dist-info/licenses}/LICENSE.txt +0 -0
  165. {pip-25.0.1.dist-info → pip-25.1.dist-info}/top_level.txt +0 -0
pip/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from typing import List, Optional
2
2
 
3
- __version__ = "25.0.1"
3
+ __version__ = "25.1"
4
4
 
5
5
 
6
6
  def main(args: Optional[List[str]] = None) -> int:
pip/__pip-runner__.py CHANGED
@@ -9,7 +9,7 @@ an import statement.
9
9
  import sys
10
10
 
11
11
  # Copied from pyproject.toml
12
- PYTHON_REQUIRES = (3, 8)
12
+ PYTHON_REQUIRES = (3, 9)
13
13
 
14
14
 
15
15
  def version_str(version): # type: ignore
@@ -1,5 +1,4 @@
1
- """Build Environment used for isolation during sdist building
2
- """
1
+ """Build Environment used for isolation during sdist building"""
3
2
 
4
3
  import logging
5
4
  import os
@@ -241,6 +240,10 @@ class BuildEnvironment:
241
240
  prefix.path,
242
241
  "--no-warn-script-location",
243
242
  "--disable-pip-version-check",
243
+ # As the build environment is ephemeral, it's wasteful to
244
+ # pre-compile everything, especially as not every Python
245
+ # module will be used/compiled in most cases.
246
+ "--no-compile",
244
247
  # The prefix specified two lines above, thus
245
248
  # target from config file or env var should be ignored
246
249
  "--target",
pip/_internal/cache.py CHANGED
@@ -1,5 +1,4 @@
1
- """Cache Management
2
- """
1
+ """Cache Management"""
3
2
 
4
3
  import hashlib
5
4
  import json
@@ -1,4 +1,3 @@
1
- """Subpackage containing all of pip's command line interface related code
2
- """
1
+ """Subpackage containing all of pip's command line interface related code"""
3
2
 
4
3
  # This file intentionally does not import submodules
@@ -1,5 +1,4 @@
1
- """Logic that powers autocompletion installed by ``pip completion``.
2
- """
1
+ """Logic that powers autocompletion installed by ``pip completion``."""
3
2
 
4
3
  import optparse
5
4
  import os
@@ -29,7 +29,6 @@ from pip._internal.exceptions import (
29
29
  NetworkConnectionError,
30
30
  PreviousBuildDirError,
31
31
  )
32
- from pip._internal.utils.deprecation import deprecated
33
32
  from pip._internal.utils.filesystem import check_path_owner
34
33
  from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging
35
34
  from pip._internal.utils.misc import get_prog, normalize_path
@@ -172,6 +171,8 @@ class Command(CommandContextMixIn):
172
171
 
173
172
  # Set verbosity so that it can be used elsewhere.
174
173
  self.verbosity = options.verbose - options.quiet
174
+ if options.debug_mode:
175
+ self.verbosity = 2
175
176
 
176
177
  reconfigure(no_color=options.no_color)
177
178
  level_number = setup_logging(
@@ -229,12 +230,4 @@ class Command(CommandContextMixIn):
229
230
  )
230
231
  options.cache_dir = None
231
232
 
232
- if options.no_python_version_warning:
233
- deprecated(
234
- reason="--no-python-version-warning is deprecated.",
235
- replacement="to remove the flag as it's a no-op",
236
- gone_in="25.1",
237
- issue=13154,
238
- )
239
-
240
233
  return self._run_wrapper(level_number, options, args)
@@ -13,6 +13,7 @@ pass on state. To be consistent, all options will follow this design.
13
13
  import importlib.util
14
14
  import logging
15
15
  import os
16
+ import pathlib
16
17
  import textwrap
17
18
  from functools import partial
18
19
  from optparse import SUPPRESS_HELP, Option, OptionGroup, OptionParser, Values
@@ -280,8 +281,17 @@ retries: Callable[..., Option] = partial(
280
281
  dest="retries",
281
282
  type="int",
282
283
  default=5,
283
- help="Maximum number of retries each connection should attempt "
284
- "(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)",
285
295
  )
286
296
 
287
297
  timeout: Callable[..., Option] = partial(
@@ -733,6 +743,46 @@ no_deps: Callable[..., Option] = partial(
733
743
  help="Don't install package dependencies.",
734
744
  )
735
745
 
746
+
747
+ def _handle_dependency_group(
748
+ option: Option, opt: str, value: str, parser: OptionParser
749
+ ) -> None:
750
+ """
751
+ Process a value provided for the --group option.
752
+
753
+ Splits on the rightmost ":", and validates that the path (if present) ends
754
+ in `pyproject.toml`. Defaults the path to `pyproject.toml` when one is not given.
755
+
756
+ `:` cannot appear in dependency group names, so this is a safe and simple parse.
757
+
758
+ This is an optparse.Option callback for the dependency_groups option.
759
+ """
760
+ path, sep, groupname = value.rpartition(":")
761
+ if not sep:
762
+ path = "pyproject.toml"
763
+ else:
764
+ # check for 'pyproject.toml' filenames using pathlib
765
+ if pathlib.PurePath(path).name != "pyproject.toml":
766
+ msg = "group paths use 'pyproject.toml' filenames"
767
+ raise_option_error(parser, option=option, msg=msg)
768
+
769
+ parser.values.dependency_groups.append((path, groupname))
770
+
771
+
772
+ dependency_groups: Callable[..., Option] = partial(
773
+ Option,
774
+ "--group",
775
+ dest="dependency_groups",
776
+ default=[],
777
+ type=str,
778
+ action="callback",
779
+ callback=_handle_dependency_group,
780
+ metavar="[path:]group",
781
+ help='Install a named dependency-group from a "pyproject.toml" file. '
782
+ 'If a path is given, the name of the file must be "pyproject.toml". '
783
+ 'Defaults to using "pyproject.toml" in the current directory.',
784
+ )
785
+
736
786
  ignore_requires_python: Callable[..., Option] = partial(
737
787
  Option,
738
788
  "--ignore-requires-python",
@@ -783,9 +833,9 @@ def _handle_no_use_pep517(
783
833
  """
784
834
  raise_option_error(parser, option=option, msg=msg)
785
835
 
786
- # If user doesn't wish to use pep517, we check if setuptools and wheel are installed
836
+ # If user doesn't wish to use pep517, we check if setuptools is installed
787
837
  # and raise error if it is not.
788
- packages = ("setuptools", "wheel")
838
+ packages = ("setuptools",)
789
839
  if not all(importlib.util.find_spec(package) for package in packages):
790
840
  msg = (
791
841
  f"It is not possible to use --no-use-pep517 "
@@ -887,6 +937,14 @@ pre: Callable[..., Option] = partial(
887
937
  "pip only finds stable versions.",
888
938
  )
889
939
 
940
+ json: Callable[..., Option] = partial(
941
+ Option,
942
+ "--json",
943
+ action="store_true",
944
+ default=False,
945
+ help="Output data in a machine-readable JSON format.",
946
+ )
947
+
890
948
  disable_pip_version_check: Callable[..., Option] = partial(
891
949
  Option,
892
950
  "--disable-pip-version-check",
@@ -990,7 +1048,7 @@ no_python_version_warning: Callable[..., Option] = partial(
990
1048
  dest="no_python_version_warning",
991
1049
  action="store_true",
992
1050
  default=False,
993
- help="Silence deprecation warnings for upcoming unsupported Pythons.",
1051
+ help=SUPPRESS_HELP, # No-op, a hold-over from the Python 2->3 transition.
994
1052
  )
995
1053
 
996
1054
 
@@ -1028,7 +1086,6 @@ use_deprecated_feature: Callable[..., Option] = partial(
1028
1086
  help=("Enable deprecated functionality, that will be removed in the future."),
1029
1087
  )
1030
1088
 
1031
-
1032
1089
  ##########
1033
1090
  # groups #
1034
1091
  ##########
@@ -1061,6 +1118,7 @@ general_group: Dict[str, Any] = {
1061
1118
  no_python_version_warning,
1062
1119
  use_new_feature,
1063
1120
  use_deprecated_feature,
1121
+ resume_retries,
1064
1122
  ],
1065
1123
  }
1066
1124
 
@@ -9,6 +9,7 @@ so commands which don't always hit the network (e.g. list w/o --outdated or
9
9
  import logging
10
10
  import os
11
11
  import sys
12
+ from functools import lru_cache
12
13
  from optparse import Values
13
14
  from typing import TYPE_CHECKING, List, Optional
14
15
 
@@ -25,6 +26,7 @@ if TYPE_CHECKING:
25
26
  logger = logging.getLogger(__name__)
26
27
 
27
28
 
29
+ @lru_cache
28
30
  def _create_truststore_ssl_context() -> Optional["SSLContext"]:
29
31
  if sys.version_info < (3, 10):
30
32
  logger.debug("Disabling truststore because Python version isn't 3.10+")
pip/_internal/cli/main.py CHANGED
@@ -1,5 +1,4 @@
1
- """Primary application entrypoint.
2
- """
1
+ """Primary application entrypoint."""
3
2
 
4
3
  import locale
5
4
  import logging
@@ -1,5 +1,4 @@
1
- """A single place for constructing and exposing the main parser
2
- """
1
+ """A single place for constructing and exposing the main parser"""
3
2
 
4
3
  import os
5
4
  import subprocess
@@ -1,11 +1,12 @@
1
1
  import functools
2
2
  import sys
3
- from typing import Callable, Generator, Iterable, Iterator, Optional, Tuple
3
+ from typing import Callable, Generator, Iterable, Iterator, Optional, Tuple, TypeVar
4
4
 
5
5
  from pip._vendor.rich.progress import (
6
6
  BarColumn,
7
7
  DownloadColumn,
8
8
  FileSizeColumn,
9
+ MofNCompleteColumn,
9
10
  Progress,
10
11
  ProgressColumn,
11
12
  SpinnerColumn,
@@ -16,16 +17,19 @@ from pip._vendor.rich.progress import (
16
17
  )
17
18
 
18
19
  from pip._internal.cli.spinners import RateLimiter
19
- from pip._internal.utils.logging import get_indentation
20
+ from pip._internal.req.req_install import InstallRequirement
21
+ from pip._internal.utils.logging import get_console, get_indentation
20
22
 
21
- DownloadProgressRenderer = Callable[[Iterable[bytes]], Iterator[bytes]]
23
+ T = TypeVar("T")
24
+ ProgressRenderer = Callable[[Iterable[T]], Iterator[T]]
22
25
 
23
26
 
24
- def _rich_progress_bar(
27
+ def _rich_download_progress_bar(
25
28
  iterable: Iterable[bytes],
26
29
  *,
27
30
  bar_type: str,
28
31
  size: Optional[int],
32
+ initial_progress: Optional[int] = None,
29
33
  ) -> Generator[bytes, None, None]:
30
34
  assert bar_type == "on", "This should only be used in the default mode."
31
35
 
@@ -51,22 +55,47 @@ def _rich_progress_bar(
51
55
 
52
56
  progress = Progress(*columns, refresh_per_second=5)
53
57
  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)
54
60
  with progress:
55
61
  for chunk in iterable:
56
62
  yield chunk
57
63
  progress.update(task_id, advance=len(chunk))
58
64
 
59
65
 
66
+ def _rich_install_progress_bar(
67
+ iterable: Iterable[InstallRequirement], *, total: int
68
+ ) -> Iterator[InstallRequirement]:
69
+ columns = (
70
+ TextColumn("{task.fields[indent]}"),
71
+ BarColumn(),
72
+ MofNCompleteColumn(),
73
+ TextColumn("{task.description}"),
74
+ )
75
+ console = get_console()
76
+
77
+ bar = Progress(*columns, refresh_per_second=6, console=console, transient=True)
78
+ # Hiding the progress bar at initialization forces a refresh cycle to occur
79
+ # until the bar appears, avoiding very short flashes.
80
+ task = bar.add_task("", total=total, indent=" " * get_indentation(), visible=False)
81
+ with bar:
82
+ for req in iterable:
83
+ bar.update(task, description=rf"\[{req.name}]", visible=True)
84
+ yield req
85
+ bar.advance(task)
86
+
87
+
60
88
  def _raw_progress_bar(
61
89
  iterable: Iterable[bytes],
62
90
  *,
63
91
  size: Optional[int],
92
+ initial_progress: Optional[int] = None,
64
93
  ) -> Generator[bytes, None, None]:
65
94
  def write_progress(current: int, total: int) -> None:
66
95
  sys.stdout.write(f"Progress {current} of {total}\n")
67
96
  sys.stdout.flush()
68
97
 
69
- current = 0
98
+ current = initial_progress or 0
70
99
  total = size or 0
71
100
  rate_limiter = RateLimiter(0.25)
72
101
 
@@ -80,15 +109,36 @@ def _raw_progress_bar(
80
109
 
81
110
 
82
111
  def get_download_progress_renderer(
83
- *, bar_type: str, size: Optional[int] = None
84
- ) -> DownloadProgressRenderer:
112
+ *, bar_type: str, size: Optional[int] = None, initial_progress: Optional[int] = None
113
+ ) -> ProgressRenderer[bytes]:
85
114
  """Get an object that can be used to render the download progress.
86
115
 
87
116
  Returns a callable, that takes an iterable to "wrap".
88
117
  """
89
118
  if bar_type == "on":
90
- return functools.partial(_rich_progress_bar, bar_type=bar_type, size=size)
119
+ return functools.partial(
120
+ _rich_download_progress_bar,
121
+ bar_type=bar_type,
122
+ size=size,
123
+ initial_progress=initial_progress,
124
+ )
91
125
  elif bar_type == "raw":
92
- 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
+ )
93
131
  else:
94
132
  return iter # no-op, when passed an iterator
133
+
134
+
135
+ def get_install_progress_renderer(
136
+ *, bar_type: str, total: int
137
+ ) -> ProgressRenderer[InstallRequirement]:
138
+ """Get an object that can be used to render the install progress.
139
+ Returns a callable, that takes an iterable to "wrap".
140
+ """
141
+ if bar_type == "on":
142
+ return functools.partial(_rich_install_progress_bar, total=total)
143
+ else:
144
+ return iter
@@ -28,6 +28,7 @@ from pip._internal.req.constructors import (
28
28
  install_req_from_parsed_requirement,
29
29
  install_req_from_req_string,
30
30
  )
31
+ from pip._internal.req.req_dependency_group import parse_dependency_groups
31
32
  from pip._internal.req.req_file import parse_requirements
32
33
  from pip._internal.req.req_install import InstallRequirement
33
34
  from pip._internal.resolution.base import BaseResolver
@@ -79,6 +80,7 @@ class RequirementCommand(IndexGroupCommand):
79
80
  def __init__(self, *args: Any, **kw: Any) -> None:
80
81
  super().__init__(*args, **kw)
81
82
 
83
+ self.cmd_opts.add_option(cmdoptions.dependency_groups())
82
84
  self.cmd_opts.add_option(cmdoptions.no_clean())
83
85
 
84
86
  @staticmethod
@@ -142,6 +144,7 @@ class RequirementCommand(IndexGroupCommand):
142
144
  lazy_wheel=lazy_wheel,
143
145
  verbosity=verbosity,
144
146
  legacy_resolver=legacy_resolver,
147
+ resume_retries=options.resume_retries,
145
148
  )
146
149
 
147
150
  @classmethod
@@ -240,6 +243,16 @@ class RequirementCommand(IndexGroupCommand):
240
243
  )
241
244
  requirements.append(req_to_add)
242
245
 
246
+ if options.dependency_groups:
247
+ for req in parse_dependency_groups(options.dependency_groups):
248
+ req_to_add = install_req_from_req_string(
249
+ req,
250
+ isolated=options.isolated_mode,
251
+ use_pep517=options.use_pep517,
252
+ user_supplied=True,
253
+ )
254
+ requirements.append(req_to_add)
255
+
243
256
  for req in options.editables:
244
257
  req_to_add = install_req_from_editable(
245
258
  req,
@@ -272,7 +285,12 @@ class RequirementCommand(IndexGroupCommand):
272
285
  if any(req.has_hash_options for req in requirements):
273
286
  options.require_hashes = True
274
287
 
275
- if not (args or options.editables or options.requirements):
288
+ if not (
289
+ args
290
+ or options.editables
291
+ or options.requirements
292
+ or options.dependency_groups
293
+ ):
276
294
  opts = {"name": self.name}
277
295
  if options.find_links:
278
296
  raise CommandError(
@@ -23,6 +23,11 @@ commands_dict: Dict[str, CommandInfo] = {
23
23
  "InstallCommand",
24
24
  "Install packages.",
25
25
  ),
26
+ "lock": CommandInfo(
27
+ "pip._internal.commands.lock",
28
+ "LockCommand",
29
+ "Generate a lock file.",
30
+ ),
26
31
  "download": CommandInfo(
27
32
  "pip._internal.commands.download",
28
33
  "DownloadCommand",
@@ -38,12 +38,18 @@ COMPLETION_SCRIPTS = {
38
38
  """,
39
39
  "fish": """
40
40
  function __fish_complete_pip
41
- set -lx COMP_WORDS (commandline -o) ""
42
- set -lx COMP_CWORD ( \\
43
- math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\
44
- )
41
+ set -lx COMP_WORDS \\
42
+ (commandline --current-process --tokenize --cut-at-cursor) \\
43
+ (commandline --current-token --cut-at-cursor)
44
+ set -lx COMP_CWORD (math (count $COMP_WORDS) - 1)
45
45
  set -lx PIP_AUTO_COMPLETE 1
46
- string split \\ -- (eval $COMP_WORDS[1])
46
+ set -l completions
47
+ if string match -q '2.*' $version
48
+ set completions (eval $COMP_WORDS[1])
49
+ else
50
+ set completions ($COMP_WORDS[1])
51
+ end
52
+ string split \\ -- $completions
47
53
  end
48
54
  complete -fa "(__fish_complete_pip)" -c {prog}
49
55
  """,
@@ -32,7 +32,6 @@ class FreezeCommand(Command):
32
32
  ignore_require_venv = True
33
33
  usage = """
34
34
  %prog [options]"""
35
- log_streams = ("ext://sys.stderr", "ext://sys.stderr")
36
35
 
37
36
  def add_options(self) -> None:
38
37
  self.cmd_opts.add_option(
@@ -1,3 +1,4 @@
1
+ import json
1
2
  import logging
2
3
  from optparse import Values
3
4
  from typing import Any, Iterable, List, Optional
@@ -7,7 +8,10 @@ from pip._vendor.packaging.version import Version
7
8
  from pip._internal.cli import cmdoptions
8
9
  from pip._internal.cli.req_command import IndexGroupCommand
9
10
  from pip._internal.cli.status_codes import ERROR, SUCCESS
10
- from pip._internal.commands.search import print_dist_installation_info
11
+ from pip._internal.commands.search import (
12
+ get_installed_distribution,
13
+ print_dist_installation_info,
14
+ )
11
15
  from pip._internal.exceptions import CommandError, DistributionNotFound, PipError
12
16
  from pip._internal.index.collector import LinkCollector
13
17
  from pip._internal.index.package_finder import PackageFinder
@@ -34,6 +38,7 @@ class IndexCommand(IndexGroupCommand):
34
38
 
35
39
  self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
36
40
  self.cmd_opts.add_option(cmdoptions.pre())
41
+ self.cmd_opts.add_option(cmdoptions.json())
37
42
  self.cmd_opts.add_option(cmdoptions.no_binary())
38
43
  self.cmd_opts.add_option(cmdoptions.only_binary())
39
44
 
@@ -50,12 +55,6 @@ class IndexCommand(IndexGroupCommand):
50
55
  "versions": self.get_available_package_versions,
51
56
  }
52
57
 
53
- logger.warning(
54
- "pip index is currently an experimental command. "
55
- "It may be removed/changed in a future release "
56
- "without prior warning."
57
- )
58
-
59
58
  # Determine action
60
59
  if not args or args[0] not in handlers:
61
60
  logger.error(
@@ -134,6 +133,21 @@ class IndexCommand(IndexGroupCommand):
134
133
  formatted_versions = [str(ver) for ver in sorted(versions, reverse=True)]
135
134
  latest = formatted_versions[0]
136
135
 
137
- write_output(f"{query} ({latest})")
138
- write_output("Available versions: {}".format(", ".join(formatted_versions)))
139
- print_dist_installation_info(query, latest)
136
+ dist = get_installed_distribution(query)
137
+
138
+ if options.json:
139
+ structured_output = {
140
+ "name": query,
141
+ "versions": formatted_versions,
142
+ "latest": latest,
143
+ }
144
+
145
+ if dist is not None:
146
+ structured_output["installed_version"] = str(dist.version)
147
+
148
+ write_output(json.dumps(structured_output))
149
+
150
+ else:
151
+ write_output(f"{query} ({latest})")
152
+ write_output("Available versions: {}".format(", ".join(formatted_versions)))
153
+ print_dist_installation_info(latest, dist)
@@ -8,6 +8,7 @@ from optparse import SUPPRESS_HELP, Values
8
8
  from typing import List, Optional
9
9
 
10
10
  from pip._vendor.packaging.utils import canonicalize_name
11
+ from pip._vendor.requests.exceptions import InvalidProxyURL
11
12
  from pip._vendor.rich import print_json
12
13
 
13
14
  # Eagerly import self_outdated_check to avoid crashes. Otherwise,
@@ -464,6 +465,7 @@ class InstallCommand(RequirementCommand):
464
465
  warn_script_location=warn_script_location,
465
466
  use_user_site=options.use_user_site,
466
467
  pycompile=options.compile,
468
+ progress_bar=options.progress_bar,
467
469
  )
468
470
 
469
471
  lib_locations = get_lib_location_guesses(
@@ -765,6 +767,13 @@ def create_os_error_message(
765
767
  parts.append(permissions_part)
766
768
  parts.append(".\n")
767
769
 
770
+ # Suggest to check "pip config debug" in case of invalid proxy
771
+ if type(error) is InvalidProxyURL:
772
+ parts.append(
773
+ 'Consider checking your local proxy configuration with "pip config debug"'
774
+ )
775
+ parts.append(".\n")
776
+
768
777
  # Suggest the user to enable Long Paths if path length is
769
778
  # more than 260
770
779
  if (
@@ -1,5 +1,6 @@
1
1
  import json
2
2
  import logging
3
+ from email.parser import Parser
3
4
  from optparse import Values
4
5
  from typing import TYPE_CHECKING, Generator, List, Optional, Sequence, Tuple, cast
5
6
 
@@ -125,7 +126,7 @@ class ListCommand(IndexGroupCommand):
125
126
  "--include-editable",
126
127
  action="store_true",
127
128
  dest="include_editable",
128
- help="Include editable package from output.",
129
+ help="Include editable package in output.",
129
130
  default=True,
130
131
  )
131
132
  self.cmd_opts.add_option(cmdoptions.list_exclude())
@@ -323,17 +324,29 @@ def format_for_columns(
323
324
  if running_outdated:
324
325
  header.extend(["Latest", "Type"])
325
326
 
326
- has_editables = any(x.editable for x in pkgs)
327
- if has_editables:
328
- header.append("Editable project location")
327
+ def wheel_build_tag(dist: BaseDistribution) -> Optional[str]:
328
+ try:
329
+ wheel_file = dist.read_text("WHEEL")
330
+ except FileNotFoundError:
331
+ return None
332
+ return Parser().parsestr(wheel_file).get("Build")
333
+
334
+ build_tags = [wheel_build_tag(p) for p in pkgs]
335
+ has_build_tags = any(build_tags)
336
+ if has_build_tags:
337
+ header.append("Build")
329
338
 
330
339
  if options.verbose >= 1:
331
340
  header.append("Location")
332
341
  if options.verbose >= 1:
333
342
  header.append("Installer")
334
343
 
344
+ has_editables = any(x.editable for x in pkgs)
345
+ if has_editables:
346
+ header.append("Editable project location")
347
+
335
348
  data = []
336
- for proj in pkgs:
349
+ for i, proj in enumerate(pkgs):
337
350
  # if we're working on the 'outdated' list, separate out the
338
351
  # latest_version and type
339
352
  row = [proj.raw_name, proj.raw_version]
@@ -342,6 +355,9 @@ def format_for_columns(
342
355
  row.append(str(proj.latest_version))
343
356
  row.append(proj.latest_filetype)
344
357
 
358
+ if has_build_tags:
359
+ row.append(build_tags[i] or "")
360
+
345
361
  if has_editables:
346
362
  row.append(proj.editable_project_location or "")
347
363