pip 25.1.1__py3-none-any.whl → 25.3__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 (236) hide show
  1. pip/__init__.py +3 -3
  2. pip/_internal/__init__.py +2 -2
  3. pip/_internal/build_env.py +186 -94
  4. pip/_internal/cache.py +17 -15
  5. pip/_internal/cli/autocompletion.py +13 -4
  6. pip/_internal/cli/base_command.py +18 -7
  7. pip/_internal/cli/cmdoptions.py +57 -80
  8. pip/_internal/cli/command_context.py +4 -3
  9. pip/_internal/cli/index_command.py +11 -9
  10. pip/_internal/cli/main.py +3 -2
  11. pip/_internal/cli/main_parser.py +4 -3
  12. pip/_internal/cli/parser.py +24 -20
  13. pip/_internal/cli/progress_bars.py +19 -12
  14. pip/_internal/cli/req_command.py +57 -33
  15. pip/_internal/cli/spinners.py +81 -5
  16. pip/_internal/commands/__init__.py +5 -3
  17. pip/_internal/commands/cache.py +18 -15
  18. pip/_internal/commands/check.py +1 -2
  19. pip/_internal/commands/completion.py +1 -2
  20. pip/_internal/commands/configuration.py +26 -18
  21. pip/_internal/commands/debug.py +8 -6
  22. pip/_internal/commands/download.py +6 -10
  23. pip/_internal/commands/freeze.py +2 -3
  24. pip/_internal/commands/hash.py +1 -2
  25. pip/_internal/commands/help.py +1 -2
  26. pip/_internal/commands/index.py +15 -9
  27. pip/_internal/commands/inspect.py +4 -4
  28. pip/_internal/commands/install.py +63 -53
  29. pip/_internal/commands/list.py +35 -26
  30. pip/_internal/commands/lock.py +4 -8
  31. pip/_internal/commands/search.py +14 -12
  32. pip/_internal/commands/show.py +14 -11
  33. pip/_internal/commands/uninstall.py +1 -2
  34. pip/_internal/commands/wheel.py +7 -13
  35. pip/_internal/configuration.py +40 -27
  36. pip/_internal/distributions/base.py +6 -4
  37. pip/_internal/distributions/installed.py +8 -4
  38. pip/_internal/distributions/sdist.py +33 -27
  39. pip/_internal/distributions/wheel.py +6 -4
  40. pip/_internal/exceptions.py +78 -42
  41. pip/_internal/index/collector.py +24 -29
  42. pip/_internal/index/package_finder.py +73 -64
  43. pip/_internal/index/sources.py +17 -14
  44. pip/_internal/locations/__init__.py +18 -16
  45. pip/_internal/locations/_distutils.py +12 -11
  46. pip/_internal/locations/_sysconfig.py +5 -4
  47. pip/_internal/locations/base.py +4 -3
  48. pip/_internal/main.py +2 -2
  49. pip/_internal/metadata/__init__.py +14 -7
  50. pip/_internal/metadata/_json.py +5 -4
  51. pip/_internal/metadata/base.py +22 -27
  52. pip/_internal/metadata/importlib/_compat.py +6 -4
  53. pip/_internal/metadata/importlib/_dists.py +20 -19
  54. pip/_internal/metadata/importlib/_envs.py +9 -6
  55. pip/_internal/metadata/pkg_resources.py +11 -14
  56. pip/_internal/models/direct_url.py +24 -21
  57. pip/_internal/models/format_control.py +5 -5
  58. pip/_internal/models/installation_report.py +4 -3
  59. pip/_internal/models/link.py +39 -34
  60. pip/_internal/models/pylock.py +27 -22
  61. pip/_internal/models/search_scope.py +6 -7
  62. pip/_internal/models/selection_prefs.py +3 -3
  63. pip/_internal/models/target_python.py +10 -9
  64. pip/_internal/models/wheel.py +12 -71
  65. pip/_internal/network/auth.py +20 -22
  66. pip/_internal/network/cache.py +28 -17
  67. pip/_internal/network/download.py +169 -141
  68. pip/_internal/network/lazy_wheel.py +15 -10
  69. pip/_internal/network/session.py +32 -27
  70. pip/_internal/network/utils.py +2 -2
  71. pip/_internal/network/xmlrpc.py +2 -2
  72. pip/_internal/operations/build/build_tracker.py +10 -8
  73. pip/_internal/operations/build/wheel.py +7 -6
  74. pip/_internal/operations/build/wheel_editable.py +7 -6
  75. pip/_internal/operations/check.py +21 -26
  76. pip/_internal/operations/freeze.py +12 -9
  77. pip/_internal/operations/install/wheel.py +49 -41
  78. pip/_internal/operations/prepare.py +42 -31
  79. pip/_internal/pyproject.py +7 -69
  80. pip/_internal/req/__init__.py +12 -12
  81. pip/_internal/req/constructors.py +68 -62
  82. pip/_internal/req/req_dependency_group.py +7 -11
  83. pip/_internal/req/req_file.py +32 -36
  84. pip/_internal/req/req_install.py +64 -170
  85. pip/_internal/req/req_set.py +4 -5
  86. pip/_internal/req/req_uninstall.py +20 -17
  87. pip/_internal/resolution/base.py +3 -3
  88. pip/_internal/resolution/legacy/resolver.py +21 -20
  89. pip/_internal/resolution/resolvelib/base.py +16 -13
  90. pip/_internal/resolution/resolvelib/candidates.py +49 -37
  91. pip/_internal/resolution/resolvelib/factory.py +72 -50
  92. pip/_internal/resolution/resolvelib/found_candidates.py +11 -9
  93. pip/_internal/resolution/resolvelib/provider.py +24 -20
  94. pip/_internal/resolution/resolvelib/reporter.py +26 -11
  95. pip/_internal/resolution/resolvelib/requirements.py +8 -6
  96. pip/_internal/resolution/resolvelib/resolver.py +41 -29
  97. pip/_internal/self_outdated_check.py +19 -9
  98. pip/_internal/utils/appdirs.py +1 -2
  99. pip/_internal/utils/compat.py +7 -1
  100. pip/_internal/utils/compatibility_tags.py +17 -16
  101. pip/_internal/utils/deprecation.py +11 -9
  102. pip/_internal/utils/direct_url_helpers.py +2 -2
  103. pip/_internal/utils/egg_link.py +6 -5
  104. pip/_internal/utils/entrypoints.py +3 -2
  105. pip/_internal/utils/filesystem.py +20 -5
  106. pip/_internal/utils/filetypes.py +4 -6
  107. pip/_internal/utils/glibc.py +6 -5
  108. pip/_internal/utils/hashes.py +9 -6
  109. pip/_internal/utils/logging.py +8 -5
  110. pip/_internal/utils/misc.py +37 -45
  111. pip/_internal/utils/packaging.py +3 -2
  112. pip/_internal/utils/retry.py +7 -4
  113. pip/_internal/utils/subprocess.py +20 -17
  114. pip/_internal/utils/temp_dir.py +10 -12
  115. pip/_internal/utils/unpacking.py +31 -4
  116. pip/_internal/utils/urls.py +1 -1
  117. pip/_internal/utils/virtualenv.py +3 -2
  118. pip/_internal/utils/wheel.py +3 -4
  119. pip/_internal/vcs/bazaar.py +26 -8
  120. pip/_internal/vcs/git.py +59 -24
  121. pip/_internal/vcs/mercurial.py +34 -11
  122. pip/_internal/vcs/subversion.py +27 -16
  123. pip/_internal/vcs/versioncontrol.py +56 -51
  124. pip/_internal/wheel_builder.py +30 -101
  125. pip/_vendor/README.rst +180 -0
  126. pip/_vendor/cachecontrol/LICENSE.txt +13 -0
  127. pip/_vendor/cachecontrol/__init__.py +1 -1
  128. pip/_vendor/certifi/LICENSE +20 -0
  129. pip/_vendor/certifi/__init__.py +1 -1
  130. pip/_vendor/certifi/cacert.pem +164 -261
  131. pip/_vendor/certifi/core.py +1 -32
  132. pip/_vendor/dependency_groups/LICENSE.txt +9 -0
  133. pip/_vendor/distlib/LICENSE.txt +284 -0
  134. pip/_vendor/distlib/__init__.py +2 -2
  135. pip/_vendor/distlib/scripts.py +1 -1
  136. pip/_vendor/distro/LICENSE +202 -0
  137. pip/_vendor/idna/LICENSE.md +31 -0
  138. pip/_vendor/msgpack/COPYING +14 -0
  139. pip/_vendor/msgpack/__init__.py +2 -2
  140. pip/_vendor/packaging/LICENSE +3 -0
  141. pip/_vendor/packaging/LICENSE.APACHE +177 -0
  142. pip/_vendor/packaging/LICENSE.BSD +23 -0
  143. pip/_vendor/pkg_resources/LICENSE +17 -0
  144. pip/_vendor/pkg_resources/__init__.py +1 -1
  145. pip/_vendor/platformdirs/LICENSE +21 -0
  146. pip/_vendor/platformdirs/api.py +1 -1
  147. pip/_vendor/platformdirs/macos.py +10 -8
  148. pip/_vendor/platformdirs/version.py +16 -3
  149. pip/_vendor/pygments/LICENSE +25 -0
  150. pip/_vendor/pygments/__init__.py +1 -1
  151. pip/_vendor/pyproject_hooks/LICENSE +21 -0
  152. pip/_vendor/requests/LICENSE +175 -0
  153. pip/_vendor/requests/__version__.py +2 -2
  154. pip/_vendor/requests/adapters.py +17 -40
  155. pip/_vendor/requests/compat.py +12 -0
  156. pip/_vendor/requests/models.py +3 -1
  157. pip/_vendor/requests/sessions.py +1 -1
  158. pip/_vendor/requests/utils.py +6 -16
  159. pip/_vendor/resolvelib/LICENSE +13 -0
  160. pip/_vendor/resolvelib/__init__.py +3 -3
  161. pip/_vendor/resolvelib/reporters.py +1 -1
  162. pip/_vendor/resolvelib/resolvers/__init__.py +4 -4
  163. pip/_vendor/resolvelib/resolvers/abstract.py +3 -3
  164. pip/_vendor/resolvelib/resolvers/resolution.py +96 -10
  165. pip/_vendor/rich/LICENSE +19 -0
  166. pip/_vendor/rich/__main__.py +12 -40
  167. pip/_vendor/rich/_inspect.py +1 -1
  168. pip/_vendor/rich/_ratio.py +1 -7
  169. pip/_vendor/rich/align.py +1 -7
  170. pip/_vendor/rich/box.py +1 -7
  171. pip/_vendor/rich/console.py +25 -20
  172. pip/_vendor/rich/control.py +1 -7
  173. pip/_vendor/rich/diagnose.py +1 -0
  174. pip/_vendor/rich/emoji.py +1 -6
  175. pip/_vendor/rich/live.py +32 -7
  176. pip/_vendor/rich/live_render.py +1 -7
  177. pip/_vendor/rich/logging.py +1 -1
  178. pip/_vendor/rich/panel.py +3 -4
  179. pip/_vendor/rich/progress.py +15 -15
  180. pip/_vendor/rich/spinner.py +7 -13
  181. pip/_vendor/rich/style.py +7 -11
  182. pip/_vendor/rich/syntax.py +24 -5
  183. pip/_vendor/rich/traceback.py +32 -17
  184. pip/_vendor/tomli/LICENSE +21 -0
  185. pip/_vendor/tomli/__init__.py +1 -1
  186. pip/_vendor/tomli/_parser.py +28 -21
  187. pip/_vendor/tomli/_re.py +8 -5
  188. pip/_vendor/tomli_w/LICENSE +21 -0
  189. pip/_vendor/truststore/LICENSE +21 -0
  190. pip/_vendor/truststore/__init__.py +1 -1
  191. pip/_vendor/truststore/_api.py +15 -7
  192. pip/_vendor/truststore/_openssl.py +3 -1
  193. pip/_vendor/urllib3/LICENSE.txt +21 -0
  194. pip/_vendor/vendor.txt +11 -12
  195. {pip-25.1.1.dist-info → pip-25.3.dist-info}/METADATA +32 -11
  196. {pip-25.1.1.dist-info → pip-25.3.dist-info}/RECORD +221 -192
  197. {pip-25.1.1.dist-info → pip-25.3.dist-info}/WHEEL +1 -2
  198. pip-25.3.dist-info/entry_points.txt +4 -0
  199. {pip-25.1.1.dist-info → pip-25.3.dist-info}/licenses/AUTHORS.txt +21 -0
  200. pip-25.3.dist-info/licenses/src/pip/_vendor/cachecontrol/LICENSE.txt +13 -0
  201. pip-25.3.dist-info/licenses/src/pip/_vendor/certifi/LICENSE +20 -0
  202. pip-25.3.dist-info/licenses/src/pip/_vendor/dependency_groups/LICENSE.txt +9 -0
  203. pip-25.3.dist-info/licenses/src/pip/_vendor/distlib/LICENSE.txt +284 -0
  204. pip-25.3.dist-info/licenses/src/pip/_vendor/distro/LICENSE +202 -0
  205. pip-25.3.dist-info/licenses/src/pip/_vendor/idna/LICENSE.md +31 -0
  206. pip-25.3.dist-info/licenses/src/pip/_vendor/msgpack/COPYING +14 -0
  207. pip-25.3.dist-info/licenses/src/pip/_vendor/packaging/LICENSE +3 -0
  208. pip-25.3.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.APACHE +177 -0
  209. pip-25.3.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.BSD +23 -0
  210. pip-25.3.dist-info/licenses/src/pip/_vendor/pkg_resources/LICENSE +17 -0
  211. pip-25.3.dist-info/licenses/src/pip/_vendor/platformdirs/LICENSE +21 -0
  212. pip-25.3.dist-info/licenses/src/pip/_vendor/pygments/LICENSE +25 -0
  213. pip-25.3.dist-info/licenses/src/pip/_vendor/pyproject_hooks/LICENSE +21 -0
  214. pip-25.3.dist-info/licenses/src/pip/_vendor/requests/LICENSE +175 -0
  215. pip-25.3.dist-info/licenses/src/pip/_vendor/resolvelib/LICENSE +13 -0
  216. pip-25.3.dist-info/licenses/src/pip/_vendor/rich/LICENSE +19 -0
  217. pip-25.3.dist-info/licenses/src/pip/_vendor/tomli/LICENSE +21 -0
  218. pip-25.3.dist-info/licenses/src/pip/_vendor/tomli_w/LICENSE +21 -0
  219. pip-25.3.dist-info/licenses/src/pip/_vendor/truststore/LICENSE +21 -0
  220. pip-25.3.dist-info/licenses/src/pip/_vendor/urllib3/LICENSE.txt +21 -0
  221. pip/_internal/operations/build/metadata_legacy.py +0 -73
  222. pip/_internal/operations/build/wheel_legacy.py +0 -118
  223. pip/_internal/operations/install/editable_legacy.py +0 -46
  224. pip/_internal/utils/setuptools_build.py +0 -147
  225. pip/_vendor/distlib/database.py +0 -1329
  226. pip/_vendor/distlib/index.py +0 -508
  227. pip/_vendor/distlib/locators.py +0 -1295
  228. pip/_vendor/distlib/manifest.py +0 -384
  229. pip/_vendor/distlib/markers.py +0 -162
  230. pip/_vendor/distlib/metadata.py +0 -1031
  231. pip/_vendor/distlib/version.py +0 -750
  232. pip/_vendor/distlib/wheel.py +0 -1100
  233. pip/_vendor/typing_extensions.py +0 -4584
  234. pip-25.1.1.dist-info/entry_points.txt +0 -3
  235. pip-25.1.1.dist-info/top_level.txt +0 -1
  236. {pip-25.1.1.dist-info → pip-25.3.dist-info}/licenses/LICENSE.txt +0 -0
