mirror of
https://github.com/pre-commit/pre-commit-hooks.git
synced 2026-04-13 22:24:45 +00:00
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
This commit is contained in:
parent
72ad6dc953
commit
f4cd1ba0d6
813 changed files with 66015 additions and 58839 deletions
|
|
@ -1,2 +1,3 @@
|
|||
"""Contains purely network-related utilities.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
|
|
|||
|
|
@ -3,23 +3,27 @@
|
|||
Contains interface (MultiDomainBasicAuth) and associated glue code for
|
||||
providing credentials in the context of network requests.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import urllib.parse
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from pip._vendor.requests.auth import AuthBase, HTTPBasicAuth
|
||||
from pip._vendor.requests.models import Request, Response
|
||||
from pip._vendor.requests.utils import get_netrc_auth
|
||||
from typing import Any
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Tuple
|
||||
|
||||
from pip._internal.utils.logging import getLogger
|
||||
from pip._internal.utils.misc import (
|
||||
ask,
|
||||
ask_input,
|
||||
ask_password,
|
||||
remove_auth_from_url,
|
||||
split_auth_netloc_from_url,
|
||||
)
|
||||
from pip._internal.utils.misc import ask
|
||||
from pip._internal.utils.misc import ask_input
|
||||
from pip._internal.utils.misc import ask_password
|
||||
from pip._internal.utils.misc import remove_auth_from_url
|
||||
from pip._internal.utils.misc import split_auth_netloc_from_url
|
||||
from pip._internal.vcs.versioncontrol import AuthInfo
|
||||
from pip._vendor.requests.auth import AuthBase
|
||||
from pip._vendor.requests.auth import HTTPBasicAuth
|
||||
from pip._vendor.requests.models import Request
|
||||
from pip._vendor.requests.models import Response
|
||||
from pip._vendor.requests.utils import get_netrc_auth
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
|
@ -31,13 +35,13 @@ except ImportError:
|
|||
keyring = None # type: ignore[assignment]
|
||||
except Exception as exc:
|
||||
logger.warning(
|
||||
"Keyring is skipped due to an exception: %s",
|
||||
'Keyring is skipped due to an exception: %s',
|
||||
str(exc),
|
||||
)
|
||||
keyring = None # type: ignore[assignment]
|
||||
|
||||
|
||||
def get_keyring_auth(url: Optional[str], username: Optional[str]) -> Optional[AuthInfo]:
|
||||
def get_keyring_auth(url: str | None, username: str | None) -> AuthInfo | None:
|
||||
"""Return the tuple auth for a given url from keyring."""
|
||||
global keyring
|
||||
if not url or not keyring:
|
||||
|
|
@ -49,21 +53,21 @@ def get_keyring_auth(url: Optional[str], username: Optional[str]) -> Optional[Au
|
|||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
logger.debug("Getting credentials from keyring for %s", url)
|
||||
logger.debug('Getting credentials from keyring for %s', url)
|
||||
cred = get_credential(url, username)
|
||||
if cred is not None:
|
||||
return cred.username, cred.password
|
||||
return None
|
||||
|
||||
if username:
|
||||
logger.debug("Getting password from keyring for %s", url)
|
||||
logger.debug('Getting password from keyring for %s', url)
|
||||
password = keyring.get_password(url, username)
|
||||
if password:
|
||||
return username, password
|
||||
|
||||
except Exception as exc:
|
||||
logger.warning(
|
||||
"Keyring is skipped due to an exception: %s",
|
||||
'Keyring is skipped due to an exception: %s',
|
||||
str(exc),
|
||||
)
|
||||
keyring = None # type: ignore[assignment]
|
||||
|
|
@ -72,19 +76,19 @@ def get_keyring_auth(url: Optional[str], username: Optional[str]) -> Optional[Au
|
|||
|
||||
class MultiDomainBasicAuth(AuthBase):
|
||||
def __init__(
|
||||
self, prompting: bool = True, index_urls: Optional[List[str]] = None
|
||||
self, prompting: bool = True, index_urls: list[str] | None = None,
|
||||
) -> None:
|
||||
self.prompting = prompting
|
||||
self.index_urls = index_urls
|
||||
self.passwords: Dict[str, AuthInfo] = {}
|
||||
self.passwords: dict[str, AuthInfo] = {}
|
||||
# When the user is prompted to enter credentials and keyring is
|
||||
# available, we will offer to save them. If the user accepts,
|
||||
# this value is set to the credentials they entered. After the
|
||||
# request authenticates, the caller should call
|
||||
# ``save_credentials`` to save these.
|
||||
self._credentials_to_save: Optional[Credentials] = None
|
||||
self._credentials_to_save: Credentials | None = None
|
||||
|
||||
def _get_index_url(self, url: str) -> Optional[str]:
|
||||
def _get_index_url(self, url: str) -> str | None:
|
||||
"""Return the original index URL matching the requested URL.
|
||||
|
||||
Cached or dynamically generated credentials may work against
|
||||
|
|
@ -101,7 +105,7 @@ class MultiDomainBasicAuth(AuthBase):
|
|||
return None
|
||||
|
||||
for u in self.index_urls:
|
||||
prefix = remove_auth_from_url(u).rstrip("/") + "/"
|
||||
prefix = remove_auth_from_url(u).rstrip('/') + '/'
|
||||
if url.startswith(prefix):
|
||||
return u
|
||||
return None
|
||||
|
|
@ -121,7 +125,7 @@ class MultiDomainBasicAuth(AuthBase):
|
|||
# Start with the credentials embedded in the url
|
||||
username, password = url_user_password
|
||||
if username is not None and password is not None:
|
||||
logger.debug("Found credentials in url for %s", netloc)
|
||||
logger.debug('Found credentials in url for %s', netloc)
|
||||
return url_user_password
|
||||
|
||||
# Find a matching index url for this request
|
||||
|
|
@ -131,20 +135,20 @@ class MultiDomainBasicAuth(AuthBase):
|
|||
index_info = split_auth_netloc_from_url(index_url)
|
||||
if index_info:
|
||||
index_url, _, index_url_user_password = index_info
|
||||
logger.debug("Found index url %s", index_url)
|
||||
logger.debug('Found index url %s', index_url)
|
||||
|
||||
# If an index URL was found, try its embedded credentials
|
||||
if index_url and index_url_user_password[0] is not None:
|
||||
username, password = index_url_user_password
|
||||
if username is not None and password is not None:
|
||||
logger.debug("Found credentials in index url for %s", netloc)
|
||||
logger.debug('Found credentials in index url for %s', netloc)
|
||||
return index_url_user_password
|
||||
|
||||
# Get creds from netrc if we still don't have them
|
||||
if allow_netrc:
|
||||
netrc_auth = get_netrc_auth(original_url)
|
||||
if netrc_auth:
|
||||
logger.debug("Found credentials in netrc for %s", netloc)
|
||||
logger.debug('Found credentials in netrc for %s', netloc)
|
||||
return netrc_auth
|
||||
|
||||
# If we don't have a password and keyring is available, use it.
|
||||
|
|
@ -157,14 +161,14 @@ class MultiDomainBasicAuth(AuthBase):
|
|||
)
|
||||
# fmt: on
|
||||
if kr_auth:
|
||||
logger.debug("Found credentials in keyring for %s", netloc)
|
||||
logger.debug('Found credentials in keyring for %s', netloc)
|
||||
return kr_auth
|
||||
|
||||
return username, password
|
||||
|
||||
def _get_url_and_credentials(
|
||||
self, original_url: str
|
||||
) -> Tuple[str, Optional[str], Optional[str]]:
|
||||
self, original_url: str,
|
||||
) -> tuple[str, str | None, str | None]:
|
||||
"""Return the credentials to use for the provided URL.
|
||||
|
||||
If allowed, netrc and keyring may be used to obtain the
|
||||
|
|
@ -195,18 +199,18 @@ class MultiDomainBasicAuth(AuthBase):
|
|||
# this netloc will show up as "cached" in the conditional above.
|
||||
# Further, HTTPBasicAuth doesn't accept None, so it makes sense to
|
||||
# cache the value that is going to be used.
|
||||
username = username or ""
|
||||
password = password or ""
|
||||
username = username or ''
|
||||
password = password or ''
|
||||
|
||||
# Store any acquired credentials.
|
||||
self.passwords[netloc] = (username, password)
|
||||
|
||||
assert (
|
||||
# Credentials were found
|
||||
(username is not None and password is not None)
|
||||
(username is not None and password is not None) or
|
||||
# Credentials were not found
|
||||
or (username is None and password is None)
|
||||
), f"Could not load credentials from url: {original_url}"
|
||||
(username is None and password is None)
|
||||
), f'Could not load credentials from url: {original_url}'
|
||||
|
||||
return url, username, password
|
||||
|
||||
|
|
@ -222,28 +226,28 @@ class MultiDomainBasicAuth(AuthBase):
|
|||
req = HTTPBasicAuth(username, password)(req)
|
||||
|
||||
# Attach a hook to handle 401 responses
|
||||
req.register_hook("response", self.handle_401)
|
||||
req.register_hook('response', self.handle_401)
|
||||
|
||||
return req
|
||||
|
||||
# Factored out to allow for easy patching in tests
|
||||
def _prompt_for_password(
|
||||
self, netloc: str
|
||||
) -> Tuple[Optional[str], Optional[str], bool]:
|
||||
username = ask_input(f"User for {netloc}: ")
|
||||
self, netloc: str,
|
||||
) -> tuple[str | None, str | None, bool]:
|
||||
username = ask_input(f'User for {netloc}: ')
|
||||
if not username:
|
||||
return None, None, False
|
||||
auth = get_keyring_auth(netloc, username)
|
||||
if auth and auth[0] is not None and auth[1] is not None:
|
||||
return auth[0], auth[1], False
|
||||
password = ask_password("Password: ")
|
||||
password = ask_password('Password: ')
|
||||
return username, password, True
|
||||
|
||||
# Factored out to allow for easy patching in tests
|
||||
def _should_save_password_to_keyring(self) -> bool:
|
||||
if not keyring:
|
||||
return False
|
||||
return ask("Save credentials to keyring [y/N]: ", ["y", "n"]) == "y"
|
||||
return ask('Save credentials to keyring [y/N]: ', ['y', 'n']) == 'y'
|
||||
|
||||
def handle_401(self, resp: Response, **kwargs: Any) -> Response:
|
||||
# We only care about 401 responses, anything else we want to just
|
||||
|
|
@ -284,14 +288,14 @@ class MultiDomainBasicAuth(AuthBase):
|
|||
resp.raw.release_conn()
|
||||
|
||||
# Add our new username and password to the request
|
||||
req = HTTPBasicAuth(username or "", password or "")(resp.request)
|
||||
req.register_hook("response", self.warn_on_401)
|
||||
req = HTTPBasicAuth(username or '', password or '')(resp.request)
|
||||
req.register_hook('response', self.warn_on_401)
|
||||
|
||||
# On successful request, save the credentials that were used to
|
||||
# keyring. (Note that if the user responded "no" above, this member
|
||||
# is not set and nothing will be saved.)
|
||||
if self._credentials_to_save:
|
||||
req.register_hook("response", self.save_credentials)
|
||||
req.register_hook('response', self.save_credentials)
|
||||
|
||||
# Send our new request
|
||||
new_resp = resp.connection.send(req, **kwargs)
|
||||
|
|
@ -303,13 +307,13 @@ class MultiDomainBasicAuth(AuthBase):
|
|||
"""Response callback to warn about incorrect credentials."""
|
||||
if resp.status_code == 401:
|
||||
logger.warning(
|
||||
"401 Error, Credentials not correct for %s",
|
||||
'401 Error, Credentials not correct for %s',
|
||||
resp.request.url,
|
||||
)
|
||||
|
||||
def save_credentials(self, resp: Response, **kwargs: Any) -> None:
|
||||
"""Response callback to save credentials on success."""
|
||||
assert keyring is not None, "should never reach here without keyring"
|
||||
assert keyring is not None, 'should never reach here without keyring'
|
||||
if not keyring:
|
||||
return
|
||||
|
||||
|
|
@ -317,7 +321,7 @@ class MultiDomainBasicAuth(AuthBase):
|
|||
self._credentials_to_save = None
|
||||
if creds and resp.status_code < 400:
|
||||
try:
|
||||
logger.info("Saving credentials to keyring")
|
||||
logger.info('Saving credentials to keyring')
|
||||
keyring.set_password(*creds)
|
||||
except Exception:
|
||||
logger.exception("Failed to save credentials")
|
||||
logger.exception('Failed to save credentials')
|
||||
|
|
|
|||
|
|
@ -1,20 +1,22 @@
|
|||
"""HTTP cache implementation.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from contextlib import contextmanager
|
||||
from typing import Iterator, Optional
|
||||
from typing import Iterator
|
||||
from typing import Optional
|
||||
|
||||
from pip._internal.utils.filesystem import adjacent_tmp_file
|
||||
from pip._internal.utils.filesystem import replace
|
||||
from pip._internal.utils.misc import ensure_dir
|
||||
from pip._vendor.cachecontrol.cache import BaseCache
|
||||
from pip._vendor.cachecontrol.caches import FileCache
|
||||
from pip._vendor.requests.models import Response
|
||||
|
||||
from pip._internal.utils.filesystem import adjacent_tmp_file, replace
|
||||
from pip._internal.utils.misc import ensure_dir
|
||||
|
||||
|
||||
def is_from_cache(response: Response) -> bool:
|
||||
return getattr(response, "from_cache", False)
|
||||
return getattr(response, 'from_cache', False)
|
||||
|
||||
|
||||
@contextmanager
|
||||
|
|
@ -35,7 +37,7 @@ class SafeFileCache(BaseCache):
|
|||
"""
|
||||
|
||||
def __init__(self, directory: str) -> None:
|
||||
assert directory is not None, "Cache directory must not be None."
|
||||
assert directory is not None, 'Cache directory must not be None.'
|
||||
super().__init__()
|
||||
self.directory = directory
|
||||
|
||||
|
|
@ -47,13 +49,13 @@ class SafeFileCache(BaseCache):
|
|||
parts = list(hashed[:5]) + [hashed]
|
||||
return os.path.join(self.directory, *parts)
|
||||
|
||||
def get(self, key: str) -> Optional[bytes]:
|
||||
def get(self, key: str) -> bytes | None:
|
||||
path = self._get_cache_path(key)
|
||||
with suppressed_cache_errors():
|
||||
with open(path, "rb") as f:
|
||||
with open(path, 'rb') as f:
|
||||
return f.read()
|
||||
|
||||
def set(self, key: str, value: bytes, expires: Optional[int] = None) -> None:
|
||||
def set(self, key: str, value: bytes, expires: int | None = None) -> None:
|
||||
path = self._get_cache_path(key)
|
||||
with suppressed_cache_errors():
|
||||
ensure_dir(os.path.dirname(path))
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
"""Download files with progress indicators.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import cgi
|
||||
import logging
|
||||
import mimetypes
|
||||
import os
|
||||
from typing import Iterable, Optional, Tuple
|
||||
|
||||
from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response
|
||||
from typing import Iterable
|
||||
from typing import Optional
|
||||
from typing import Tuple
|
||||
|
||||
from pip._internal.cli.progress_bars import get_download_progress_renderer
|
||||
from pip._internal.exceptions import NetworkConnectionError
|
||||
|
|
@ -14,15 +16,21 @@ from pip._internal.models.index import PyPI
|
|||
from pip._internal.models.link import Link
|
||||
from pip._internal.network.cache import is_from_cache
|
||||
from pip._internal.network.session import PipSession
|
||||
from pip._internal.network.utils import HEADERS, raise_for_status, response_chunks
|
||||
from pip._internal.utils.misc import format_size, redact_auth_from_url, splitext
|
||||
from pip._internal.network.utils import HEADERS
|
||||
from pip._internal.network.utils import raise_for_status
|
||||
from pip._internal.network.utils import response_chunks
|
||||
from pip._internal.utils.misc import format_size
|
||||
from pip._internal.utils.misc import redact_auth_from_url
|
||||
from pip._internal.utils.misc import splitext
|
||||
from pip._vendor.requests.models import CONTENT_CHUNK_SIZE
|
||||
from pip._vendor.requests.models import Response
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_http_response_size(resp: Response) -> Optional[int]:
|
||||
def _get_http_response_size(resp: Response) -> int | None:
|
||||
try:
|
||||
return int(resp.headers["content-length"])
|
||||
return int(resp.headers['content-length'])
|
||||
except (ValueError, KeyError, TypeError):
|
||||
return None
|
||||
|
||||
|
|
@ -42,12 +50,12 @@ def _prepare_download(
|
|||
logged_url = redact_auth_from_url(url)
|
||||
|
||||
if total_length:
|
||||
logged_url = "{} ({})".format(logged_url, format_size(total_length))
|
||||
logged_url = f'{logged_url} ({format_size(total_length)})'
|
||||
|
||||
if is_from_cache(resp):
|
||||
logger.info("Using cached %s", logged_url)
|
||||
logger.info('Using cached %s', logged_url)
|
||||
else:
|
||||
logger.info("Downloading %s", logged_url)
|
||||
logger.info('Downloading %s', logged_url)
|
||||
|
||||
if logger.getEffectiveLevel() > logging.INFO:
|
||||
show_progress = False
|
||||
|
|
@ -82,7 +90,7 @@ def parse_content_disposition(content_disposition: str, default_filename: str) -
|
|||
return the default filename if the result is empty.
|
||||
"""
|
||||
_type, params = cgi.parse_header(content_disposition)
|
||||
filename = params.get("filename")
|
||||
filename = params.get('filename')
|
||||
if filename:
|
||||
# We need to sanitize the filename to prevent directory traversal
|
||||
# in case the filename contains ".." path parts.
|
||||
|
|
@ -96,12 +104,12 @@ def _get_http_response_filename(resp: Response, link: Link) -> str:
|
|||
"""
|
||||
filename = link.filename # fallback
|
||||
# Have a look at the Content-Disposition header for a better guess
|
||||
content_disposition = resp.headers.get("content-disposition")
|
||||
content_disposition = resp.headers.get('content-disposition')
|
||||
if content_disposition:
|
||||
filename = parse_content_disposition(content_disposition, filename)
|
||||
ext: Optional[str] = splitext(filename)[1]
|
||||
ext: str | None = splitext(filename)[1]
|
||||
if not ext:
|
||||
ext = mimetypes.guess_extension(resp.headers.get("content-type", ""))
|
||||
ext = mimetypes.guess_extension(resp.headers.get('content-type', ''))
|
||||
if ext:
|
||||
filename += ext
|
||||
if not ext and link.url != resp.url:
|
||||
|
|
@ -112,7 +120,7 @@ def _get_http_response_filename(resp: Response, link: Link) -> str:
|
|||
|
||||
|
||||
def _http_get_download(session: PipSession, link: Link) -> Response:
|
||||
target_url = link.url.split("#", 1)[0]
|
||||
target_url = link.url.split('#', 1)[0]
|
||||
resp = session.get(target_url, headers=HEADERS, stream=True)
|
||||
raise_for_status(resp)
|
||||
return resp
|
||||
|
|
@ -127,14 +135,14 @@ class Downloader:
|
|||
self._session = session
|
||||
self._progress_bar = progress_bar
|
||||
|
||||
def __call__(self, link: Link, location: str) -> Tuple[str, str]:
|
||||
def __call__(self, link: Link, location: str) -> tuple[str, str]:
|
||||
"""Download the file given by link into location."""
|
||||
try:
|
||||
resp = _http_get_download(self._session, link)
|
||||
except NetworkConnectionError as e:
|
||||
assert e.response is not None
|
||||
logger.critical(
|
||||
"HTTP error %s while getting %s", e.response.status_code, link
|
||||
'HTTP error %s while getting %s', e.response.status_code, link,
|
||||
)
|
||||
raise
|
||||
|
||||
|
|
@ -142,10 +150,10 @@ class Downloader:
|
|||
filepath = os.path.join(location, filename)
|
||||
|
||||
chunks = _prepare_download(resp, link, self._progress_bar)
|
||||
with open(filepath, "wb") as content_file:
|
||||
with open(filepath, 'wb') as content_file:
|
||||
for chunk in chunks:
|
||||
content_file.write(chunk)
|
||||
content_type = resp.headers.get("Content-Type", "")
|
||||
content_type = resp.headers.get('Content-Type', '')
|
||||
return filepath, content_type
|
||||
|
||||
|
||||
|
|
@ -159,8 +167,8 @@ class BatchDownloader:
|
|||
self._progress_bar = progress_bar
|
||||
|
||||
def __call__(
|
||||
self, links: Iterable[Link], location: str
|
||||
) -> Iterable[Tuple[Link, Tuple[str, str]]]:
|
||||
self, links: Iterable[Link], location: str,
|
||||
) -> Iterable[tuple[Link, tuple[str, str]]]:
|
||||
"""Download the files given by links into location."""
|
||||
for link in links:
|
||||
try:
|
||||
|
|
@ -168,7 +176,7 @@ class BatchDownloader:
|
|||
except NetworkConnectionError as e:
|
||||
assert e.response is not None
|
||||
logger.critical(
|
||||
"HTTP error %s while getting %s",
|
||||
'HTTP error %s while getting %s',
|
||||
e.response.status_code,
|
||||
link,
|
||||
)
|
||||
|
|
@ -178,8 +186,8 @@ class BatchDownloader:
|
|||
filepath = os.path.join(location, filename)
|
||||
|
||||
chunks = _prepare_download(resp, link, self._progress_bar)
|
||||
with open(filepath, "wb") as content_file:
|
||||
with open(filepath, 'wb') as content_file:
|
||||
for chunk in chunks:
|
||||
content_file.write(chunk)
|
||||
content_type = resp.headers.get("Content-Type", "")
|
||||
content_type = resp.headers.get('Content-Type', '')
|
||||
yield link, (filepath, content_type)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"""Lazy ZIP over HTTP"""
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ["HTTPRangeRequestUnsupported", "dist_from_wheel_url"]
|
||||
__all__ = ['HTTPRangeRequestUnsupported', 'dist_from_wheel_url']
|
||||
|
||||
from bisect import bisect_left, bisect_right
|
||||
from contextlib import contextmanager
|
||||
|
|
@ -47,25 +48,25 @@ class LazyZipOverHTTP:
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self, url: str, session: PipSession, chunk_size: int = CONTENT_CHUNK_SIZE
|
||||
self, url: str, session: PipSession, chunk_size: int = CONTENT_CHUNK_SIZE,
|
||||
) -> None:
|
||||
head = session.head(url, headers=HEADERS)
|
||||
raise_for_status(head)
|
||||
assert head.status_code == 200
|
||||
self._session, self._url, self._chunk_size = session, url, chunk_size
|
||||
self._length = int(head.headers["Content-Length"])
|
||||
self._length = int(head.headers['Content-Length'])
|
||||
self._file = NamedTemporaryFile()
|
||||
self.truncate(self._length)
|
||||
self._left: List[int] = []
|
||||
self._right: List[int] = []
|
||||
if "bytes" not in head.headers.get("Accept-Ranges", "none"):
|
||||
raise HTTPRangeRequestUnsupported("range request is not supported")
|
||||
self._left: list[int] = []
|
||||
self._right: list[int] = []
|
||||
if 'bytes' not in head.headers.get('Accept-Ranges', 'none'):
|
||||
raise HTTPRangeRequestUnsupported('range request is not supported')
|
||||
self._check_zip()
|
||||
|
||||
@property
|
||||
def mode(self) -> str:
|
||||
"""Opening mode, which is always rb."""
|
||||
return "rb"
|
||||
return 'rb'
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
|
|
@ -117,7 +118,7 @@ class LazyZipOverHTTP:
|
|||
"""Return the current position."""
|
||||
return self._file.tell()
|
||||
|
||||
def truncate(self, size: Optional[int] = None) -> int:
|
||||
def truncate(self, size: int | None = None) -> int:
|
||||
"""Resize the stream to the given size in bytes.
|
||||
|
||||
If size is unspecified resize to the current position.
|
||||
|
|
@ -131,11 +132,11 @@ class LazyZipOverHTTP:
|
|||
"""Return False."""
|
||||
return False
|
||||
|
||||
def __enter__(self) -> "LazyZipOverHTTP":
|
||||
def __enter__(self) -> LazyZipOverHTTP:
|
||||
self._file.__enter__()
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc: Any) -> Optional[bool]:
|
||||
def __exit__(self, *exc: Any) -> bool | None:
|
||||
return self._file.__exit__(*exc)
|
||||
|
||||
@contextmanager
|
||||
|
|
@ -166,18 +167,18 @@ class LazyZipOverHTTP:
|
|||
break
|
||||
|
||||
def _stream_response(
|
||||
self, start: int, end: int, base_headers: Dict[str, str] = HEADERS
|
||||
self, start: int, end: int, base_headers: dict[str, str] = HEADERS,
|
||||
) -> Response:
|
||||
"""Return HTTP response to a range request from start to end."""
|
||||
headers = base_headers.copy()
|
||||
headers["Range"] = f"bytes={start}-{end}"
|
||||
headers['Range'] = f'bytes={start}-{end}'
|
||||
# TODO: Get range requests to be correctly cached
|
||||
headers["Cache-Control"] = "no-cache"
|
||||
headers['Cache-Control'] = 'no-cache'
|
||||
return self._session.get(self._url, headers=headers, stream=True)
|
||||
|
||||
def _merge(
|
||||
self, start: int, end: int, left: int, right: int
|
||||
) -> Iterator[Tuple[int, int]]:
|
||||
self, start: int, end: int, left: int, right: int,
|
||||
) -> Iterator[tuple[int, int]]:
|
||||
"""Return an iterator of intervals to be fetched.
|
||||
|
||||
Args:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"""PipSession and supporting code, containing all pip-specific
|
||||
network request configuration and behavior.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import email.utils
|
||||
import io
|
||||
|
|
@ -15,27 +16,37 @@ import subprocess
|
|||
import sys
|
||||
import urllib.parse
|
||||
import warnings
|
||||
from typing import Any, Dict, Iterator, List, Mapping, Optional, Sequence, Tuple, Union
|
||||
|
||||
from pip._vendor import requests, urllib3
|
||||
from pip._vendor.cachecontrol import CacheControlAdapter
|
||||
from pip._vendor.requests.adapters import BaseAdapter, HTTPAdapter
|
||||
from pip._vendor.requests.models import PreparedRequest, Response
|
||||
from pip._vendor.requests.structures import CaseInsensitiveDict
|
||||
from pip._vendor.urllib3.connectionpool import ConnectionPool
|
||||
from pip._vendor.urllib3.exceptions import InsecureRequestWarning
|
||||
from typing import Any
|
||||
from typing import Dict
|
||||
from typing import Iterator
|
||||
from typing import List
|
||||
from typing import Mapping
|
||||
from typing import Optional
|
||||
from typing import Sequence
|
||||
from typing import Tuple
|
||||
from typing import Union
|
||||
|
||||
from pip import __version__
|
||||
from pip._internal.metadata import get_default_environment
|
||||
from pip._internal.models.link import Link
|
||||
from pip._internal.network.auth import MultiDomainBasicAuth
|
||||
from pip._internal.network.cache import SafeFileCache
|
||||
|
||||
# Import ssl from compat so the initial import occurs in only one place.
|
||||
from pip._internal.utils.compat import has_tls
|
||||
from pip._internal.utils.glibc import libc_ver
|
||||
from pip._internal.utils.misc import build_url_from_netloc, parse_netloc
|
||||
from pip._internal.utils.misc import build_url_from_netloc
|
||||
from pip._internal.utils.misc import parse_netloc
|
||||
from pip._internal.utils.urls import url_to_path
|
||||
from pip._vendor import requests
|
||||
from pip._vendor import urllib3
|
||||
from pip._vendor.cachecontrol import CacheControlAdapter
|
||||
from pip._vendor.requests.adapters import BaseAdapter
|
||||
from pip._vendor.requests.adapters import HTTPAdapter
|
||||
from pip._vendor.requests.models import PreparedRequest
|
||||
from pip._vendor.requests.models import Response
|
||||
from pip._vendor.requests.structures import CaseInsensitiveDict
|
||||
from pip._vendor.urllib3.connectionpool import ConnectionPool
|
||||
from pip._vendor.urllib3.exceptions import InsecureRequestWarning
|
||||
# Import ssl from compat so the initial import occurs in only one place.
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -43,19 +54,19 @@ SecureOrigin = Tuple[str, str, Optional[Union[int, str]]]
|
|||
|
||||
|
||||
# Ignore warning raised when using --trusted-host.
|
||||
warnings.filterwarnings("ignore", category=InsecureRequestWarning)
|
||||
warnings.filterwarnings('ignore', category=InsecureRequestWarning)
|
||||
|
||||
|
||||
SECURE_ORIGINS: List[SecureOrigin] = [
|
||||
SECURE_ORIGINS: list[SecureOrigin] = [
|
||||
# protocol, hostname, port
|
||||
# Taken from Chrome's list of secure origins (See: http://bit.ly/1qrySKC)
|
||||
("https", "*", "*"),
|
||||
("*", "localhost", "*"),
|
||||
("*", "127.0.0.0/8", "*"),
|
||||
("*", "::1/128", "*"),
|
||||
("file", "*", None),
|
||||
('https', '*', '*'),
|
||||
('*', 'localhost', '*'),
|
||||
('*', '127.0.0.0/8', '*'),
|
||||
('*', '::1/128', '*'),
|
||||
('file', '*', None),
|
||||
# ssh is always secure.
|
||||
("ssh", "*", "*"),
|
||||
('ssh', '*', '*'),
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -68,13 +79,13 @@ SECURE_ORIGINS: List[SecureOrigin] = [
|
|||
# For more background, see: https://github.com/pypa/pip/issues/5499
|
||||
CI_ENVIRONMENT_VARIABLES = (
|
||||
# Azure Pipelines
|
||||
"BUILD_BUILDID",
|
||||
'BUILD_BUILDID',
|
||||
# Jenkins
|
||||
"BUILD_ID",
|
||||
'BUILD_ID',
|
||||
# AppVeyor, CircleCI, Codeship, Gitlab CI, Shippable, Travis CI
|
||||
"CI",
|
||||
'CI',
|
||||
# Explicit environment variable.
|
||||
"PIP_IS_CI",
|
||||
'PIP_IS_CI',
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -92,100 +103,100 @@ def user_agent() -> str:
|
|||
"""
|
||||
Return a string representing the user agent.
|
||||
"""
|
||||
data: Dict[str, Any] = {
|
||||
"installer": {"name": "pip", "version": __version__},
|
||||
"python": platform.python_version(),
|
||||
"implementation": {
|
||||
"name": platform.python_implementation(),
|
||||
data: dict[str, Any] = {
|
||||
'installer': {'name': 'pip', 'version': __version__},
|
||||
'python': platform.python_version(),
|
||||
'implementation': {
|
||||
'name': platform.python_implementation(),
|
||||
},
|
||||
}
|
||||
|
||||
if data["implementation"]["name"] == "CPython":
|
||||
data["implementation"]["version"] = platform.python_version()
|
||||
elif data["implementation"]["name"] == "PyPy":
|
||||
if data['implementation']['name'] == 'CPython':
|
||||
data['implementation']['version'] = platform.python_version()
|
||||
elif data['implementation']['name'] == 'PyPy':
|
||||
pypy_version_info = sys.pypy_version_info # type: ignore
|
||||
if pypy_version_info.releaselevel == "final":
|
||||
if pypy_version_info.releaselevel == 'final':
|
||||
pypy_version_info = pypy_version_info[:3]
|
||||
data["implementation"]["version"] = ".".join(
|
||||
[str(x) for x in pypy_version_info]
|
||||
data['implementation']['version'] = '.'.join(
|
||||
[str(x) for x in pypy_version_info],
|
||||
)
|
||||
elif data["implementation"]["name"] == "Jython":
|
||||
elif data['implementation']['name'] == 'Jython':
|
||||
# Complete Guess
|
||||
data["implementation"]["version"] = platform.python_version()
|
||||
elif data["implementation"]["name"] == "IronPython":
|
||||
data['implementation']['version'] = platform.python_version()
|
||||
elif data['implementation']['name'] == 'IronPython':
|
||||
# Complete Guess
|
||||
data["implementation"]["version"] = platform.python_version()
|
||||
data['implementation']['version'] = platform.python_version()
|
||||
|
||||
if sys.platform.startswith("linux"):
|
||||
if sys.platform.startswith('linux'):
|
||||
from pip._vendor import distro
|
||||
|
||||
linux_distribution = distro.name(), distro.version(), distro.codename()
|
||||
distro_infos: Dict[str, Any] = dict(
|
||||
distro_infos: dict[str, Any] = dict(
|
||||
filter(
|
||||
lambda x: x[1],
|
||||
zip(["name", "version", "id"], linux_distribution),
|
||||
)
|
||||
zip(['name', 'version', 'id'], linux_distribution),
|
||||
),
|
||||
)
|
||||
libc = dict(
|
||||
filter(
|
||||
lambda x: x[1],
|
||||
zip(["lib", "version"], libc_ver()),
|
||||
)
|
||||
zip(['lib', 'version'], libc_ver()),
|
||||
),
|
||||
)
|
||||
if libc:
|
||||
distro_infos["libc"] = libc
|
||||
distro_infos['libc'] = libc
|
||||
if distro_infos:
|
||||
data["distro"] = distro_infos
|
||||
data['distro'] = distro_infos
|
||||
|
||||
if sys.platform.startswith("darwin") and platform.mac_ver()[0]:
|
||||
data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]}
|
||||
if sys.platform.startswith('darwin') and platform.mac_ver()[0]:
|
||||
data['distro'] = {'name': 'macOS', 'version': platform.mac_ver()[0]}
|
||||
|
||||
if platform.system():
|
||||
data.setdefault("system", {})["name"] = platform.system()
|
||||
data.setdefault('system', {})['name'] = platform.system()
|
||||
|
||||
if platform.release():
|
||||
data.setdefault("system", {})["release"] = platform.release()
|
||||
data.setdefault('system', {})['release'] = platform.release()
|
||||
|
||||
if platform.machine():
|
||||
data["cpu"] = platform.machine()
|
||||
data['cpu'] = platform.machine()
|
||||
|
||||
if has_tls():
|
||||
import _ssl as ssl
|
||||
|
||||
data["openssl_version"] = ssl.OPENSSL_VERSION
|
||||
data['openssl_version'] = ssl.OPENSSL_VERSION
|
||||
|
||||
setuptools_dist = get_default_environment().get_distribution("setuptools")
|
||||
setuptools_dist = get_default_environment().get_distribution('setuptools')
|
||||
if setuptools_dist is not None:
|
||||
data["setuptools_version"] = str(setuptools_dist.version)
|
||||
data['setuptools_version'] = str(setuptools_dist.version)
|
||||
|
||||
if shutil.which("rustc") is not None:
|
||||
if shutil.which('rustc') is not None:
|
||||
# If for any reason `rustc --version` fails, silently ignore it
|
||||
try:
|
||||
rustc_output = subprocess.check_output(
|
||||
["rustc", "--version"], stderr=subprocess.STDOUT, timeout=0.5
|
||||
['rustc', '--version'], stderr=subprocess.STDOUT, timeout=0.5,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
if rustc_output.startswith(b"rustc "):
|
||||
if rustc_output.startswith(b'rustc '):
|
||||
# The format of `rustc --version` is:
|
||||
# `b'rustc 1.52.1 (9bc8c42bb 2021-05-09)\n'`
|
||||
# We extract just the middle (1.52.1) part
|
||||
data["rustc_version"] = rustc_output.split(b" ")[1].decode()
|
||||
data['rustc_version'] = rustc_output.split(b' ')[1].decode()
|
||||
|
||||
# Use None rather than False so as not to give the impression that
|
||||
# pip knows it is not being run under CI. Rather, it is a null or
|
||||
# inconclusive result. Also, we include some value rather than no
|
||||
# value to make it easier to know that the check has been run.
|
||||
data["ci"] = True if looks_like_ci() else None
|
||||
data['ci'] = True if looks_like_ci() else None
|
||||
|
||||
user_data = os.environ.get("PIP_USER_AGENT_USER_DATA")
|
||||
user_data = os.environ.get('PIP_USER_AGENT_USER_DATA')
|
||||
if user_data is not None:
|
||||
data["user_data"] = user_data
|
||||
data['user_data'] = user_data
|
||||
|
||||
return "{data[installer][name]}/{data[installer][version]} {json}".format(
|
||||
return '{data[installer][name]}/{data[installer][version]} {json}'.format(
|
||||
data=data,
|
||||
json=json.dumps(data, separators=(",", ":"), sort_keys=True),
|
||||
json=json.dumps(data, separators=(',', ':'), sort_keys=True),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -194,10 +205,10 @@ class LocalFSAdapter(BaseAdapter):
|
|||
self,
|
||||
request: PreparedRequest,
|
||||
stream: bool = False,
|
||||
timeout: Optional[Union[float, Tuple[float, float]]] = None,
|
||||
verify: Union[bool, str] = True,
|
||||
cert: Optional[Union[str, Tuple[str, str]]] = None,
|
||||
proxies: Optional[Mapping[str, str]] = None,
|
||||
timeout: float | tuple[float, float] | None = None,
|
||||
verify: bool | str = True,
|
||||
cert: str | tuple[str, str] | None = None,
|
||||
proxies: Mapping[str, str] | None = None,
|
||||
) -> Response:
|
||||
pathname = url_to_path(request.url)
|
||||
|
||||
|
|
@ -212,19 +223,19 @@ class LocalFSAdapter(BaseAdapter):
|
|||
# to return a better error message:
|
||||
resp.status_code = 404
|
||||
resp.reason = type(exc).__name__
|
||||
resp.raw = io.BytesIO(f"{resp.reason}: {exc}".encode("utf8"))
|
||||
resp.raw = io.BytesIO(f'{resp.reason}: {exc}'.encode())
|
||||
else:
|
||||
modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
|
||||
content_type = mimetypes.guess_type(pathname)[0] or "text/plain"
|
||||
content_type = mimetypes.guess_type(pathname)[0] or 'text/plain'
|
||||
resp.headers = CaseInsensitiveDict(
|
||||
{
|
||||
"Content-Type": content_type,
|
||||
"Content-Length": stats.st_size,
|
||||
"Last-Modified": modified,
|
||||
}
|
||||
'Content-Type': content_type,
|
||||
'Content-Length': stats.st_size,
|
||||
'Last-Modified': modified,
|
||||
},
|
||||
)
|
||||
|
||||
resp.raw = open(pathname, "rb")
|
||||
resp.raw = open(pathname, 'rb')
|
||||
resp.close = resp.raw.close
|
||||
|
||||
return resp
|
||||
|
|
@ -238,8 +249,8 @@ class InsecureHTTPAdapter(HTTPAdapter):
|
|||
self,
|
||||
conn: ConnectionPool,
|
||||
url: str,
|
||||
verify: Union[bool, str],
|
||||
cert: Optional[Union[str, Tuple[str, str]]],
|
||||
verify: bool | str,
|
||||
cert: str | tuple[str, str] | None,
|
||||
) -> None:
|
||||
super().cert_verify(conn=conn, url=url, verify=False, cert=cert)
|
||||
|
||||
|
|
@ -249,23 +260,23 @@ class InsecureCacheControlAdapter(CacheControlAdapter):
|
|||
self,
|
||||
conn: ConnectionPool,
|
||||
url: str,
|
||||
verify: Union[bool, str],
|
||||
cert: Optional[Union[str, Tuple[str, str]]],
|
||||
verify: bool | str,
|
||||
cert: str | tuple[str, str] | None,
|
||||
) -> None:
|
||||
super().cert_verify(conn=conn, url=url, verify=False, cert=cert)
|
||||
|
||||
|
||||
class PipSession(requests.Session):
|
||||
|
||||
timeout: Optional[int] = None
|
||||
timeout: int | None = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*args: Any,
|
||||
retries: int = 0,
|
||||
cache: Optional[str] = None,
|
||||
cache: str | None = None,
|
||||
trusted_hosts: Sequence[str] = (),
|
||||
index_urls: Optional[List[str]] = None,
|
||||
index_urls: list[str] | None = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""
|
||||
|
|
@ -276,10 +287,10 @@ class PipSession(requests.Session):
|
|||
|
||||
# Namespace the attribute with "pip_" just in case to prevent
|
||||
# possible conflicts with the base class.
|
||||
self.pip_trusted_origins: List[Tuple[str, Optional[int]]] = []
|
||||
self.pip_trusted_origins: list[tuple[str, int | None]] = []
|
||||
|
||||
# Attach our User Agent to the request
|
||||
self.headers["User-Agent"] = user_agent()
|
||||
self.headers['User-Agent'] = user_agent()
|
||||
|
||||
# Attach our Authentication handler to the session
|
||||
self.auth = MultiDomainBasicAuth(index_urls=index_urls)
|
||||
|
|
@ -327,16 +338,16 @@ class PipSession(requests.Session):
|
|||
secure_adapter = HTTPAdapter(max_retries=retries)
|
||||
self._trusted_host_adapter = insecure_adapter
|
||||
|
||||
self.mount("https://", secure_adapter)
|
||||
self.mount("http://", insecure_adapter)
|
||||
self.mount('https://', secure_adapter)
|
||||
self.mount('http://', insecure_adapter)
|
||||
|
||||
# Enable file:// urls
|
||||
self.mount("file://", LocalFSAdapter())
|
||||
self.mount('file://', LocalFSAdapter())
|
||||
|
||||
for host in trusted_hosts:
|
||||
self.add_trusted_host(host, suppress_logging=True)
|
||||
|
||||
def update_index_urls(self, new_index_urls: List[str]) -> None:
|
||||
def update_index_urls(self, new_index_urls: list[str]) -> None:
|
||||
"""
|
||||
:param new_index_urls: New index urls to update the authentication
|
||||
handler with.
|
||||
|
|
@ -344,7 +355,7 @@ class PipSession(requests.Session):
|
|||
self.auth.index_urls = new_index_urls
|
||||
|
||||
def add_trusted_host(
|
||||
self, host: str, source: Optional[str] = None, suppress_logging: bool = False
|
||||
self, host: str, source: str | None = None, suppress_logging: bool = False,
|
||||
) -> None:
|
||||
"""
|
||||
:param host: It is okay to provide a host that has previously been
|
||||
|
|
@ -353,9 +364,9 @@ class PipSession(requests.Session):
|
|||
string came from.
|
||||
"""
|
||||
if not suppress_logging:
|
||||
msg = f"adding trusted host: {host!r}"
|
||||
msg = f'adding trusted host: {host!r}'
|
||||
if source is not None:
|
||||
msg += f" (from {source})"
|
||||
msg += f' (from {source})'
|
||||
logger.info(msg)
|
||||
|
||||
host_port = parse_netloc(host)
|
||||
|
|
@ -363,21 +374,21 @@ class PipSession(requests.Session):
|
|||
self.pip_trusted_origins.append(host_port)
|
||||
|
||||
self.mount(
|
||||
build_url_from_netloc(host, scheme="http") + "/", self._trusted_host_adapter
|
||||
build_url_from_netloc(host, scheme='http') + '/', self._trusted_host_adapter,
|
||||
)
|
||||
self.mount(build_url_from_netloc(host) + "/", self._trusted_host_adapter)
|
||||
self.mount(build_url_from_netloc(host) + '/', self._trusted_host_adapter)
|
||||
if not host_port[1]:
|
||||
self.mount(
|
||||
build_url_from_netloc(host, scheme="http") + ":",
|
||||
build_url_from_netloc(host, scheme='http') + ':',
|
||||
self._trusted_host_adapter,
|
||||
)
|
||||
# Mount wildcard ports for the same host.
|
||||
self.mount(build_url_from_netloc(host) + ":", self._trusted_host_adapter)
|
||||
self.mount(build_url_from_netloc(host) + ':', self._trusted_host_adapter)
|
||||
|
||||
def iter_secure_origins(self) -> Iterator[SecureOrigin]:
|
||||
yield from SECURE_ORIGINS
|
||||
for host, port in self.pip_trusted_origins:
|
||||
yield ("*", host, "*" if port is None else port)
|
||||
yield ('*', host, '*' if port is None else port)
|
||||
|
||||
def is_secure_origin(self, location: Link) -> bool:
|
||||
# Determine if this url used a secure transport mechanism
|
||||
|
|
@ -392,14 +403,14 @@ class PipSession(requests.Session):
|
|||
# Don't count the repository type as part of the protocol: in
|
||||
# cases such as "git+ssh", only use "ssh". (I.e., Only verify against
|
||||
# the last scheme.)
|
||||
origin_protocol = origin_protocol.rsplit("+", 1)[-1]
|
||||
origin_protocol = origin_protocol.rsplit('+', 1)[-1]
|
||||
|
||||
# Determine if our origin is a secure origin by looking through our
|
||||
# hardcoded list of secure origins, as well as any additional ones
|
||||
# configured on this PackageFinder instance.
|
||||
for secure_origin in self.iter_secure_origins():
|
||||
secure_protocol, secure_host, secure_port = secure_origin
|
||||
if origin_protocol != secure_protocol and secure_protocol != "*":
|
||||
if origin_protocol != secure_protocol and secure_protocol != '*':
|
||||
continue
|
||||
|
||||
try:
|
||||
|
|
@ -409,9 +420,9 @@ class PipSession(requests.Session):
|
|||
# We don't have both a valid address or a valid network, so
|
||||
# we'll check this origin against hostnames.
|
||||
if (
|
||||
origin_host
|
||||
and origin_host.lower() != secure_host.lower()
|
||||
and secure_host != "*"
|
||||
origin_host and
|
||||
origin_host.lower() != secure_host.lower() and
|
||||
secure_host != '*'
|
||||
):
|
||||
continue
|
||||
else:
|
||||
|
|
@ -422,9 +433,9 @@ class PipSession(requests.Session):
|
|||
|
||||
# Check to see if the port matches.
|
||||
if (
|
||||
origin_port != secure_port
|
||||
and secure_port != "*"
|
||||
and secure_port is not None
|
||||
origin_port != secure_port and
|
||||
secure_port != '*' and
|
||||
secure_port is not None
|
||||
):
|
||||
continue
|
||||
|
||||
|
|
@ -436,9 +447,9 @@ class PipSession(requests.Session):
|
|||
# will not accept it as a valid location to search. We will however
|
||||
# log a warning that we are ignoring it.
|
||||
logger.warning(
|
||||
"The repository located at %s is not a trusted or secure host and "
|
||||
"is being ignored. If this repository is available via HTTPS we "
|
||||
"recommend you use HTTPS instead, otherwise you may silence "
|
||||
'The repository located at %s is not a trusted or secure host and '
|
||||
'is being ignored. If this repository is available via HTTPS we '
|
||||
'recommend you use HTTPS instead, otherwise you may silence '
|
||||
"this warning and allow it anyway with '--trusted-host %s'.",
|
||||
origin_host,
|
||||
origin_host,
|
||||
|
|
@ -448,7 +459,7 @@ class PipSession(requests.Session):
|
|||
|
||||
def request(self, method: str, url: str, *args: Any, **kwargs: Any) -> Response:
|
||||
# Allow setting a default timeout on a session
|
||||
kwargs.setdefault("timeout", self.timeout)
|
||||
kwargs.setdefault('timeout', self.timeout)
|
||||
|
||||
# Dispatch the actual request
|
||||
return super().request(method, url, *args, **kwargs)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
from typing import Dict, Iterator
|
||||
from __future__ import annotations
|
||||
|
||||
from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response
|
||||
from typing import Dict
|
||||
from typing import Iterator
|
||||
|
||||
from pip._internal.exceptions import NetworkConnectionError
|
||||
from pip._vendor.requests.models import CONTENT_CHUNK_SIZE
|
||||
from pip._vendor.requests.models import Response
|
||||
|
||||
# The following comments and HTTP headers were originally added by
|
||||
# Donald Stufft in git commit 22c562429a61bb77172039e480873fb239dd8c03.
|
||||
|
|
@ -23,31 +26,31 @@ from pip._internal.exceptions import NetworkConnectionError
|
|||
# you're not asking for a compressed file and will then decompress it
|
||||
# before sending because if that's the case I don't think it'll ever be
|
||||
# possible to make this work.
|
||||
HEADERS: Dict[str, str] = {"Accept-Encoding": "identity"}
|
||||
HEADERS: dict[str, str] = {'Accept-Encoding': 'identity'}
|
||||
|
||||
|
||||
def raise_for_status(resp: Response) -> None:
|
||||
http_error_msg = ""
|
||||
http_error_msg = ''
|
||||
if isinstance(resp.reason, bytes):
|
||||
# We attempt to decode utf-8 first because some servers
|
||||
# choose to localize their reason strings. If the string
|
||||
# isn't utf-8, we fall back to iso-8859-1 for all other
|
||||
# encodings.
|
||||
try:
|
||||
reason = resp.reason.decode("utf-8")
|
||||
reason = resp.reason.decode('utf-8')
|
||||
except UnicodeDecodeError:
|
||||
reason = resp.reason.decode("iso-8859-1")
|
||||
reason = resp.reason.decode('iso-8859-1')
|
||||
else:
|
||||
reason = resp.reason
|
||||
|
||||
if 400 <= resp.status_code < 500:
|
||||
http_error_msg = (
|
||||
f"{resp.status_code} Client Error: {reason} for url: {resp.url}"
|
||||
f'{resp.status_code} Client Error: {reason} for url: {resp.url}'
|
||||
)
|
||||
|
||||
elif 500 <= resp.status_code < 600:
|
||||
http_error_msg = (
|
||||
f"{resp.status_code} Server Error: {reason} for url: {resp.url}"
|
||||
f'{resp.status_code} Server Error: {reason} for url: {resp.url}'
|
||||
)
|
||||
|
||||
if http_error_msg:
|
||||
|
|
@ -55,7 +58,7 @@ def raise_for_status(resp: Response) -> None:
|
|||
|
||||
|
||||
def response_chunks(
|
||||
response: Response, chunk_size: int = CONTENT_CHUNK_SIZE
|
||||
response: Response, chunk_size: int = CONTENT_CHUNK_SIZE,
|
||||
) -> Iterator[bytes]:
|
||||
"""Given a requests Response, provide the data chunks."""
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
"""xmlrpclib.Transport implementation
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import urllib.parse
|
||||
import xmlrpc.client
|
||||
from typing import TYPE_CHECKING, Tuple
|
||||
from typing import Tuple
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from pip._internal.exceptions import NetworkConnectionError
|
||||
from pip._internal.network.session import PipSession
|
||||
|
|
@ -22,7 +24,7 @@ class PipXmlrpcTransport(xmlrpc.client.Transport):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self, index_url: str, session: PipSession, use_datetime: bool = False
|
||||
self, index_url: str, session: PipSession, use_datetime: bool = False,
|
||||
) -> None:
|
||||
super().__init__(use_datetime)
|
||||
index_parts = urllib.parse.urlparse(index_url)
|
||||
|
|
@ -31,16 +33,16 @@ class PipXmlrpcTransport(xmlrpc.client.Transport):
|
|||
|
||||
def request(
|
||||
self,
|
||||
host: "_HostType",
|
||||
host: _HostType,
|
||||
handler: str,
|
||||
request_body: bytes,
|
||||
verbose: bool = False,
|
||||
) -> Tuple["_Marshallable", ...]:
|
||||
) -> tuple[_Marshallable, ...]:
|
||||
assert isinstance(host, str)
|
||||
parts = (self._scheme, host, handler, None, None, None)
|
||||
url = urllib.parse.urlunparse(parts)
|
||||
try:
|
||||
headers = {"Content-Type": "text/xml"}
|
||||
headers = {'Content-Type': 'text/xml'}
|
||||
response = self._session.post(
|
||||
url,
|
||||
data=request_body,
|
||||
|
|
@ -53,7 +55,7 @@ class PipXmlrpcTransport(xmlrpc.client.Transport):
|
|||
except NetworkConnectionError as exc:
|
||||
assert exc.response
|
||||
logger.critical(
|
||||
"HTTP error %s while getting %s",
|
||||
'HTTP error %s while getting %s',
|
||||
exc.response.status_code,
|
||||
url,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue