|
1 |
| -"""Contains the Command base classes that depend on PipSession. |
| 1 | +"""Contains the RequirementCommand base class. |
2 | 2 |
|
3 |
| -The classes in this module are in a separate module so the commands not |
4 |
| -needing download / PackageFinder capability don't unnecessarily import the |
| 3 | +This class is in a separate module so the commands that do not always |
| 4 | +need PackageFinder capability don't unnecessarily import the |
5 | 5 | PackageFinder machinery and all its vendored dependencies, etc.
|
6 | 6 | """
|
7 | 7 |
|
8 | 8 | import logging
|
9 |
| -import os |
10 |
| -import sys |
11 | 9 | from functools import partial
|
12 | 10 | from optparse import Values
|
13 |
| -from typing import TYPE_CHECKING, Any, List, Optional, Tuple |
| 11 | +from typing import Any, List, Optional, Tuple |
14 | 12 |
|
15 | 13 | from pip._internal.cache import WheelCache
|
16 | 14 | from pip._internal.cli import cmdoptions
|
17 |
| -from pip._internal.cli.base_command import Command |
18 |
| -from pip._internal.cli.command_context import CommandContextMixIn |
| 15 | +from pip._internal.cli.index_command import IndexGroupCommand |
| 16 | +from pip._internal.cli.index_command import SessionCommandMixin as SessionCommandMixin |
19 | 17 | from pip._internal.exceptions import CommandError, PreviousBuildDirError
|
20 | 18 | from pip._internal.index.collector import LinkCollector
|
21 | 19 | from pip._internal.index.package_finder import PackageFinder
|
|
33 | 31 | from pip._internal.req.req_file import parse_requirements
|
34 | 32 | from pip._internal.req.req_install import InstallRequirement
|
35 | 33 | from pip._internal.resolution.base import BaseResolver
|
36 |
| -from pip._internal.self_outdated_check import pip_self_version_check |
37 | 34 | from pip._internal.utils.temp_dir import (
|
38 | 35 | TempDirectory,
|
39 | 36 | TempDirectoryTypeRegistry,
|
40 | 37 | tempdir_kinds,
|
41 | 38 | )
|
42 | 39 |
|
43 |
| -if TYPE_CHECKING: |
44 |
| - from ssl import SSLContext |
45 |
| - |
46 | 40 | logger = logging.getLogger(__name__)
|
47 | 41 |
|
48 | 42 |
|
49 |
| -def _create_truststore_ssl_context() -> Optional["SSLContext"]: |
50 |
| - if sys.version_info < (3, 10): |
51 |
| - raise CommandError("The truststore feature is only available for Python 3.10+") |
52 |
| - |
53 |
| - try: |
54 |
| - import ssl |
55 |
| - except ImportError: |
56 |
| - logger.warning("Disabling truststore since ssl support is missing") |
57 |
| - return None |
58 |
| - |
59 |
| - try: |
60 |
| - from pip._vendor import truststore |
61 |
| - except ImportError as e: |
62 |
| - raise CommandError(f"The truststore feature is unavailable: {e}") |
63 |
| - |
64 |
| - return truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT) |
65 |
| - |
66 |
| - |
67 |
| -class SessionCommandMixin(CommandContextMixIn): |
68 |
| - """ |
69 |
| - A class mixin for command classes needing _build_session(). |
70 |
| - """ |
71 |
| - |
72 |
| - def __init__(self) -> None: |
73 |
| - super().__init__() |
74 |
| - self._session: Optional[PipSession] = None |
75 |
| - |
76 |
| - @classmethod |
77 |
| - def _get_index_urls(cls, options: Values) -> Optional[List[str]]: |
78 |
| - """Return a list of index urls from user-provided options.""" |
79 |
| - index_urls = [] |
80 |
| - if not getattr(options, "no_index", False): |
81 |
| - url = getattr(options, "index_url", None) |
82 |
| - if url: |
83 |
| - index_urls.append(url) |
84 |
| - urls = getattr(options, "extra_index_urls", None) |
85 |
| - if urls: |
86 |
| - index_urls.extend(urls) |
87 |
| - # Return None rather than an empty list |
88 |
| - return index_urls or None |
89 |
| - |
90 |
| - def get_default_session(self, options: Values) -> PipSession: |
91 |
| - """Get a default-managed session.""" |
92 |
| - if self._session is None: |
93 |
| - self._session = self.enter_context(self._build_session(options)) |
94 |
| - # there's no type annotation on requests.Session, so it's |
95 |
| - # automatically ContextManager[Any] and self._session becomes Any, |
96 |
| - # then https://github.com/python/mypy/issues/7696 kicks in |
97 |
| - assert self._session is not None |
98 |
| - return self._session |
99 |
| - |
100 |
| - def _build_session( |
101 |
| - self, |
102 |
| - options: Values, |
103 |
| - retries: Optional[int] = None, |
104 |
| - timeout: Optional[int] = None, |
105 |
| - fallback_to_certifi: bool = False, |
106 |
| - ) -> PipSession: |
107 |
| - cache_dir = options.cache_dir |
108 |
| - assert not cache_dir or os.path.isabs(cache_dir) |
109 |
| - |
110 |
| - if "truststore" in options.features_enabled: |
111 |
| - try: |
112 |
| - ssl_context = _create_truststore_ssl_context() |
113 |
| - except Exception: |
114 |
| - if not fallback_to_certifi: |
115 |
| - raise |
116 |
| - ssl_context = None |
117 |
| - else: |
118 |
| - ssl_context = None |
119 |
| - |
120 |
| - session = PipSession( |
121 |
| - cache=os.path.join(cache_dir, "http-v2") if cache_dir else None, |
122 |
| - retries=retries if retries is not None else options.retries, |
123 |
| - trusted_hosts=options.trusted_hosts, |
124 |
| - index_urls=self._get_index_urls(options), |
125 |
| - ssl_context=ssl_context, |
126 |
| - ) |
127 |
| - |
128 |
| - # Handle custom ca-bundles from the user |
129 |
| - if options.cert: |
130 |
| - session.verify = options.cert |
131 |
| - |
132 |
| - # Handle SSL client certificate |
133 |
| - if options.client_cert: |
134 |
| - session.cert = options.client_cert |
135 |
| - |
136 |
| - # Handle timeouts |
137 |
| - if options.timeout or timeout: |
138 |
| - session.timeout = timeout if timeout is not None else options.timeout |
139 |
| - |
140 |
| - # Handle configured proxies |
141 |
| - if options.proxy: |
142 |
| - session.proxies = { |
143 |
| - "http": options.proxy, |
144 |
| - "https": options.proxy, |
145 |
| - } |
146 |
| - session.trust_env = False |
147 |
| - |
148 |
| - # Determine if we can prompt the user for authentication or not |
149 |
| - session.auth.prompting = not options.no_input |
150 |
| - session.auth.keyring_provider = options.keyring_provider |
151 |
| - |
152 |
| - return session |
153 |
| - |
154 |
| - |
155 |
| -class IndexGroupCommand(Command, SessionCommandMixin): |
156 |
| - """ |
157 |
| - Abstract base class for commands with the index_group options. |
158 |
| -
|
159 |
| - This also corresponds to the commands that permit the pip version check. |
160 |
| - """ |
161 |
| - |
162 |
| - def handle_pip_version_check(self, options: Values) -> None: |
163 |
| - """ |
164 |
| - Do the pip version check if not disabled. |
165 |
| -
|
166 |
| - This overrides the default behavior of not doing the check. |
167 |
| - """ |
168 |
| - # Make sure the index_group options are present. |
169 |
| - assert hasattr(options, "no_index") |
170 |
| - |
171 |
| - if options.disable_pip_version_check or options.no_index: |
172 |
| - return |
173 |
| - |
174 |
| - # Otherwise, check if we're using the latest version of pip available. |
175 |
| - session = self._build_session( |
176 |
| - options, |
177 |
| - retries=0, |
178 |
| - timeout=min(5, options.timeout), |
179 |
| - # This is set to ensure the function does not fail when truststore is |
180 |
| - # specified in use-feature but cannot be loaded. This usually raises a |
181 |
| - # CommandError and shows a nice user-facing error, but this function is not |
182 |
| - # called in that try-except block. |
183 |
| - fallback_to_certifi=True, |
184 |
| - ) |
185 |
| - with session: |
186 |
| - pip_self_version_check(session, options) |
187 |
| - |
188 |
| - |
189 | 43 | KEEPABLE_TEMPDIR_TYPES = [
|
190 | 44 | tempdir_kinds.BUILD_ENV,
|
191 | 45 | tempdir_kinds.EPHEM_WHEEL_CACHE,
|
|
0 commit comments