@@ -9,8 +9,8 @@ pass on state. To be consistent, all options will follow this design.
9
9
 
10
10
  # The following comment should be removed at some point in the future.
11
11
  # mypy: strict-optional=False
12
+ from __future__ import annotations
12
13
 
13
- import importlib.util
14
14
  import logging
15
15
  import os
16
16
  import pathlib
@@ -18,7 +18,7 @@ import textwrap
18
18
  from functools import partial
19
19
  from optparse import SUPPRESS_HELP, Option, OptionGroup, OptionParser, Values
20
20
  from textwrap import dedent
21
- from typing import Any, Callable, Dict, Optional, Tuple
21
+ from typing import Any, Callable
22
22
 
23
23
  from pip._vendor.packaging.utils import canonicalize_name
24
24
 
@@ -48,7 +48,7 @@ def raise_option_error(parser: OptionParser, option: Option, msg: str) -> None:
48
48
  parser.error(msg)
49
49
 
50
50
 
51
- def make_option_group(group: Dict[str, Any], parser: ConfigOptionParser) -> OptionGroup:
51
+ def make_option_group(group: dict[str, Any], parser: ConfigOptionParser) -> OptionGroup:
52
52
  """
53
53
  Return an OptionGroup object
54
54
  group -- assumed to be dict with 'name' and 'options' keys
@@ -100,6 +100,29 @@ def check_dist_restriction(options: Values, check_target: bool = False) -> None:
100
100
  )
101
101
 
102
102
 
103
+ def check_build_constraints(options: Values) -> None:
104
+ """Function for validating build constraints options.
105
+
106
+ :param options: The OptionParser options.
107
+ """
108
+ if hasattr(options, "build_constraints") and options.build_constraints:
109
+ if not options.build_isolation:
110
+ raise CommandError(
111
+ "--build-constraint cannot be used with --no-build-isolation."
112
+ )
113
+
114
+ # Import here to avoid circular imports
115
+ from pip._internal.network.session import PipSession
116
+ from pip._internal.req.req_file import get_file_content
117
+
118
+ # Eagerly check build constraints file contents
119
+ # is valid so that we don't fail in when trying
120
+ # to check constraints in isolated build process
121
+ with PipSession() as session:
122
+ for constraint_file in options.build_constraints:
123
+ get_file_content(constraint_file, session)
124
+
125
+
103
126
  def _path_option_check(option: Option, opt: str, value: str) -> str:
104
127
  return os.path.expanduser(value)
105
128
 
@@ -160,8 +183,7 @@ require_virtualenv: Callable[..., Option] = partial(
160
183
  action="store_true",
161
184
  default=False,
162
185
  help=(
163
- "Allow pip to only run in a virtual environment; "
164
- "exit with an error otherwise."
186
+ "Allow pip to only run in a virtual environment; exit with an error otherwise."
165
187
  ),
166
188
  )
167
189
 
@@ -227,9 +249,13 @@ progress_bar: Callable[..., Option] = partial(
227
249
  "--progress-bar",
228
250
  dest="progress_bar",
229
251
  type="choice",
230
- choices=["on", "off", "raw"],
231
- default="on",
232
- help="Specify whether the progress bar should be used [on, off, raw] (default: on)",
252
+ choices=["auto", "on", "off", "raw"],
253
+ default="auto",
254
+ help=(
255
+ "Specify whether the progress bar should be used. In 'auto'"
256
+ " mode, --quiet will suppress all progress bars."
257
+ " [auto, on, off, raw] (default: auto)"
258
+ ),
233
259
  )
234
260
 
235
261
  log: Callable[..., Option] = partial(
@@ -289,7 +315,7 @@ resume_retries: Callable[..., Option] = partial(
289
315
  "--resume-retries",
290
316
  dest="resume_retries",
291
317
  type="int",
292
- default=0,
318
+ default=5,
293
319
  help="Maximum attempts to resume or restart an incomplete download. "
294
320
  "(default: %default)",
295
321
  )
@@ -425,6 +451,21 @@ def constraints() -> Option:
425
451
  )
426
452
 
427
453
 
454
+ def build_constraints() -> Option:
455
+ return Option(
456
+ "--build-constraint",
457
+ dest="build_constraints",
458
+ action="append",
459
+ type="str",
460
+ default=[],
461
+ metavar="file",
462
+ help=(
463
+ "Constrain build dependencies using the given constraints file. "
464
+ "This option can be used multiple times."
465
+ ),
466
+ )
467
+
468
+
428
469
  def requirements() -> Option:
429
470
  return Option(
430
471
  "-r",
@@ -555,7 +596,7 @@ platforms: Callable[..., Option] = partial(
555
596
 
556
597
 
557
598
  # This was made a separate function for unit-testing purposes.
558
- def _convert_python_version(value: str) -> Tuple[Tuple[int, ...], Optional[str]]:
599
+ def _convert_python_version(value: str) -> tuple[tuple[int, ...], str | None]:
559
600
  """
560
601
  Convert a version string like "3", "37", or "3.7.3" into a tuple of ints.
561
602
 
@@ -808,62 +849,16 @@ check_build_deps: Callable[..., Option] = partial(
808
849
  dest="check_build_deps",
809
850
  action="store_true",
810
851
  default=False,
811
- help="Check the build dependencies when PEP517 is used.",
852
+ help="Check the build dependencies.",
812
853
  )
813
854
 
814
855
 
815
- def _handle_no_use_pep517(
816
- option: Option, opt: str, value: str, parser: OptionParser
817
- ) -> None:
818
- """
819
- Process a value provided for the --no-use-pep517 option.
820
-
821
- This is an optparse.Option callback for the no_use_pep517 option.
822
- """
823
- # Since --no-use-pep517 doesn't accept arguments, the value argument
824
- # will be None if --no-use-pep517 is passed via the command-line.
825
- # However, the value can be non-None if the option is triggered e.g.
826
- # by an environment variable, for example "PIP_NO_USE_PEP517=true".
827
- if value is not None:
828
- msg = """A value was passed for --no-use-pep517,
829
- probably using either the PIP_NO_USE_PEP517 environment variable
830
- or the "no-use-pep517" config file option. Use an appropriate value
831
- of the PIP_USE_PEP517 environment variable or the "use-pep517"
832
- config file option instead.
833
- """
834
- raise_option_error(parser, option=option, msg=msg)
835
-
836
- # If user doesn't wish to use pep517, we check if setuptools is installed
837
- # and raise error if it is not.
838
- packages = ("setuptools",)
839
- if not all(importlib.util.find_spec(package) for package in packages):
840
- msg = (
841
- f"It is not possible to use --no-use-pep517 "
842
- f"without {' and '.join(packages)} installed."
843
- )
844
- raise_option_error(parser, option=option, msg=msg)
845
-
846
- # Otherwise, --no-use-pep517 was passed via the command-line.
847
- parser.values.use_pep517 = False
848
-
849
-
850
856
  use_pep517: Any = partial(
851
857
  Option,
852
858
  "--use-pep517",
853
859
  dest="use_pep517",
854
860
  action="store_true",
855
- default=None,
856
- help="Use PEP 517 for building source distributions "
857
- "(use --no-use-pep517 to force legacy behaviour).",
858
- )
859
-
860
- no_use_pep517: Any = partial(
861
- Option,
862
- "--no-use-pep517",
863
- dest="use_pep517",
864
- action="callback",
865
- callback=_handle_no_use_pep517,
866
- default=None,
861
+ default=True,
867
862
  help=SUPPRESS_HELP,
868
863
  )
869
864
 
@@ -896,30 +891,11 @@ config_settings: Callable[..., Option] = partial(
896
891
  action="callback",
897
892
  callback=_handle_config_settings,
898
893
  metavar="settings",
899
- help="Configuration settings to be passed to the PEP 517 build backend. "
894
+ help="Configuration settings to be passed to the build backend. "
900
895
  "Settings take the form KEY=VALUE. Use multiple --config-settings options "
901
896
  "to pass multiple keys to the backend.",
902
897
  )
903
898
 
904
- build_options: Callable[..., Option] = partial(
905
- Option,
906
- "--build-option",
907
- dest="build_options",
908
- metavar="options",
909
- action="append",
910
- help="Extra arguments to be supplied to 'setup.py bdist_wheel'.",
911
- )
912
-
913
- global_options: Callable[..., Option] = partial(
914
- Option,
915
- "--global-option",
916
- dest="global_options",
917
- action="append",
918
- metavar="options",
919
- help="Extra global options to be supplied to the setup.py "
920
- "call before the install or bdist_wheel command.",
921
- )
922
-
923
899
  no_clean: Callable[..., Option] = partial(
924
900
  Option,
925
901
  "--no-clean",
@@ -1067,6 +1043,7 @@ use_new_feature: Callable[..., Option] = partial(
1067
1043
  default=[],
1068
1044
  choices=[
1069
1045
  "fast-deps",
1046
+ "build-constraint",
1070
1047
  ]
1071
1048
  + ALWAYS_ENABLED_FEATURES,
1072
1049
  help="Enable new functionality, that may be backward incompatible.",
@@ -1090,7 +1067,7 @@ use_deprecated_feature: Callable[..., Option] = partial(
1090
1067
  # groups #
1091
1068
  ##########
1092
1069
 
1093
- general_group: Dict[str, Any] = {
1070
+ general_group: dict[str, Any] = {
1094
1071
  "name": "General Options",
1095
1072
  "options": [
1096
1073
  help_,
@@ -1122,7 +1099,7 @@ general_group: Dict[str, Any] = {
1122
1099
  ],
1123
1100
  }
1124
1101
 
1125
- index_group: Dict[str, Any] = {
1102
+ index_group: dict[str, Any] = {
1126
1103
  "name": "Package Index Options",
1127
1104
  "options": [
1128
1105
  index_url,
@@ -1,5 +1,6 @@
1
- from contextlib import ExitStack, contextmanager
2
- from typing import ContextManager, Generator, TypeVar
1
+ from collections.abc import Generator
2
+ from contextlib import AbstractContextManager, ExitStack, contextmanager
3
+ from typing import TypeVar
3
4
 
4
5
  _T = TypeVar("_T", covariant=True)
5
6
 
@@ -21,7 +22,7 @@ class CommandContextMixIn:
21
22
  finally:
22
23
  self._in_main_context = False
23
24
 
24
- def enter_context(self, context_provider: ContextManager[_T]) -> _T:
25
+ def enter_context(self, context_provider: AbstractContextManager[_T]) -> _T:
25
26
  assert self._in_main_context
26
27
 
27
28
  return self._main_context.enter_context(context_provider)
@@ -6,12 +6,14 @@ so commands which don't always hit the network (e.g. list w/o --outdated or
6
6
  --uptodate) don't need waste time importing PipSession and friends.
7
7
  """
8
8
 
9
+ from __future__ import annotations
10
+
9
11
  import logging
10
12
  import os
11
13
  import sys
12
14
  from functools import lru_cache
13
15
  from optparse import Values
14
- from typing import TYPE_CHECKING, List, Optional
16
+ from typing import TYPE_CHECKING
15
17
 
16
18
  from pip._vendor import certifi
17
19
 
@@ -27,7 +29,7 @@ logger = logging.getLogger(__name__)
27
29
 
28
30
 
29
31
  @lru_cache
30
- def _create_truststore_ssl_context() -> Optional["SSLContext"]:
32
+ def _create_truststore_ssl_context() -> SSLContext | None:
31
33
  if sys.version_info < (3, 10):
32
34
  logger.debug("Disabling truststore because Python version isn't 3.10+")
33
35
  return None
@@ -56,10 +58,10 @@ class SessionCommandMixin(CommandContextMixIn):
56
58
 
57
59
  def __init__(self) -> None:
58
60
  super().__init__()
59
- self._session: Optional[PipSession] = None
61
+ self._session: PipSession | None = None
60
62
 
61
63
  @classmethod
62
- def _get_index_urls(cls, options: Values) -> Optional[List[str]]:
64
+ def _get_index_urls(cls, options: Values) -> list[str] | None:
63
65
  """Return a list of index urls from user-provided options."""
64
66
  index_urls = []
65
67
  if not getattr(options, "no_index", False):
@@ -72,7 +74,7 @@ class SessionCommandMixin(CommandContextMixIn):
72
74
  # Return None rather than an empty list
73
75
  return index_urls or None
74
76
 
75
- def get_default_session(self, options: Values) -> "PipSession":
77
+ def get_default_session(self, options: Values) -> PipSession:
76
78
  """Get a default-managed session."""
77
79
  if self._session is None:
78
80
  self._session = self.enter_context(self._build_session(options))
@@ -85,9 +87,9 @@ class SessionCommandMixin(CommandContextMixIn):
85
87
  def _build_session(
86
88
  self,
87
89
  options: Values,
88
- retries: Optional[int] = None,
89
- timeout: Optional[int] = None,
90
- ) -> "PipSession":
90
+ retries: int | None = None,
91
+ timeout: int | None = None,
92
+ ) -> PipSession:
91
93
  from pip._internal.network.session import PipSession
92
94
 
93
95
  cache_dir = options.cache_dir
@@ -134,7 +136,7 @@ class SessionCommandMixin(CommandContextMixIn):
134
136
  return session
135
137
 
136
138
 
137
- def _pip_self_version_check(session: "PipSession", options: Values) -> None:
139
+ def _pip_self_version_check(session: PipSession, options: Values) -> None:
138
140
  from pip._internal.self_outdated_check import pip_self_version_check as check
139
141
 
140
142
  check(session, options)
pip/_internal/cli/main.py CHANGED
@@ -1,11 +1,12 @@
1
1
  """Primary application entrypoint."""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import locale
4
6
  import logging
5
7
  import os
6
8
  import sys
7
9
  import warnings
8
- from typing import List, Optional
9
10
 
10
11
  from pip._internal.cli.autocompletion import autocomplete
11
12
  from pip._internal.cli.main_parser import parse_command
@@ -43,7 +44,7 @@ logger = logging.getLogger(__name__)
43
44
  # main, this should not be an issue in practice.
44
45
 
45
46
 
46
- def main(args: Optional[List[str]] = None) -> int:
47
+ def main(args: list[str] | None = None) -> int:
47
48
  if args is None:
48
49
  args = sys.argv[1:]
49
50
 
@@ -1,9 +1,10 @@
1
1
  """A single place for constructing and exposing the main parser"""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import os
4
6
  import subprocess
5
7
  import sys
6
- from typing import List, Optional, Tuple
7
8
 
8
9
  from pip._internal.build_env import get_runnable_pip
9
10
  from pip._internal.cli import cmdoptions
@@ -46,7 +47,7 @@ def create_main_parser() -> ConfigOptionParser:
46
47
  return parser
47
48
 
48
49
 
49
- def identify_python_interpreter(python: str) -> Optional[str]:
50
+ def identify_python_interpreter(python: str) -> str | None:
50
51
  # If the named file exists, use it.
51
52
  # If it's a directory, assume it's a virtual environment and
52
53
  # look for the environment's Python executable.
@@ -65,7 +66,7 @@ def identify_python_interpreter(python: str) -> Optional[str]:
65
66
  return None
66
67
 
67
68
 
68
- def parse_command(args: List[str]) -> Tuple[str, List[str]]:
69
+ def parse_command(args: list[str]) -> tuple[str, list[str]]:
69
70
  parser = create_main_parser()
70
71
 
71
72
  # Note: parser calls disable_interspersed_args(), so the result of this
@@ -1,12 +1,15 @@
1
1
  """Base option parser setup"""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import logging
4
6
  import optparse
5
7
  import shutil
6
8
  import sys
7
9
  import textwrap
10
+ from collections.abc import Generator
8
11
  from contextlib import suppress
9
- from typing import Any, Dict, Generator, List, NoReturn, Optional, Tuple
12
+ from typing import Any, NoReturn
10
13
 
11
14
  from pip._internal.cli.status_codes import UNKNOWN_ERROR
12
15
  from pip._internal.configuration import Configuration, ConfigurationError
@@ -67,7 +70,7 @@ class PrettyHelpFormatter(optparse.IndentedHelpFormatter):
67
70
  msg = "\nUsage: {}\n".format(self.indent_lines(textwrap.dedent(usage), " "))
68
71
  return msg
69
72
 
70
- def format_description(self, description: Optional[str]) -> str:
73
+ def format_description(self, description: str | None) -> str:
71
74
  # leave full control over description to us
72
75
  if description:
73
76
  if hasattr(self.parser, "main"):
@@ -85,7 +88,7 @@ class PrettyHelpFormatter(optparse.IndentedHelpFormatter):
85
88
  else:
86
89
  return ""
87
90
 
88
- def format_epilog(self, epilog: Optional[str]) -> str:
91
+ def format_epilog(self, epilog: str | None) -> str:
89
92
  # leave full control over epilog to us
90
93
  if epilog:
91
94
  return epilog
@@ -142,7 +145,7 @@ class CustomOptionParser(optparse.OptionParser):
142
145
  return group
143
146
 
144
147
  @property
145
- def option_list_all(self) -> List[optparse.Option]:
148
+ def option_list_all(self) -> list[optparse.Option]:
146
149
  """Get a list of all options, including those in option groups."""
147
150
  res = self.option_list[:]
148
151
  for i in self.option_groups:
@@ -177,33 +180,34 @@ class ConfigOptionParser(CustomOptionParser):
177
180
 
178
181
  def _get_ordered_configuration_items(
179
182
  self,
180
- ) -> Generator[Tuple[str, Any], None, None]:
183
+ ) -> Generator[tuple[str, Any], None, None]:
181
184
  # Configuration gives keys in an unordered manner. Order them.
182
185
  override_order = ["global", self.name, ":env:"]
183
186
 
184
187
  # Pool the options into different groups
185
- section_items: Dict[str, List[Tuple[str, Any]]] = {
188
+ section_items: dict[str, list[tuple[str, Any]]] = {
186
189
  name: [] for name in override_order
187
190
  }
188
- for section_key, val in self.config.items():
189
- # ignore empty values
190
- if not val:
191
- logger.debug(
192
- "Ignoring configuration key '%s' as it's value is empty.",
193
- section_key,
194
- )
195
- continue
196
191
 
197
- section, key = section_key.split(".", 1)
198
- if section in override_order:
199
- section_items[section].append((key, val))
192
+ for _, value in self.config.items(): # noqa: PERF102
193
+ for section_key, val in value.items():
194
+ # ignore empty values
195
+ if not val:
196
+ logger.debug(
197
+ "Ignoring configuration key '%s' as its value is empty.",
198
+ section_key,
199
+ )
200
+ continue
201
+
202
+ section, key = section_key.split(".", 1)
203
+ if section in override_order:
204
+ section_items[section].append((key, val))
200
205
 
201
206
  # Yield each group in their override order
202
207
  for section in override_order:
203
- for key, val in section_items[section]:
204
- yield key, val
208
+ yield from section_items[section]
205
209
 
206
- def _update_defaults(self, defaults: Dict[str, Any]) -> Dict[str, Any]:
210
+ def _update_defaults(self, defaults: dict[str, Any]) -> dict[str, Any]:
207
211
  """Updates the given defaults with values from the config files and
208
212
  the environ. Does a little special handling for certain types of
209
213
  options (lists)."""
@@ -1,6 +1,9 @@
1
+ from __future__ import annotations
2
+
1
3
  import functools
2
4
  import sys
3
- from typing import Callable, Generator, Iterable, Iterator, Optional, Tuple, TypeVar
5
+ from collections.abc import Generator, Iterable, Iterator
6
+ from typing import Callable, Literal, TypeVar
4
7
 
5
8
  from pip._vendor.rich.progress import (
6
9
  BarColumn,
@@ -22,20 +25,21 @@ from pip._internal.utils.logging import get_console, get_indentation
22
25
 
23
26
  T = TypeVar("T")
24
27
  ProgressRenderer = Callable[[Iterable[T]], Iterator[T]]
28
+ BarType = Literal["on", "off", "raw"]
25
29
 
26
30
 
27
31
  def _rich_download_progress_bar(
28
32
  iterable: Iterable[bytes],
29
33
  *,
30
- bar_type: str,
31
- size: Optional[int],
32
- initial_progress: Optional[int] = None,
34
+ bar_type: BarType,
35
+ size: int | None,
36
+ initial_progress: int | None = None,
33
37
  ) -> Generator[bytes, None, None]:
34
38
  assert bar_type == "on", "This should only be used in the default mode."
35
39
 
36
40
  if not size:
37
41
  total = float("inf")
38
- columns: Tuple[ProgressColumn, ...] = (
42
+ columns: tuple[ProgressColumn, ...] = (
39
43
  TextColumn("[progress.description]{task.description}"),
40
44
  SpinnerColumn("line", speed=1.5),
41
45
  FileSizeColumn(),
@@ -49,18 +53,21 @@ def _rich_download_progress_bar(
49
53
  BarColumn(),
50
54
  DownloadColumn(),
51
55
  TransferSpeedColumn(),
52
- TextColumn("eta"),
53
- TimeRemainingColumn(),
56
+ TextColumn("{task.fields[time_description]}"),
57
+ TimeRemainingColumn(elapsed_when_finished=True),
54
58
  )
55
59
 
56
60
  progress = Progress(*columns, refresh_per_second=5)
57
- task_id = progress.add_task(" " * (get_indentation() + 2), total=total)
61
+ task_id = progress.add_task(
62
+ " " * (get_indentation() + 2), total=total, time_description="eta"
63
+ )
58
64
  if initial_progress is not None:
59
65
  progress.update(task_id, advance=initial_progress)
60
66
  with progress:
61
67
  for chunk in iterable:
62
68
  yield chunk
63
69
  progress.update(task_id, advance=len(chunk))
70
+ progress.update(task_id, time_description="")
64
71
 
65
72
 
66
73
  def _rich_install_progress_bar(
@@ -88,8 +95,8 @@ def _rich_install_progress_bar(
88
95
  def _raw_progress_bar(
89
96
  iterable: Iterable[bytes],
90
97
  *,
91
- size: Optional[int],
92
- initial_progress: Optional[int] = None,
98
+ size: int | None,
99
+ initial_progress: int | None = None,
93
100
  ) -> Generator[bytes, None, None]:
94
101
  def write_progress(current: int, total: int) -> None:
95
102
  sys.stdout.write(f"Progress {current} of {total}\n")
@@ -109,7 +116,7 @@ def _raw_progress_bar(
109
116
 
110
117
 
111
118
  def get_download_progress_renderer(
112
- *, bar_type: str, size: Optional[int] = None, initial_progress: Optional[int] = None
119
+ *, bar_type: BarType, size: int | None = None, initial_progress: int | None = None
113
120
  ) -> ProgressRenderer[bytes]:
114
121
  """Get an object that can be used to render the download progress.
115
122
 
@@ -133,7 +140,7 @@ def get_download_progress_renderer(
133
140
 
134
141
 
135
142
  def get_install_progress_renderer(
136
- *, bar_type: str, total: int
143
+ *, bar_type: BarType, total: int
137
144
  ) -> ProgressRenderer[InstallRequirement]:
138
145
  """Get an object that can be used to render the install progress.
139
146
  Returns a callable, that takes an iterable to "wrap".