aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2024-11-11 07:44:29 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2024-11-11 08:02:45 +0300
commit957f86df328db96cde860a1f5c8ba564358688a3 (patch)
treee8d2c0179ee1a743eed3236a4c50771934f1da75 /contrib/python
parent0c30aa1174f1b6b193bac7b5c67f32d039e872e5 (diff)
downloadydb-957f86df328db96cde860a1f5c8ba564358688a3.tar.gz
Intermediate changes
commit_hash:a48f9d9abf0ac0bec1edeb52eb1d3fea3fe7d758
Diffstat (limited to 'contrib/python')
-rw-r--r--contrib/python/pip/.dist-info/METADATA3
-rw-r--r--contrib/python/pip/AUTHORS.txt3
-rw-r--r--contrib/python/pip/patches/01-arcadia.patch13
-rw-r--r--contrib/python/pip/pip/__init__.py2
-rw-r--r--contrib/python/pip/pip/_internal/build_env.py4
-rw-r--r--contrib/python/pip/pip/_internal/cli/index_command.py2
-rw-r--r--contrib/python/pip/pip/_internal/cli/parser.py4
-rw-r--r--contrib/python/pip/pip/_internal/cli/progress_bars.py2
-rw-r--r--contrib/python/pip/pip/_internal/commands/list.py2
-rw-r--r--contrib/python/pip/pip/_internal/commands/search.py2
-rw-r--r--contrib/python/pip/pip/_internal/exceptions.py34
-rw-r--r--contrib/python/pip/pip/_internal/index/sources.py5
-rw-r--r--contrib/python/pip/pip/_internal/locations/_distutils.py6
-rw-r--r--contrib/python/pip/pip/_internal/metadata/importlib/_envs.py2
-rw-r--r--contrib/python/pip/pip/_internal/models/wheel.py31
-rw-r--r--contrib/python/pip/pip/_internal/network/lazy_wheel.py2
-rw-r--r--contrib/python/pip/pip/_internal/req/constructors.py2
-rw-r--r--contrib/python/pip/pip/_internal/req/req_file.py37
-rw-r--r--contrib/python/pip/pip/_internal/resolution/resolvelib/candidates.py9
-rw-r--r--contrib/python/pip/pip/_internal/resolution/resolvelib/factory.py16
-rw-r--r--contrib/python/pip/pip/_internal/utils/compatibility_tags.py27
-rw-r--r--contrib/python/pip/pip/_internal/utils/misc.py9
-rw-r--r--contrib/python/pip/pip/_vendor/certifi/__init__.py2
-rw-r--r--contrib/python/pip/pip/_vendor/certifi/cacert.pem131
-rw-r--r--contrib/python/pip/pip/_vendor/distlib/__init__.py2
-rw-r--r--contrib/python/pip/pip/_vendor/distlib/compat.py3
-rw-r--r--contrib/python/pip/pip/_vendor/distlib/database.py90
-rw-r--r--contrib/python/pip/pip/_vendor/distlib/locators.py122
-rw-r--r--contrib/python/pip/pip/_vendor/distlib/markers.py19
-rw-r--r--contrib/python/pip/pip/_vendor/distlib/metadata.py181
-rw-r--r--contrib/python/pip/pip/_vendor/distlib/scripts.py88
-rw-r--r--contrib/python/pip/pip/_vendor/distlib/util.py123
-rw-r--r--contrib/python/pip/pip/_vendor/distlib/version.py3
-rw-r--r--contrib/python/pip/pip/_vendor/distlib/wheel.py129
-rw-r--r--contrib/python/pip/pip/_vendor/packaging/tags.py69
-rw-r--r--contrib/python/pip/pip/_vendor/truststore/__init__.py25
-rw-r--r--contrib/python/pip/pip/_vendor/truststore/_api.py3
-rw-r--r--contrib/python/pip/pip/_vendor/truststore/_macos.py200
-rw-r--r--contrib/python/pip/pip/_vendor/truststore/_windows.py7
-rw-r--r--contrib/python/pip/pip/_vendor/urllib3/_version.py2
-rw-r--r--contrib/python/pip/pip/_vendor/urllib3/connection.py4
-rw-r--r--contrib/python/pip/pip/_vendor/urllib3/connectionpool.py7
-rw-r--r--contrib/python/pip/pip/_vendor/urllib3/util/retry.py4
-rw-r--r--contrib/python/pip/pip/_vendor/urllib3/util/ssl_.py17
-rw-r--r--contrib/python/pip/pip/_vendor/vendor.txt8
-rw-r--r--contrib/python/pip/ya.make2
46 files changed, 864 insertions, 594 deletions
diff --git a/contrib/python/pip/.dist-info/METADATA b/contrib/python/pip/.dist-info/METADATA
index 6141107f90..9e5aa3a486 100644
--- a/contrib/python/pip/.dist-info/METADATA
+++ b/contrib/python/pip/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: pip
-Version: 24.2
+Version: 24.3.1
Summary: The PyPA recommended tool for installing Python packages.
Author-email: The pip developers <distutils-sig@python.org>
License: MIT
@@ -20,6 +20,7 @@ Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Requires-Python: >=3.8
diff --git a/contrib/python/pip/AUTHORS.txt b/contrib/python/pip/AUTHORS.txt
index dda2ac30f8..8ccefbc6e5 100644
--- a/contrib/python/pip/AUTHORS.txt
+++ b/contrib/python/pip/AUTHORS.txt
@@ -57,6 +57,7 @@ Anthony Sottile
Antoine Musso
Anton Ovchinnikov
Anton Patrushev
+Anton Zelenov
Antonio Alvarado Hernandez
Antony Lee
Antti Kaihola
@@ -225,6 +226,7 @@ Diego Ramirez
DiegoCaraballo
Dimitri Merejkowsky
Dimitri Papadopoulos
+Dimitri Papadopoulos Orfanos
Dirk Stolle
Dmitry Gladkov
Dmitry Volodin
@@ -690,6 +692,7 @@ snook92
socketubs
Sorin Sbarnea
Srinivas Nyayapati
+Srishti Hegde
Stavros Korokithakis
Stefan Scherfke
Stefano Rivera
diff --git a/contrib/python/pip/patches/01-arcadia.patch b/contrib/python/pip/patches/01-arcadia.patch
deleted file mode 100644
index 3bf8efa83c..0000000000
--- a/contrib/python/pip/patches/01-arcadia.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-DEVTOOLSSUPPORT-48054
---- contrib/python/pip/pip/_vendor/distlib/scripts.py (index)
-+++ contrib/python/pip/pip/_vendor/distlib/scripts.py (working tree)
-@@ -62,9 +62,6 @@ if __name__ == '__main__':
- distlib_package = __name__.rsplit('.', 1)[0]
-
- WRAPPERS = {
-- r.name: r.bytes
-- for r in finder(distlib_package).iterator("")
-- if r.name.endswith(".exe")
- }
-
-
diff --git a/contrib/python/pip/pip/__init__.py b/contrib/python/pip/pip/__init__.py
index 640e922f53..efefccffc7 100644
--- a/contrib/python/pip/pip/__init__.py
+++ b/contrib/python/pip/pip/__init__.py
@@ -1,6 +1,6 @@
from typing import List, Optional
-__version__ = "24.2"
+__version__ = "24.3.1"
def main(args: Optional[List[str]] = None) -> int:
diff --git a/contrib/python/pip/pip/_internal/build_env.py b/contrib/python/pip/pip/_internal/build_env.py
index be1e0ca85d..0f1e2667ca 100644
--- a/contrib/python/pip/pip/_internal/build_env.py
+++ b/contrib/python/pip/pip/_internal/build_env.py
@@ -242,6 +242,10 @@ class BuildEnvironment:
prefix.path,
"--no-warn-script-location",
"--disable-pip-version-check",
+ # The prefix specified two lines above, thus
+ # target from config file or env var should be ignored
+ "--target",
+ "",
]
if logger.getEffectiveLevel() <= logging.DEBUG:
args.append("-vv")
diff --git a/contrib/python/pip/pip/_internal/cli/index_command.py b/contrib/python/pip/pip/_internal/cli/index_command.py
index 226f8da1e9..db105d0fef 100644
--- a/contrib/python/pip/pip/_internal/cli/index_command.py
+++ b/contrib/python/pip/pip/_internal/cli/index_command.py
@@ -54,7 +54,7 @@ class SessionCommandMixin(CommandContextMixIn):
def __init__(self) -> None:
super().__init__()
- self._session: Optional["PipSession"] = None
+ self._session: Optional[PipSession] = None
@classmethod
def _get_index_urls(cls, options: Values) -> Optional[List[str]]:
diff --git a/contrib/python/pip/pip/_internal/cli/parser.py b/contrib/python/pip/pip/_internal/cli/parser.py
index b7d7c1f600..bc4aca032d 100644
--- a/contrib/python/pip/pip/_internal/cli/parser.py
+++ b/contrib/python/pip/pip/_internal/cli/parser.py
@@ -6,7 +6,7 @@ import shutil
import sys
import textwrap
from contextlib import suppress
-from typing import Any, Dict, Generator, List, Optional, Tuple
+from typing import Any, Dict, Generator, List, NoReturn, Optional, Tuple
from pip._internal.cli.status_codes import UNKNOWN_ERROR
from pip._internal.configuration import Configuration, ConfigurationError
@@ -289,6 +289,6 @@ class ConfigOptionParser(CustomOptionParser):
defaults[option.dest] = option.check_value(opt_str, default)
return optparse.Values(defaults)
- def error(self, msg: str) -> None:
+ def error(self, msg: str) -> NoReturn:
self.print_usage(sys.stderr)
self.exit(UNKNOWN_ERROR, f"{msg}\n")
diff --git a/contrib/python/pip/pip/_internal/cli/progress_bars.py b/contrib/python/pip/pip/_internal/cli/progress_bars.py
index 883359c9ce..1236180c08 100644
--- a/contrib/python/pip/pip/_internal/cli/progress_bars.py
+++ b/contrib/python/pip/pip/_internal/cli/progress_bars.py
@@ -25,7 +25,7 @@ def _rich_progress_bar(
iterable: Iterable[bytes],
*,
bar_type: str,
- size: int,
+ size: Optional[int],
) -> Generator[bytes, None, None]:
assert bar_type == "on", "This should only be used in the default mode."
diff --git a/contrib/python/pip/pip/_internal/commands/list.py b/contrib/python/pip/pip/_internal/commands/list.py
index 82fc46a118..8494370241 100644
--- a/contrib/python/pip/pip/_internal/commands/list.py
+++ b/contrib/python/pip/pip/_internal/commands/list.py
@@ -176,7 +176,7 @@ class ListCommand(IndexGroupCommand):
if options.excludes:
skip.update(canonicalize_name(n) for n in options.excludes)
- packages: "_ProcessedDists" = [
+ packages: _ProcessedDists = [
cast("_DistWithLatestInfo", d)
for d in get_environment(options.path).iter_installed_distributions(
local_only=options.local,
diff --git a/contrib/python/pip/pip/_internal/commands/search.py b/contrib/python/pip/pip/_internal/commands/search.py
index e0d329d58a..74b8d656b4 100644
--- a/contrib/python/pip/pip/_internal/commands/search.py
+++ b/contrib/python/pip/pip/_internal/commands/search.py
@@ -89,7 +89,7 @@ def transform_hits(hits: List[Dict[str, str]]) -> List["TransformedHit"]:
packages with the list of versions stored inline. This converts the
list from pypi into one we can use.
"""
- packages: Dict[str, "TransformedHit"] = OrderedDict()
+ packages: Dict[str, TransformedHit] = OrderedDict()
for hit in hits:
name = hit["name"]
summary = hit["summary"]
diff --git a/contrib/python/pip/pip/_internal/exceptions.py b/contrib/python/pip/pip/_internal/exceptions.py
index 2587740f73..45a876a850 100644
--- a/contrib/python/pip/pip/_internal/exceptions.py
+++ b/contrib/python/pip/pip/_internal/exceptions.py
@@ -15,6 +15,8 @@ import sys
from itertools import chain, groupby, repeat
from typing import TYPE_CHECKING, Dict, Iterator, List, Literal, Optional, Union
+from pip._vendor.packaging.requirements import InvalidRequirement
+from pip._vendor.packaging.version import InvalidVersion
from pip._vendor.rich.console import Console, ConsoleOptions, RenderResult
from pip._vendor.rich.markup import escape
from pip._vendor.rich.text import Text
@@ -429,7 +431,7 @@ class HashErrors(InstallationError):
"""Multiple HashError instances rolled into one for reporting"""
def __init__(self) -> None:
- self.errors: List["HashError"] = []
+ self.errors: List[HashError] = []
def append(self, error: "HashError") -> None:
self.errors.append(error)
@@ -775,3 +777,33 @@ class LegacyDistutilsInstall(DiagnosticPipError):
),
hint_stmt=None,
)
+
+
+class InvalidInstalledPackage(DiagnosticPipError):
+ reference = "invalid-installed-package"
+
+ def __init__(
+ self,
+ *,
+ dist: "BaseDistribution",
+ invalid_exc: Union[InvalidRequirement, InvalidVersion],
+ ) -> None:
+ installed_location = dist.installed_location
+
+ if isinstance(invalid_exc, InvalidRequirement):
+ invalid_type = "requirement"
+ else:
+ invalid_type = "version"
+
+ super().__init__(
+ message=Text(
+ f"Cannot process installed package {dist} "
+ + (f"in {installed_location!r} " if installed_location else "")
+ + f"because it has an invalid {invalid_type}:\n{invalid_exc.args[0]}"
+ ),
+ context=(
+ "Starting with pip 24.1, packages with invalid "
+ f"{invalid_type}s can not be processed."
+ ),
+ hint_stmt="To proceed this package must be uninstalled.",
+ )
diff --git a/contrib/python/pip/pip/_internal/index/sources.py b/contrib/python/pip/pip/_internal/index/sources.py
index f4626d71ab..3dafb30e6e 100644
--- a/contrib/python/pip/pip/_internal/index/sources.py
+++ b/contrib/python/pip/pip/_internal/index/sources.py
@@ -6,7 +6,6 @@ from typing import Callable, Dict, Iterable, List, Optional, Tuple
from pip._vendor.packaging.utils import (
InvalidSdistFilename,
- InvalidVersion,
InvalidWheelFilename,
canonicalize_name,
parse_sdist_filename,
@@ -68,10 +67,10 @@ class _FlatDirectoryToUrls:
# otherwise not worth considering as a package
try:
project_filename = parse_wheel_filename(entry.name)[0]
- except (InvalidWheelFilename, InvalidVersion):
+ except InvalidWheelFilename:
try:
project_filename = parse_sdist_filename(entry.name)[0]
- except (InvalidSdistFilename, InvalidVersion):
+ except InvalidSdistFilename:
continue
self._project_name_to_urls[project_filename].append(url)
diff --git a/contrib/python/pip/pip/_internal/locations/_distutils.py b/contrib/python/pip/pip/_internal/locations/_distutils.py
index 0e18c6e1e1..3d85625698 100644
--- a/contrib/python/pip/pip/_internal/locations/_distutils.py
+++ b/contrib/python/pip/pip/_internal/locations/_distutils.py
@@ -21,7 +21,7 @@ from distutils.cmd import Command as DistutilsCommand
from distutils.command.install import SCHEME_KEYS
from distutils.command.install import install as distutils_install_command
from distutils.sysconfig import get_python_lib
-from typing import Dict, List, Optional, Union, cast
+from typing import Dict, List, Optional, Union
from pip._internal.models.scheme import Scheme
from pip._internal.utils.compat import WINDOWS
@@ -64,7 +64,7 @@ def distutils_scheme(
obj: Optional[DistutilsCommand] = None
obj = d.get_command_obj("install", create=True)
assert obj is not None
- i = cast(distutils_install_command, obj)
+ i: distutils_install_command = obj
# NOTE: setting user or home has the side-effect of creating the home dir
# or user base for installations during finalize_options()
# ideally, we'd prefer a scheme class that has no side-effects.
@@ -78,7 +78,7 @@ def distutils_scheme(
i.root = root or i.root
i.finalize_options()
- scheme = {}
+ scheme: Dict[str, str] = {}
for key in SCHEME_KEYS:
scheme[key] = getattr(i, "install_" + key)
diff --git a/contrib/python/pip/pip/_internal/metadata/importlib/_envs.py b/contrib/python/pip/pip/_internal/metadata/importlib/_envs.py
index 70cb7a6009..4d906fd314 100644
--- a/contrib/python/pip/pip/_internal/metadata/importlib/_envs.py
+++ b/contrib/python/pip/pip/_internal/metadata/importlib/_envs.py
@@ -150,7 +150,7 @@ def _emit_egg_deprecation(location: Optional[str]) -> None:
deprecated(
reason=f"Loading egg at {location} is deprecated.",
replacement="to use pip for package installation",
- gone_in="24.3",
+ gone_in="25.1",
issue=12330,
)
diff --git a/contrib/python/pip/pip/_internal/models/wheel.py b/contrib/python/pip/pip/_internal/models/wheel.py
index 36d4d2e785..ea8560089d 100644
--- a/contrib/python/pip/pip/_internal/models/wheel.py
+++ b/contrib/python/pip/pip/_internal/models/wheel.py
@@ -6,8 +6,13 @@ import re
from typing import Dict, Iterable, List
from pip._vendor.packaging.tags import Tag
+from pip._vendor.packaging.utils import (
+ InvalidWheelFilename as PackagingInvalidWheelName,
+)
+from pip._vendor.packaging.utils import parse_wheel_filename
from pip._internal.exceptions import InvalidWheelFilename
+from pip._internal.utils.deprecation import deprecated
class Wheel:
@@ -29,9 +34,29 @@ class Wheel:
raise InvalidWheelFilename(f"{filename} is not a valid wheel filename.")
self.filename = filename
self.name = wheel_info.group("name").replace("_", "-")
- # we'll assume "_" means "-" due to wheel naming scheme
- # (https://github.com/pypa/pip/issues/1150)
- self.version = wheel_info.group("ver").replace("_", "-")
+ _version = wheel_info.group("ver")
+ if "_" in _version:
+ try:
+ parse_wheel_filename(filename)
+ except PackagingInvalidWheelName as e:
+ deprecated(
+ reason=(
+ f"Wheel filename {filename!r} is not correctly normalised. "
+ "Future versions of pip will raise the following error:\n"
+ f"{e.args[0]}\n\n"
+ ),
+ replacement=(
+ "to rename the wheel to use a correctly normalised "
+ "name (this may require updating the version in "
+ "the project metadata)"
+ ),
+ gone_in="25.1",
+ issue=12938,
+ )
+
+ _version = _version.replace("_", "-")
+
+ self.version = _version
self.build_tag = wheel_info.group("build")
self.pyversions = wheel_info.group("pyver").split(".")
self.abis = wheel_info.group("abi").split(".")
diff --git a/contrib/python/pip/pip/_internal/network/lazy_wheel.py b/contrib/python/pip/pip/_internal/network/lazy_wheel.py
index 82ec50d510..03f883c1fc 100644
--- a/contrib/python/pip/pip/_internal/network/lazy_wheel.py
+++ b/contrib/python/pip/pip/_internal/network/lazy_wheel.py
@@ -159,7 +159,7 @@ class LazyZipOverHTTP:
try:
# For read-only ZIP files, ZipFile only needs
# methods read, seek, seekable and tell.
- ZipFile(self) # type: ignore
+ ZipFile(self)
except BadZipFile:
pass
else:
diff --git a/contrib/python/pip/pip/_internal/req/constructors.py b/contrib/python/pip/pip/_internal/req/constructors.py
index d73236e05c..56a964f317 100644
--- a/contrib/python/pip/pip/_internal/req/constructors.py
+++ b/contrib/python/pip/pip/_internal/req/constructors.py
@@ -80,7 +80,7 @@ def _set_requirement_extras(req: Requirement, new_extras: Set[str]) -> Requireme
assert (
pre is not None and post is not None
), f"regex group selection for requirement {req} failed, this should never happen"
- extras: str = "[%s]" % ",".join(sorted(new_extras)) if new_extras else ""
+ extras: str = "[{}]".format(",".join(sorted(new_extras)) if new_extras else "")
return get_requirement(f"{pre}{extras}{post}")
diff --git a/contrib/python/pip/pip/_internal/req/req_file.py b/contrib/python/pip/pip/_internal/req/req_file.py
index 53ad8674cd..eb2a1f6992 100644
--- a/contrib/python/pip/pip/_internal/req/req_file.py
+++ b/contrib/python/pip/pip/_internal/req/req_file.py
@@ -329,10 +329,15 @@ class RequirementsFileParser:
self, filename: str, constraint: bool
) -> Generator[ParsedLine, None, None]:
"""Parse a given file, yielding parsed lines."""
- yield from self._parse_and_recurse(filename, constraint)
+ yield from self._parse_and_recurse(
+ filename, constraint, [{os.path.abspath(filename): None}]
+ )
def _parse_and_recurse(
- self, filename: str, constraint: bool
+ self,
+ filename: str,
+ constraint: bool,
+ parsed_files_stack: List[Dict[str, Optional[str]]],
) -> Generator[ParsedLine, None, None]:
for line in self._parse_file(filename, constraint):
if not line.is_requirement and (
@@ -353,12 +358,30 @@ class RequirementsFileParser:
# original file and nested file are paths
elif not SCHEME_RE.search(req_path):
# do a join so relative paths work
- req_path = os.path.join(
- os.path.dirname(filename),
- req_path,
+ # and then abspath so that we can identify recursive references
+ req_path = os.path.abspath(
+ os.path.join(
+ os.path.dirname(filename),
+ req_path,
+ )
)
-
- yield from self._parse_and_recurse(req_path, nested_constraint)
+ parsed_files = parsed_files_stack[0]
+ if req_path in parsed_files:
+ initial_file = parsed_files[req_path]
+ tail = (
+ f" and again in {initial_file}"
+ if initial_file is not None
+ else ""
+ )
+ raise RequirementsFileParseError(
+ f"{req_path} recursively references itself in {filename}{tail}"
+ )
+ # Keeping a track where was each file first included in
+ new_parsed_files = parsed_files.copy()
+ new_parsed_files[req_path] = filename
+ yield from self._parse_and_recurse(
+ req_path, nested_constraint, [new_parsed_files, *parsed_files_stack]
+ )
else:
yield line
diff --git a/contrib/python/pip/pip/_internal/resolution/resolvelib/candidates.py b/contrib/python/pip/pip/_internal/resolution/resolvelib/candidates.py
index d30d477be6..6617644fe5 100644
--- a/contrib/python/pip/pip/_internal/resolution/resolvelib/candidates.py
+++ b/contrib/python/pip/pip/_internal/resolution/resolvelib/candidates.py
@@ -9,6 +9,7 @@ from pip._vendor.packaging.version import Version
from pip._internal.exceptions import (
HashError,
InstallationSubprocessError,
+ InvalidInstalledPackage,
MetadataInconsistent,
MetadataInvalid,
)
@@ -398,8 +399,12 @@ class AlreadyInstalledCandidate(Candidate):
def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]:
if not with_requires:
return
- for r in self.dist.iter_dependencies():
- yield from self._factory.make_requirements_from_spec(str(r), self._ireq)
+
+ try:
+ for r in self.dist.iter_dependencies():
+ yield from self._factory.make_requirements_from_spec(str(r), self._ireq)
+ except InvalidRequirement as exc:
+ raise InvalidInstalledPackage(dist=self.dist, invalid_exc=exc) from None
def get_install_requirement(self) -> Optional[InstallRequirement]:
return None
diff --git a/contrib/python/pip/pip/_internal/resolution/resolvelib/factory.py b/contrib/python/pip/pip/_internal/resolution/resolvelib/factory.py
index 145bdbf71a..dc6e2e12e1 100644
--- a/contrib/python/pip/pip/_internal/resolution/resolvelib/factory.py
+++ b/contrib/python/pip/pip/_internal/resolution/resolvelib/factory.py
@@ -23,13 +23,14 @@ from typing import (
from pip._vendor.packaging.requirements import InvalidRequirement
from pip._vendor.packaging.specifiers import SpecifierSet
from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
-from pip._vendor.packaging.version import Version
+from pip._vendor.packaging.version import InvalidVersion, Version
from pip._vendor.resolvelib import ResolutionImpossible
from pip._internal.cache import CacheEntry, WheelCache
from pip._internal.exceptions import (
DistributionNotFound,
InstallationError,
+ InvalidInstalledPackage,
MetadataInconsistent,
MetadataInvalid,
UnsupportedPythonVersion,
@@ -283,10 +284,15 @@ class Factory:
installed_dist = self._installed_dists[name]
except KeyError:
return None
- # Don't use the installed distribution if its version does not fit
- # the current dependency graph.
- if not specifier.contains(installed_dist.version, prereleases=True):
- return None
+
+ try:
+ # Don't use the installed distribution if its version
+ # does not fit the current dependency graph.
+ if not specifier.contains(installed_dist.version, prereleases=True):
+ return None
+ except InvalidVersion as e:
+ raise InvalidInstalledPackage(dist=installed_dist, invalid_exc=e)
+
candidate = self._make_candidate_from_dist(
dist=installed_dist,
extras=extras,
diff --git a/contrib/python/pip/pip/_internal/utils/compatibility_tags.py b/contrib/python/pip/pip/_internal/utils/compatibility_tags.py
index b6ed9a78e5..2e7b7450dc 100644
--- a/contrib/python/pip/pip/_internal/utils/compatibility_tags.py
+++ b/contrib/python/pip/pip/_internal/utils/compatibility_tags.py
@@ -12,10 +12,11 @@ from pip._vendor.packaging.tags import (
generic_tags,
interpreter_name,
interpreter_version,
+ ios_platforms,
mac_platforms,
)
-_osx_arch_pat = re.compile(r"(.+)_(\d+)_(\d+)_(.+)")
+_apple_arch_pat = re.compile(r"(.+)_(\d+)_(\d+)_(.+)")
def version_info_to_nodot(version_info: Tuple[int, ...]) -> str:
@@ -24,7 +25,7 @@ def version_info_to_nodot(version_info: Tuple[int, ...]) -> str:
def _mac_platforms(arch: str) -> List[str]:
- match = _osx_arch_pat.match(arch)
+ match = _apple_arch_pat.match(arch)
if match:
name, major, minor, actual_arch = match.groups()
mac_version = (int(major), int(minor))
@@ -43,6 +44,26 @@ def _mac_platforms(arch: str) -> List[str]:
return arches
+def _ios_platforms(arch: str) -> List[str]:
+ match = _apple_arch_pat.match(arch)
+ if match:
+ name, major, minor, actual_multiarch = match.groups()
+ ios_version = (int(major), int(minor))
+ arches = [
+ # Since we have always only checked that the platform starts
+ # with "ios", for backwards-compatibility we extract the
+ # actual prefix provided by the user in case they provided
+ # something like "ioscustom_". It may be good to remove
+ # this as undocumented or deprecate it in the future.
+ "{}_{}".format(name, arch[len("ios_") :])
+ for arch in ios_platforms(ios_version, actual_multiarch)
+ ]
+ else:
+ # arch pattern didn't match (?!)
+ arches = [arch]
+ return arches
+
+
def _custom_manylinux_platforms(arch: str) -> List[str]:
arches = [arch]
arch_prefix, arch_sep, arch_suffix = arch.partition("_")
@@ -68,6 +89,8 @@ def _get_custom_platforms(arch: str) -> List[str]:
arch_prefix, arch_sep, arch_suffix = arch.partition("_")
if arch.startswith("macosx"):
arches = _mac_platforms(arch)
+ elif arch.startswith("ios"):
+ arches = _ios_platforms(arch)
elif arch_prefix in ["manylinux2014", "manylinux2010"]:
arches = _custom_manylinux_platforms(arch)
else:
diff --git a/contrib/python/pip/pip/_internal/utils/misc.py b/contrib/python/pip/pip/_internal/utils/misc.py
index 3707e87268..c0a3e4d3b9 100644
--- a/contrib/python/pip/pip/_internal/utils/misc.py
+++ b/contrib/python/pip/pip/_internal/utils/misc.py
@@ -129,12 +129,7 @@ def rmtree(
onexc = _onerror_ignore
if onexc is None:
onexc = _onerror_reraise
- handler: OnErr = partial(
- # `[func, path, Union[ExcInfo, BaseException]] -> Any` is equivalent to
- # `Union[([func, path, ExcInfo] -> Any), ([func, path, BaseException] -> Any)]`.
- cast(Union[OnExc, OnErr], rmtree_errorhandler),
- onexc=onexc,
- )
+ handler: OnErr = partial(rmtree_errorhandler, onexc=onexc)
if sys.version_info >= (3, 12):
# See https://docs.python.org/3.12/whatsnew/3.12.html#shutil.
shutil.rmtree(dir, onexc=handler) # type: ignore
@@ -555,7 +550,7 @@ class HiddenText:
# This is useful for testing.
def __eq__(self, other: Any) -> bool:
- if type(self) != type(other):
+ if type(self) is not type(other):
return False
# The string being used for redaction doesn't also have to match,
diff --git a/contrib/python/pip/pip/_vendor/certifi/__init__.py b/contrib/python/pip/pip/_vendor/certifi/__init__.py
index d321f1bc3a..f61d77fa38 100644
--- a/contrib/python/pip/pip/_vendor/certifi/__init__.py
+++ b/contrib/python/pip/pip/_vendor/certifi/__init__.py
@@ -1,4 +1,4 @@
from .core import contents, where
__all__ = ["contents", "where"]
-__version__ = "2024.07.04"
+__version__ = "2024.08.30"
diff --git a/contrib/python/pip/pip/_vendor/certifi/cacert.pem b/contrib/python/pip/pip/_vendor/certifi/cacert.pem
index a6581589ba..3c165a1b85 100644
--- a/contrib/python/pip/pip/_vendor/certifi/cacert.pem
+++ b/contrib/python/pip/pip/_vendor/certifi/cacert.pem
@@ -4796,3 +4796,134 @@ PQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgLcFBTApFw
hVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dG
XSaQpYXFuXqUPoeovQA=
-----END CERTIFICATE-----
+
+# Issuer: CN=TWCA CYBER Root CA O=TAIWAN-CA OU=Root CA
+# Subject: CN=TWCA CYBER Root CA O=TAIWAN-CA OU=Root CA
+# Label: "TWCA CYBER Root CA"
+# Serial: 85076849864375384482682434040119489222
+# MD5 Fingerprint: 0b:33:a0:97:52:95:d4:a9:fd:bb:db:6e:a3:55:5b:51
+# SHA1 Fingerprint: f6:b1:1c:1a:83:38:e9:7b:db:b3:a8:c8:33:24:e0:2d:9c:7f:26:66
+# SHA256 Fingerprint: 3f:63:bb:28:14:be:17:4e:c8:b6:43:9c:f0:8d:6d:56:f0:b7:c4:05:88:3a:56:48:a3:34:42:4d:6b:3e:c5:58
+-----BEGIN CERTIFICATE-----
+MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQ
+MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290
+IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5
+WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FO
+LUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3Qg
+Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1sTs6P
+40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxF
+avcokPFhV8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/
+34bKS1PE2Y2yHer43CdTo0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684i
+JkXXYJndzk834H/nY62wuFm40AZoNWDTNq5xQwTxaWV4fPMf88oon1oglWa0zbfu
+j3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK/c/WMw+f+5eesRycnupf
+Xtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkHIuNZW0CP
+2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDA
+S9TMfAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDA
+oS/xUgXJP+92ZuJF2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzC
+kHDXShi8fgGwsOsVHkQGzaRP6AzRwyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW
+5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83QOGt4A1WNzAd
+BgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB
+AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0t
+tGlTITVX1olNc79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn
+68xDiBaiA9a5F/gZbG0jAn/xX9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNn
+TKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDRIG4kqIQnoVesqlVYL9zZyvpoBJ7t
+RCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq/p1hvIbZv97Tujqx
+f36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0RFxbI
+Qh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz
+8ppy6rBePm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4
+NxKfKjLji7gh7MMrZQzvIt6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzX
+xeSDwWrruoBa3lwtcHb4yOWHh8qgnaHlIhInD0Q9HWzq1MKLL295q39QpsQZp6F6
+t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X
+-----END CERTIFICATE-----
+
+# Issuer: CN=SecureSign Root CA12 O=Cybertrust Japan Co., Ltd.
+# Subject: CN=SecureSign Root CA12 O=Cybertrust Japan Co., Ltd.
+# Label: "SecureSign Root CA12"
+# Serial: 587887345431707215246142177076162061960426065942
+# MD5 Fingerprint: c6:89:ca:64:42:9b:62:08:49:0b:1e:7f:e9:07:3d:e8
+# SHA1 Fingerprint: 7a:22:1e:3d:de:1b:06:ac:9e:c8:47:70:16:8e:3c:e5:f7:6b:06:f4
+# SHA256 Fingerprint: 3f:03:4b:b5:70:4d:44:b2:d0:85:45:a0:20:57:de:93:eb:f3:90:5f:ce:72:1a:cb:c7:30:c0:6d:da:ee:90:4e
+-----BEGIN CERTIFICATE-----
+MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQEL
+BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u
+LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgw
+NTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD
+eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS
+b290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3emhF
+KxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mt
+p7JIKwccJ/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zd
+J1M3s6oYwlkm7Fsf0uZlfO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gur
+FzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBFEaCeVESE99g2zvVQR9wsMJvuwPWW0v4J
+hscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1UefNzFJM3IFTQy2VYzxV4+K
+h9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
+AgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsF
+AAOCAQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6Ld
+mmQOmFxv3Y67ilQiLUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJ
+mBClnW8Zt7vPemVV2zfrPIpyMpcemik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA
+8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPSvWKErI4cqc1avTc7bgoitPQV
+55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhgaaaI5gdka9at/
+yOPiZwud9AzqVN/Ssq+xIvEg37xEHA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=SecureSign Root CA14 O=Cybertrust Japan Co., Ltd.
+# Subject: CN=SecureSign Root CA14 O=Cybertrust Japan Co., Ltd.
+# Label: "SecureSign Root CA14"
+# Serial: 575790784512929437950770173562378038616896959179
+# MD5 Fingerprint: 71:0d:72:fa:92:19:65:5e:89:04:ac:16:33:f0:bc:d5
+# SHA1 Fingerprint: dd:50:c0:f7:79:b3:64:2e:74:a2:b8:9d:9f:d3:40:dd:bb:f0:f2:4f
+# SHA256 Fingerprint: 4b:00:9c:10:34:49:4f:9a:b5:6b:ba:3b:a1:d6:27:31:fc:4d:20:d8:95:5a:dc:ec:10:a9:25:60:72:61:e3:38
+-----BEGIN CERTIFICATE-----
+MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEM
+BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u
+LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgw
+NzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD
+eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS
+b290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh1oq/
+FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOg
+vlIfX8xnbacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy
+6pJxaeQp8E+BgQQ8sqVb1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo
+/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9J
+kdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOEkJTRX45zGRBdAuVwpcAQ
+0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSxjVIHvXib
+y8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac
+18izju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs
+0Wq2XSqypWa9a4X0dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIAB
+SMbHdPTGrMNASRZhdCyvjG817XsYAFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVL
+ApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeqYR3r6/wtbyPk
+86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E
+rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ib
+ed87hwriZLoAymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopT
+zfFP7ELyk+OZpDc8h7hi2/DsHzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHS
+DCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPGFrojutzdfhrGe0K22VoF3Jpf1d+4
+2kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6qnsb58Nn4DSEC5MUo
+FlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/OfVy
+K4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6
+dB7h7sxaOgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtl
+Lor6CZpO2oYofaphNdgOpygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB
+365jJ6UeTo3cKXhZ+PmhIIynJkBugnLNeLLIjzwec+fBH7/PzqUqm9tEZDKgu39c
+JRNItX+S
+-----END CERTIFICATE-----
+
+# Issuer: CN=SecureSign Root CA15 O=Cybertrust Japan Co., Ltd.
+# Subject: CN=SecureSign Root CA15 O=Cybertrust Japan Co., Ltd.
+# Label: "SecureSign Root CA15"
+# Serial: 126083514594751269499665114766174399806381178503
+# MD5 Fingerprint: 13:30:fc:c4:62:a6:a9:de:b5:c1:68:af:b5:d2:31:47
+# SHA1 Fingerprint: cb:ba:83:c8:c1:5a:5d:f1:f9:73:6f:ca:d7:ef:28:13:06:4a:07:7d
+# SHA256 Fingerprint: e7:78:f0:f0:95:fe:84:37:29:cd:1a:00:82:17:9e:53:14:a9:c2:91:44:28:05:e1:fb:1d:8f:b6:b8:88:6c:3a
+-----BEGIN CERTIFICATE-----
+MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMw
+UTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBM
+dGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMy
+NTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpDeWJl
+cnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBSb290
+IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5GdCx4
+wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSR
+ZHX+AezB2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMB
+Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT
+9DAKBggqhkjOPQQDAwNoADBlAjEA2S6Jfl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp
+4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJSwdLZrWeqrqgHkHZAXQ6
+bkU6iYAZezKYVWOr62Nuk22rGwlgMU4=
+-----END CERTIFICATE-----
diff --git a/contrib/python/pip/pip/_vendor/distlib/__init__.py b/contrib/python/pip/pip/_vendor/distlib/__init__.py
index e999438fe9..bf0d6c6d30 100644
--- a/contrib/python/pip/pip/_vendor/distlib/__init__.py
+++ b/contrib/python/pip/pip/_vendor/distlib/__init__.py
@@ -6,7 +6,7 @@
#
import logging
-__version__ = '0.3.8'
+__version__ = '0.3.9'
class DistlibException(Exception):
diff --git a/contrib/python/pip/pip/_vendor/distlib/compat.py b/contrib/python/pip/pip/_vendor/distlib/compat.py
index e93dc27a3e..ca561dd2e3 100644
--- a/contrib/python/pip/pip/_vendor/distlib/compat.py
+++ b/contrib/python/pip/pip/_vendor/distlib/compat.py
@@ -217,8 +217,7 @@ except ImportError: # pragma: no cover
# Additionally check that `file` is not a directory, as on Windows
# directories pass the os.access check.
def _access_check(fn, mode):
- return (os.path.exists(fn) and os.access(fn, mode)
- and not os.path.isdir(fn))
+ return (os.path.exists(fn) and os.access(fn, mode) and not os.path.isdir(fn))
# If we're given a path with a directory part, look it up directly rather
# than referring to PATH directories. This includes checking relative to the
diff --git a/contrib/python/pip/pip/_vendor/distlib/database.py b/contrib/python/pip/pip/_vendor/distlib/database.py
index eb3765f193..c0f896a7d8 100644
--- a/contrib/python/pip/pip/_vendor/distlib/database.py
+++ b/contrib/python/pip/pip/_vendor/distlib/database.py
@@ -20,14 +20,12 @@ import zipimport
from . import DistlibException, resources
from .compat import StringIO
from .version import get_scheme, UnsupportedVersionError
-from .metadata import (Metadata, METADATA_FILENAME, WHEEL_METADATA_FILENAME,
- LEGACY_METADATA_FILENAME)
-from .util import (parse_requirement, cached_property, parse_name_and_version,
- read_exports, write_exports, CSVReader, CSVWriter)
+from .metadata import (Metadata, METADATA_FILENAME, WHEEL_METADATA_FILENAME, LEGACY_METADATA_FILENAME)
+from .util import (parse_requirement, cached_property, parse_name_and_version, read_exports, write_exports, CSVReader,
+ CSVWriter)
__all__ = [
- 'Distribution', 'BaseInstalledDistribution', 'InstalledDistribution',
- 'EggInfoDistribution', 'DistributionPath'
+ 'Distribution', 'BaseInstalledDistribution', 'InstalledDistribution', 'EggInfoDistribution', 'DistributionPath'
]
logger = logging.getLogger(__name__)
@@ -35,8 +33,7 @@ logger = logging.getLogger(__name__)
EXPORTS_FILENAME = 'pydist-exports.json'
COMMANDS_FILENAME = 'pydist-commands.json'
-DIST_FILES = ('INSTALLER', METADATA_FILENAME, 'RECORD', 'REQUESTED',
- 'RESOURCES', EXPORTS_FILENAME, 'SHARED')
+DIST_FILES = ('INSTALLER', METADATA_FILENAME, 'RECORD', 'REQUESTED', 'RESOURCES', EXPORTS_FILENAME, 'SHARED')
DISTINFO_EXT = '.dist-info'
@@ -134,13 +131,9 @@ class DistributionPath(object):
continue
try:
if self._include_dist and entry.endswith(DISTINFO_EXT):
- possible_filenames = [
- METADATA_FILENAME, WHEEL_METADATA_FILENAME,
- LEGACY_METADATA_FILENAME
- ]
+ possible_filenames = [METADATA_FILENAME, WHEEL_METADATA_FILENAME, LEGACY_METADATA_FILENAME]
for metadata_filename in possible_filenames:
- metadata_path = posixpath.join(
- entry, metadata_filename)
+ metadata_path = posixpath.join(entry, metadata_filename)
pydist = finder.find(metadata_path)
if pydist:
break
@@ -148,15 +141,11 @@ class DistributionPath(object):
continue
with contextlib.closing(pydist.as_stream()) as stream:
- metadata = Metadata(fileobj=stream,
- scheme='legacy')
+ metadata = Metadata(fileobj=stream, scheme='legacy')
logger.debug('Found %s', r.path)
seen.add(r.path)
- yield new_dist_class(r.path,
- metadata=metadata,
- env=self)
- elif self._include_egg and entry.endswith(
- ('.egg-info', '.egg')):
+ yield new_dist_class(r.path, metadata=metadata, env=self)
+ elif self._include_egg and entry.endswith(('.egg-info', '.egg')):
logger.debug('Found %s', r.path)
seen.add(r.path)
yield old_dist_class(r.path, self)
@@ -274,8 +263,7 @@ class DistributionPath(object):
try:
matcher = self._scheme.matcher('%s (%s)' % (name, version))
except ValueError:
- raise DistlibException('invalid name or version: %r, %r' %
- (name, version))
+ raise DistlibException('invalid name or version: %r, %r' % (name, version))
for dist in self.get_distributions():
# We hit a problem on Travis where enum34 was installed and doesn't
@@ -390,10 +378,8 @@ class Distribution(object):
def _get_requirements(self, req_attr):
md = self.metadata
reqts = getattr(md, req_attr)
- logger.debug('%s: got requirements %r from metadata: %r', self.name,
- req_attr, reqts)
- return set(
- md.get_requirements(reqts, extras=self.extras, env=self.context))
+ logger.debug('%s: got requirements %r from metadata: %r', self.name, req_attr, reqts)
+ return set(md.get_requirements(reqts, extras=self.extras, env=self.context))
@property
def run_requires(self):
@@ -469,8 +455,7 @@ class Distribution(object):
if type(other) is not type(self):
result = False
else:
- result = (self.name == other.name and self.version == other.version
- and self.source_url == other.source_url)
+ result = (self.name == other.name and self.version == other.version and self.source_url == other.source_url)
return result
def __hash__(self):
@@ -561,8 +546,7 @@ class InstalledDistribution(BaseInstalledDistribution):
if r is None:
r = finder.find(LEGACY_METADATA_FILENAME)
if r is None:
- raise ValueError('no %s found in %s' %
- (METADATA_FILENAME, path))
+ raise ValueError('no %s found in %s' % (METADATA_FILENAME, path))
with contextlib.closing(r.as_stream()) as stream:
metadata = Metadata(fileobj=stream, scheme='legacy')
@@ -580,8 +564,7 @@ class InstalledDistribution(BaseInstalledDistribution):
self.modules = data.splitlines()
def __repr__(self):
- return '<InstalledDistribution %r %s at %r>' % (
- self.name, self.version, self.path)
+ return '<InstalledDistribution %r %s at %r>' % (self.name, self.version, self.path)
def __str__(self):
return "%s %s" % (self.name, self.version)
@@ -703,8 +686,7 @@ class InstalledDistribution(BaseInstalledDistribution):
size = '%d' % os.path.getsize(path)
with open(path, 'rb') as fp:
hash_value = self.get_hash(fp.read())
- if path.startswith(base) or (base_under_prefix
- and path.startswith(prefix)):
+ if path.startswith(base) or (base_under_prefix and path.startswith(prefix)):
path = os.path.relpath(path, base)
writer.writerow((path, hash_value, size))
@@ -746,8 +728,7 @@ class InstalledDistribution(BaseInstalledDistribution):
with open(path, 'rb') as f:
actual_hash = self.get_hash(f.read(), hasher)
if actual_hash != hash_value:
- mismatches.append(
- (path, 'hash', hash_value, actual_hash))
+ mismatches.append((path, 'hash', hash_value, actual_hash))
return mismatches
@cached_property
@@ -829,9 +810,8 @@ class InstalledDistribution(BaseInstalledDistribution):
# it's an absolute path?
distinfo_dirname, path = path.split(os.sep)[-2:]
if distinfo_dirname != self.path.split(os.sep)[-1]:
- raise DistlibException(
- 'dist-info file %r does not belong to the %r %s '
- 'distribution' % (path, self.name, self.version))
+ raise DistlibException('dist-info file %r does not belong to the %r %s '
+ 'distribution' % (path, self.name, self.version))
# The file must be relative
if path not in DIST_FILES:
@@ -857,8 +837,7 @@ class InstalledDistribution(BaseInstalledDistribution):
yield path
def __eq__(self, other):
- return (isinstance(other, InstalledDistribution)
- and self.path == other.path)
+ return (isinstance(other, InstalledDistribution) and self.path == other.path)
# See http://docs.python.org/reference/datamodel#object.__hash__
__hash__ = object.__hash__
@@ -911,8 +890,7 @@ class EggInfoDistribution(BaseInstalledDistribution):
if not line: # pragma: no cover
continue
if line.startswith('['): # pragma: no cover
- logger.warning(
- 'Unexpected line: quitting requirement scan: %r', line)
+ logger.warning('Unexpected line: quitting requirement scan: %r', line)
break
r = parse_requirement(line)
if not r: # pragma: no cover
@@ -954,13 +932,11 @@ class EggInfoDistribution(BaseInstalledDistribution):
else:
# FIXME handle the case where zipfile is not available
zipf = zipimport.zipimporter(path)
- fileobj = StringIO(
- zipf.get_data('EGG-INFO/PKG-INFO').decode('utf8'))
+ fileobj = StringIO(zipf.get_data('EGG-INFO/PKG-INFO').decode('utf8'))
metadata = Metadata(fileobj=fileobj, scheme='legacy')
try:
data = zipf.get_data('EGG-INFO/requires.txt')
- tl_data = zipf.get_data('EGG-INFO/top_level.txt').decode(
- 'utf-8')
+ tl_data = zipf.get_data('EGG-INFO/top_level.txt').decode('utf-8')
requires = parse_requires_data(data.decode('utf-8'))
except IOError:
requires = None
@@ -990,8 +966,7 @@ class EggInfoDistribution(BaseInstalledDistribution):
return metadata
def __repr__(self):
- return '<EggInfoDistribution %r %s at %r>' % (self.name, self.version,
- self.path)
+ return '<EggInfoDistribution %r %s at %r>' % (self.name, self.version, self.path)
def __str__(self):
return "%s %s" % (self.name, self.version)
@@ -1083,8 +1058,7 @@ class EggInfoDistribution(BaseInstalledDistribution):
yield line
def __eq__(self, other):
- return (isinstance(other, EggInfoDistribution)
- and self.path == other.path)
+ return (isinstance(other, EggInfoDistribution) and self.path == other.path)
# See http://docs.python.org/reference/datamodel#object.__hash__
__hash__ = object.__hash__
@@ -1184,8 +1158,7 @@ class DependencyGraph(object):
disconnected.append(dist)
for other, label in adjs:
if label is not None:
- f.write('"%s" -> "%s" [label="%s"]\n' %
- (dist.name, other.name, label))
+ f.write('"%s" -> "%s" [label="%s"]\n' % (dist.name, other.name, label))
else:
f.write('"%s" -> "%s"\n' % (dist.name, other.name))
if not skip_disconnected and len(disconnected) > 0:
@@ -1225,8 +1198,7 @@ class DependencyGraph(object):
# Remove from the adjacency list of others
for k, v in alist.items():
alist[k] = [(d, r) for d, r in v if d not in to_remove]
- logger.debug('Moving to result: %s',
- ['%s (%s)' % (d.name, d.version) for d in to_remove])
+ logger.debug('Moving to result: %s', ['%s (%s)' % (d.name, d.version) for d in to_remove])
result.extend(to_remove)
return result, list(alist.keys())
@@ -1261,15 +1233,13 @@ def make_graph(dists, scheme='default'):
# now make the edges
for dist in dists:
- requires = (dist.run_requires | dist.meta_requires
- | dist.build_requires | dist.dev_requires)
+ requires = (dist.run_requires | dist.meta_requires | dist.build_requires | dist.dev_requires)
for req in requires:
try:
matcher = scheme.matcher(req)
except UnsupportedVersionError:
# XXX compat-mode if cannot read the version
- logger.warning('could not read version %r - using name only',
- req)
+ logger.warning('could not read version %r - using name only', req)
name = req.split()[0]
matcher = scheme.matcher(name)
diff --git a/contrib/python/pip/pip/_vendor/distlib/locators.py b/contrib/python/pip/pip/_vendor/distlib/locators.py
index f9f0788fc2..222c1bf3e9 100644
--- a/contrib/python/pip/pip/_vendor/distlib/locators.py
+++ b/contrib/python/pip/pip/_vendor/distlib/locators.py
@@ -19,15 +19,12 @@ except ImportError: # pragma: no cover
import zlib
from . import DistlibException
-from .compat import (urljoin, urlparse, urlunparse, url2pathname, pathname2url,
- queue, quote, unescape, build_opener,
- HTTPRedirectHandler as BaseRedirectHandler, text_type,
- Request, HTTPError, URLError)
+from .compat import (urljoin, urlparse, urlunparse, url2pathname, pathname2url, queue, quote, unescape, build_opener,
+ HTTPRedirectHandler as BaseRedirectHandler, text_type, Request, HTTPError, URLError)
from .database import Distribution, DistributionPath, make_dist
from .metadata import Metadata, MetadataInvalidError
-from .util import (cached_property, ensure_slash, split_filename, get_project_data,
- parse_requirement, parse_name_and_version, ServerProxy,
- normalize_name)
+from .util import (cached_property, ensure_slash, split_filename, get_project_data, parse_requirement,
+ parse_name_and_version, ServerProxy, normalize_name)
from .version import get_scheme, UnsupportedVersionError
from .wheel import Wheel, is_compatible
@@ -58,6 +55,7 @@ class RedirectHandler(BaseRedirectHandler):
"""
A class to work around a bug in some Python 3.2.x releases.
"""
+
# There's a bug in the base version for some 3.2.x
# (e.g. 3.2.2 on Ubuntu Oneiric). If a Location header
# returns e.g. /abc, it bails because it says the scheme ''
@@ -80,8 +78,7 @@ class RedirectHandler(BaseRedirectHandler):
headers.replace_header(key, newurl)
else:
headers[key] = newurl
- return BaseRedirectHandler.http_error_302(self, req, fp, code, msg,
- headers)
+ return BaseRedirectHandler.http_error_302(self, req, fp, code, msg, headers)
http_error_301 = http_error_303 = http_error_307 = http_error_302
@@ -92,7 +89,7 @@ class Locator(object):
"""
source_extensions = ('.tar.gz', '.tar.bz2', '.tar', '.zip', '.tgz', '.tbz')
binary_extensions = ('.egg', '.exe', '.whl')
- excluded_extensions = ('.pdf',)
+ excluded_extensions = ('.pdf', )
# A list of tags indicating which wheels you want to match. The default
# value of None matches against the tags compatible with the running
@@ -100,7 +97,7 @@ class Locator(object):
# instance to a list of tuples (pyver, abi, arch) which you want to match.
wheel_tags = None
- downloadable_extensions = source_extensions + ('.whl',)
+ downloadable_extensions = source_extensions + ('.whl', )
def __init__(self, scheme='default'):
"""
@@ -200,8 +197,7 @@ class Locator(object):
is_downloadable = basename.endswith(self.downloadable_extensions)
if is_wheel:
compatible = is_compatible(Wheel(basename), self.wheel_tags)
- return (t.scheme == 'https', 'pypi.org' in t.netloc,
- is_downloadable, is_wheel, compatible, basename)
+ return (t.scheme == 'https', 'pypi.org' in t.netloc, is_downloadable, is_wheel, compatible, basename)
def prefer_url(self, url1, url2):
"""
@@ -239,14 +235,14 @@ class Locator(object):
If it is, a dictionary is returned with keys "name", "version",
"filename" and "url"; otherwise, None is returned.
"""
+
def same_project(name1, name2):
return normalize_name(name1) == normalize_name(name2)
result = None
scheme, netloc, path, params, query, frag = urlparse(url)
if frag.lower().startswith('egg='): # pragma: no cover
- logger.debug('%s: version hint in fragment: %r',
- project_name, frag)
+ logger.debug('%s: version hint in fragment: %r', project_name, frag)
m = HASHER_HASH.match(frag)
if m:
algo, digest = m.groups()
@@ -270,10 +266,8 @@ class Locator(object):
'name': wheel.name,
'version': wheel.version,
'filename': wheel.filename,
- 'url': urlunparse((scheme, netloc, origpath,
- params, query, '')),
- 'python-version': ', '.join(
- ['.'.join(list(v[2:])) for v in wheel.pyver]),
+ 'url': urlunparse((scheme, netloc, origpath, params, query, '')),
+ 'python-version': ', '.join(['.'.join(list(v[2:])) for v in wheel.pyver]),
}
except Exception: # pragma: no cover
logger.warning('invalid path for wheel: %s', path)
@@ -294,8 +288,7 @@ class Locator(object):
'name': name,
'version': version,
'filename': filename,
- 'url': urlunparse((scheme, netloc, origpath,
- params, query, '')),
+ 'url': urlunparse((scheme, netloc, origpath, params, query, '')),
}
if pyver: # pragma: no cover
result['python-version'] = pyver
@@ -371,7 +364,7 @@ class Locator(object):
self.matcher = matcher = scheme.matcher(r.requirement)
logger.debug('matcher: %s (%s)', matcher, type(matcher).__name__)
versions = self.get_project(r.name)
- if len(versions) > 2: # urls and digests keys are present
+ if len(versions) > 2: # urls and digests keys are present
# sometimes, versions are invalid
slist = []
vcls = matcher.version_class
@@ -412,6 +405,7 @@ class PyPIRPCLocator(Locator):
This locator uses XML-RPC to locate distributions. It therefore
cannot be used with simple mirrors (that only mirror file content).
"""
+
def __init__(self, url, **kwargs):
"""
Initialise an instance.
@@ -461,6 +455,7 @@ class PyPIJSONLocator(Locator):
This locator uses PyPI's JSON interface. It's very limited in functionality
and probably not worth using.
"""
+
def __init__(self, url, **kwargs):
super(PyPIJSONLocator, self).__init__(**kwargs)
self.base_url = ensure_slash(url)
@@ -498,7 +493,7 @@ class PyPIJSONLocator(Locator):
# Now get other releases
for version, infos in d['releases'].items():
if version == md.version:
- continue # already done
+ continue # already done
omd = Metadata(scheme=self.scheme)
omd.name = md.name
omd.version = version
@@ -511,6 +506,8 @@ class PyPIJSONLocator(Locator):
odist.digests[url] = self._get_digest(info)
result['urls'].setdefault(version, set()).add(url)
result['digests'][url] = self._get_digest(info)
+
+
# for info in urls:
# md.source_url = info['url']
# dist.digest = self._get_digest(info)
@@ -534,7 +531,8 @@ class Page(object):
# or immediately followed by a "rel" attribute. The attribute values can be
# declared with double quotes, single quotes or no quotes - which leads to
# the length of the expression.
- _href = re.compile("""
+ _href = re.compile(
+ """
(rel\\s*=\\s*(?:"(?P<rel1>[^"]*)"|'(?P<rel2>[^']*)'|(?P<rel3>[^>\\s\n]*))\\s+)?
href\\s*=\\s*(?:"(?P<url1>[^"]*)"|'(?P<url2>[^']*)'|(?P<url3>[^>\\s\n]*))
(\\s+rel\\s*=\\s*(?:"(?P<rel4>[^"]*)"|'(?P<rel5>[^']*)'|(?P<rel6>[^>\\s\n]*)))?
@@ -561,17 +559,16 @@ href\\s*=\\s*(?:"(?P<url1>[^"]*)"|'(?P<url2>[^']*)'|(?P<url3>[^>\\s\n]*))
about their "rel" attribute, for determining which ones to treat as
downloads and which ones to queue for further scraping.
"""
+
def clean(url):
"Tidy up an URL."
scheme, netloc, path, params, query, frag = urlparse(url)
- return urlunparse((scheme, netloc, quote(path),
- params, query, frag))
+ return urlunparse((scheme, netloc, quote(path), params, query, frag))
result = set()
for match in self._href.finditer(self.data):
d = match.groupdict('')
- rel = (d['rel1'] or d['rel2'] or d['rel3'] or
- d['rel4'] or d['rel5'] or d['rel6'])
+ rel = (d['rel1'] or d['rel2'] or d['rel3'] or d['rel4'] or d['rel5'] or d['rel6'])
url = d['url1'] or d['url2'] or d['url3']
url = urljoin(self.base_url, url)
url = unescape(url)
@@ -645,7 +642,7 @@ class SimpleScrapingLocator(Locator):
# Note that you need two loops, since you can't say which
# thread will get each sentinel
for t in self._threads:
- self._to_fetch.put(None) # sentinel
+ self._to_fetch.put(None) # sentinel
for t in self._threads:
t.join()
self._threads = []
@@ -693,7 +690,7 @@ class SimpleScrapingLocator(Locator):
info = self.convert_url_to_download_info(url, self.project_name)
logger.debug('process_download: %s -> %s', url, info)
if info:
- with self._lock: # needed because self.result is shared
+ with self._lock: # needed because self.result is shared
self._update_version_data(self.result, info)
return info
@@ -703,8 +700,7 @@ class SimpleScrapingLocator(Locator):
particular "rel" attribute should be queued for scraping.
"""
scheme, netloc, path, _, _, _ = urlparse(link)
- if path.endswith(self.source_extensions + self.binary_extensions +
- self.excluded_extensions):
+ if path.endswith(self.source_extensions + self.binary_extensions + self.excluded_extensions):
result = False
elif self.skip_externals and not link.startswith(self.base_url):
result = False
@@ -722,8 +718,7 @@ class SimpleScrapingLocator(Locator):
result = False
else:
result = True
- logger.debug('should_queue: %s (%s) from %s -> %s', link, rel,
- referrer, result)
+ logger.debug('should_queue: %s (%s) from %s -> %s', link, rel, referrer, result)
return result
def _fetch(self):
@@ -738,14 +733,13 @@ class SimpleScrapingLocator(Locator):
try:
if url:
page = self.get_page(url)
- if page is None: # e.g. after an error
+ if page is None: # e.g. after an error
continue
for link, rel in page.links:
if link not in self._seen:
try:
self._seen.add(link)
- if (not self._process_download(link) and
- self._should_queue(link, url, rel)):
+ if (not self._process_download(link) and self._should_queue(link, url, rel)):
logger.debug('Queueing %s from %s', link, url)
self._to_fetch.put(link)
except MetadataInvalidError: # e.g. invalid versions
@@ -793,7 +787,7 @@ class SimpleScrapingLocator(Locator):
data = resp.read()
encoding = headers.get('Content-Encoding')
if encoding:
- decoder = self.decoders[encoding] # fail if not found
+ decoder = self.decoders[encoding] # fail if not found
data = decoder(data)
encoding = 'utf-8'
m = CHARSET.search(content_type)
@@ -802,7 +796,7 @@ class SimpleScrapingLocator(Locator):
try:
data = data.decode(encoding)
except UnicodeError: # pragma: no cover
- data = data.decode('latin-1') # fallback
+ data = data.decode('latin-1') # fallback
result = Page(data, final_url)
self._page_cache[final_url] = result
except HTTPError as e:
@@ -815,7 +809,7 @@ class SimpleScrapingLocator(Locator):
except Exception as e: # pragma: no cover
logger.exception('Fetch failed: %s: %s', url, e)
finally:
- self._page_cache[url] = result # even if None (failure)
+ self._page_cache[url] = result # even if None (failure)
return result
_distname_re = re.compile('<a href=[^>]*>([^<]+)<')
@@ -869,9 +863,7 @@ class DirectoryLocator(Locator):
for fn in files:
if self.should_include(fn, root):
fn = os.path.join(root, fn)
- url = urlunparse(('file', '',
- pathname2url(os.path.abspath(fn)),
- '', '', ''))
+ url = urlunparse(('file', '', pathname2url(os.path.abspath(fn)), '', '', ''))
info = self.convert_url_to_download_info(url, name)
if info:
self._update_version_data(result, info)
@@ -888,9 +880,7 @@ class DirectoryLocator(Locator):
for fn in files:
if self.should_include(fn, root):
fn = os.path.join(root, fn)
- url = urlunparse(('file', '',
- pathname2url(os.path.abspath(fn)),
- '', '', ''))
+ url = urlunparse(('file', '', pathname2url(os.path.abspath(fn)), '', '', ''))
info = self.convert_url_to_download_info(url, None)
if info:
result.add(info['name'])
@@ -906,6 +896,7 @@ class JSONLocator(Locator):
require archive downloads before dependencies can be determined! As you
might imagine, that can be slow.
"""
+
def get_distribution_names(self):
"""
Return all the distribution names known to this locator.
@@ -922,9 +913,9 @@ class JSONLocator(Locator):
# We don't store summary in project metadata as it makes
# the data bigger for no benefit during dependency
# resolution
- dist = make_dist(data['name'], info['version'],
- summary=data.get('summary',
- 'Placeholder for summary'),
+ dist = make_dist(data['name'],
+ info['version'],
+ summary=data.get('summary', 'Placeholder for summary'),
scheme=self.scheme)
md = dist.metadata
md.source_url = info['url']
@@ -943,6 +934,7 @@ class DistPathLocator(Locator):
This locator finds installed distributions in a path. It can be useful for
adding to an :class:`AggregatingLocator`.
"""
+
def __init__(self, distpath, **kwargs):
"""
Initialise an instance.
@@ -960,8 +952,12 @@ class DistPathLocator(Locator):
else:
result = {
dist.version: dist,
- 'urls': {dist.version: set([dist.source_url])},
- 'digests': {dist.version: set([None])}
+ 'urls': {
+ dist.version: set([dist.source_url])
+ },
+ 'digests': {
+ dist.version: set([None])
+ }
}
return result
@@ -970,6 +966,7 @@ class AggregatingLocator(Locator):
"""
This class allows you to chain and/or merge a list of locators.
"""
+
def __init__(self, *locators, **kwargs):
"""
Initialise an instance.
@@ -1058,10 +1055,9 @@ class AggregatingLocator(Locator):
# We use a legacy scheme simply because most of the dists on PyPI use legacy
# versions which don't conform to PEP 440.
default_locator = AggregatingLocator(
- # JSONLocator(), # don't use as PEP 426 is withdrawn
- SimpleScrapingLocator('https://pypi.org/simple/',
- timeout=3.0),
- scheme='legacy')
+ # JSONLocator(), # don't use as PEP 426 is withdrawn
+ SimpleScrapingLocator('https://pypi.org/simple/', timeout=3.0),
+ scheme='legacy')
locate = default_locator.locate
@@ -1137,7 +1133,7 @@ class DependencyFinder(object):
:return: A set of distribution which can fulfill the requirement.
"""
matcher = self.get_matcher(reqt)
- name = matcher.key # case-insensitive
+ name = matcher.key # case-insensitive
result = set()
provided = self.provided
if name in provided:
@@ -1179,8 +1175,7 @@ class DependencyFinder(object):
unmatched.add(s)
if unmatched:
# can't replace other with provider
- problems.add(('cantreplace', provider, other,
- frozenset(unmatched)))
+ problems.add(('cantreplace', provider, other, frozenset(unmatched)))
result = False
else:
# can replace other with provider
@@ -1233,8 +1228,7 @@ class DependencyFinder(object):
dist = odist = requirement
logger.debug('passed %s as requirement', odist)
else:
- dist = odist = self.locator.locate(requirement,
- prereleases=prereleases)
+ dist = odist = self.locator.locate(requirement, prereleases=prereleases)
if dist is None:
raise DistlibException('Unable to locate %r' % requirement)
logger.debug('located %s', odist)
@@ -1244,7 +1238,7 @@ class DependencyFinder(object):
install_dists = set([odist])
while todo:
dist = todo.pop()
- name = dist.key # case-insensitive
+ name = dist.key # case-insensitive
if name not in self.dists_by_name:
self.add_distribution(dist)
else:
@@ -1281,8 +1275,7 @@ class DependencyFinder(object):
providers.add(provider)
if r in ireqts and dist in install_dists:
install_dists.add(provider)
- logger.debug('Adding %s to install_dists',
- provider.name_and_version)
+ logger.debug('Adding %s to install_dists', provider.name_and_version)
for p in providers:
name = p.key
if name not in self.dists_by_name:
@@ -1297,7 +1290,6 @@ class DependencyFinder(object):
for dist in dists:
dist.build_time_dependency = dist not in install_dists
if dist.build_time_dependency:
- logger.debug('%s is a build-time dependency only.',
- dist.name_and_version)
+ logger.debug('%s is a build-time dependency only.', dist.name_and_version)
logger.debug('find done for %s', odist)
return dists, problems
diff --git a/contrib/python/pip/pip/_vendor/distlib/markers.py b/contrib/python/pip/pip/_vendor/distlib/markers.py
index 1514d460e7..3f5632be47 100644
--- a/contrib/python/pip/pip/_vendor/distlib/markers.py
+++ b/contrib/python/pip/pip/_vendor/distlib/markers.py
@@ -23,8 +23,7 @@ from .version import LegacyVersion as LV
__all__ = ['interpret']
-_VERSION_PATTERN = re.compile(
- r'((\d+(\.\d+)*\w*)|\'(\d+(\.\d+)*\w*)\'|\"(\d+(\.\d+)*\w*)\")')
+_VERSION_PATTERN = re.compile(r'((\d+(\.\d+)*\w*)|\'(\d+(\.\d+)*\w*)\'|\"(\d+(\.\d+)*\w*)\")')
_VERSION_MARKERS = {'python_version', 'python_full_version'}
@@ -82,13 +81,12 @@ class Evaluator(object):
elhs = expr['lhs']
erhs = expr['rhs']
if _is_literal(expr['lhs']) and _is_literal(expr['rhs']):
- raise SyntaxError('invalid comparison: %s %s %s' %
- (elhs, op, erhs))
+ raise SyntaxError('invalid comparison: %s %s %s' % (elhs, op, erhs))
lhs = self.evaluate(elhs, context)
rhs = self.evaluate(erhs, context)
- if ((_is_version_marker(elhs) or _is_version_marker(erhs))
- and op in ('<', '<=', '>', '>=', '===', '==', '!=', '~=')):
+ if ((_is_version_marker(elhs) or _is_version_marker(erhs)) and
+ op in ('<', '<=', '>', '>=', '===', '==', '!=', '~=')):
lhs = LV(lhs)
rhs = LV(rhs)
elif _is_version_marker(elhs) and op in ('in', 'not in'):
@@ -111,8 +109,7 @@ def default_context():
return version
if hasattr(sys, 'implementation'):
- implementation_version = format_full_version(
- sys.implementation.version)
+ implementation_version = format_full_version(sys.implementation.version)
implementation_name = sys.implementation.name
else:
implementation_version = '0'
@@ -156,11 +153,9 @@ def interpret(marker, execution_context=None):
try:
expr, rest = parse_marker(marker)
except Exception as e:
- raise SyntaxError('Unable to interpret marker syntax: %s: %s' %
- (marker, e))
+ raise SyntaxError('Unable to interpret marker syntax: %s: %s' % (marker, e))
if rest and rest[0] != '#':
- raise SyntaxError('unexpected trailing data in marker: %s: %s' %
- (marker, rest))
+ raise SyntaxError('unexpected trailing data in marker: %s: %s' % (marker, rest))
context = dict(DEFAULT_CONTEXT)
if execution_context:
context.update(execution_context)
diff --git a/contrib/python/pip/pip/_vendor/distlib/metadata.py b/contrib/python/pip/pip/_vendor/distlib/metadata.py
index 7189aeef22..ce9a34b3e2 100644
--- a/contrib/python/pip/pip/_vendor/distlib/metadata.py
+++ b/contrib/python/pip/pip/_vendor/distlib/metadata.py
@@ -15,7 +15,6 @@ import json
import logging
import re
-
from . import DistlibException, __version__
from .compat import StringIO, string_types, text_type
from .markers import interpret
@@ -40,6 +39,7 @@ class MetadataUnrecognizedVersionError(DistlibException):
class MetadataInvalidError(DistlibException):
"""A metadata value is invalid"""
+
# public API of this module
__all__ = ['Metadata', 'PKG_INFO_ENCODING', 'PKG_INFO_PREFERRED_VERSION']
@@ -52,53 +52,38 @@ PKG_INFO_PREFERRED_VERSION = '1.1'
_LINE_PREFIX_1_2 = re.compile('\n \\|')
_LINE_PREFIX_PRE_1_2 = re.compile('\n ')
-_241_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform',
- 'Summary', 'Description',
- 'Keywords', 'Home-page', 'Author', 'Author-email',
- 'License')
-
-_314_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform',
- 'Supported-Platform', 'Summary', 'Description',
- 'Keywords', 'Home-page', 'Author', 'Author-email',
- 'License', 'Classifier', 'Download-URL', 'Obsoletes',
+_241_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', 'Summary', 'Description', 'Keywords', 'Home-page',
+ 'Author', 'Author-email', 'License')
+
+_314_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', 'Supported-Platform', 'Summary', 'Description',
+ 'Keywords', 'Home-page', 'Author', 'Author-email', 'License', 'Classifier', 'Download-URL', 'Obsoletes',
'Provides', 'Requires')
-_314_MARKERS = ('Obsoletes', 'Provides', 'Requires', 'Classifier',
- 'Download-URL')
+_314_MARKERS = ('Obsoletes', 'Provides', 'Requires', 'Classifier', 'Download-URL')
-_345_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform',
- 'Supported-Platform', 'Summary', 'Description',
- 'Keywords', 'Home-page', 'Author', 'Author-email',
- 'Maintainer', 'Maintainer-email', 'License',
- 'Classifier', 'Download-URL', 'Obsoletes-Dist',
- 'Project-URL', 'Provides-Dist', 'Requires-Dist',
+_345_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', 'Supported-Platform', 'Summary', 'Description',
+ 'Keywords', 'Home-page', 'Author', 'Author-email', 'Maintainer', 'Maintainer-email', 'License',
+ 'Classifier', 'Download-URL', 'Obsoletes-Dist', 'Project-URL', 'Provides-Dist', 'Requires-Dist',
'Requires-Python', 'Requires-External')
-_345_MARKERS = ('Provides-Dist', 'Requires-Dist', 'Requires-Python',
- 'Obsoletes-Dist', 'Requires-External', 'Maintainer',
- 'Maintainer-email', 'Project-URL')
+_345_MARKERS = ('Provides-Dist', 'Requires-Dist', 'Requires-Python', 'Obsoletes-Dist', 'Requires-External',
+ 'Maintainer', 'Maintainer-email', 'Project-URL')
-_426_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform',
- 'Supported-Platform', 'Summary', 'Description',
- 'Keywords', 'Home-page', 'Author', 'Author-email',
- 'Maintainer', 'Maintainer-email', 'License',
- 'Classifier', 'Download-URL', 'Obsoletes-Dist',
- 'Project-URL', 'Provides-Dist', 'Requires-Dist',
- 'Requires-Python', 'Requires-External', 'Private-Version',
- 'Obsoleted-By', 'Setup-Requires-Dist', 'Extension',
- 'Provides-Extra')
+_426_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', 'Supported-Platform', 'Summary', 'Description',
+ 'Keywords', 'Home-page', 'Author', 'Author-email', 'Maintainer', 'Maintainer-email', 'License',
+ 'Classifier', 'Download-URL', 'Obsoletes-Dist', 'Project-URL', 'Provides-Dist', 'Requires-Dist',
+ 'Requires-Python', 'Requires-External', 'Private-Version', 'Obsoleted-By', 'Setup-Requires-Dist',
+ 'Extension', 'Provides-Extra')
-_426_MARKERS = ('Private-Version', 'Provides-Extra', 'Obsoleted-By',
- 'Setup-Requires-Dist', 'Extension')
+_426_MARKERS = ('Private-Version', 'Provides-Extra', 'Obsoleted-By', 'Setup-Requires-Dist', 'Extension')
# See issue #106: Sometimes 'Requires' and 'Provides' occur wrongly in
# the metadata. Include them in the tuple literal below to allow them
# (for now).
# Ditto for Obsoletes - see issue #140.
-_566_FIELDS = _426_FIELDS + ('Description-Content-Type',
- 'Requires', 'Provides', 'Obsoletes')
+_566_FIELDS = _426_FIELDS + ('Description-Content-Type', 'Requires', 'Provides', 'Obsoletes')
-_566_MARKERS = ('Description-Content-Type',)
+_566_MARKERS = ('Description-Content-Type', )
_643_MARKERS = ('Dynamic', 'License-File')
@@ -135,6 +120,7 @@ def _version2fieldlist(version):
def _best_version(fields):
"""Detect the best version depending on the fields used."""
+
def _has_marker(keys, markers):
return any(marker in keys for marker in markers)
@@ -163,12 +149,12 @@ def _best_version(fields):
possible_versions.remove('2.2')
logger.debug('Removed 2.2 due to %s', key)
# if key not in _426_FIELDS and '2.0' in possible_versions:
- # possible_versions.remove('2.0')
- # logger.debug('Removed 2.0 due to %s', key)
+ # possible_versions.remove('2.0')
+ # logger.debug('Removed 2.0 due to %s', key)
# possible_version contains qualified versions
if len(possible_versions) == 1:
- return possible_versions[0] # found !
+ return possible_versions[0] # found !
elif len(possible_versions) == 0:
logger.debug('Out of options - unknown metadata set: %s', fields)
raise MetadataConflictError('Unknown metadata set')
@@ -199,28 +185,25 @@ def _best_version(fields):
if is_2_1:
return '2.1'
# if is_2_2:
- # return '2.2'
+ # return '2.2'
return '2.2'
+
# This follows the rules about transforming keys as described in
# https://www.python.org/dev/peps/pep-0566/#id17
-_ATTR2FIELD = {
- name.lower().replace("-", "_"): name for name in _ALL_FIELDS
-}
+_ATTR2FIELD = {name.lower().replace("-", "_"): name for name in _ALL_FIELDS}
_FIELD2ATTR = {field: attr for attr, field in _ATTR2FIELD.items()}
_PREDICATE_FIELDS = ('Requires-Dist', 'Obsoletes-Dist', 'Provides-Dist')
-_VERSIONS_FIELDS = ('Requires-Python',)
-_VERSION_FIELDS = ('Version',)
-_LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes',
- 'Requires', 'Provides', 'Obsoletes-Dist',
- 'Provides-Dist', 'Requires-Dist', 'Requires-External',
- 'Project-URL', 'Supported-Platform', 'Setup-Requires-Dist',
+_VERSIONS_FIELDS = ('Requires-Python', )
+_VERSION_FIELDS = ('Version', )
+_LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes', 'Requires', 'Provides', 'Obsoletes-Dist', 'Provides-Dist',
+ 'Requires-Dist', 'Requires-External', 'Project-URL', 'Supported-Platform', 'Setup-Requires-Dist',
'Provides-Extra', 'Extension', 'License-File')
-_LISTTUPLEFIELDS = ('Project-URL',)
+_LISTTUPLEFIELDS = ('Project-URL', )
-_ELEMENTSFIELD = ('Keywords',)
+_ELEMENTSFIELD = ('Keywords', )
_UNICODEFIELDS = ('Author', 'Maintainer', 'Summary', 'Description')
@@ -252,10 +235,10 @@ class LegacyMetadata(object):
- *mapping* is a dict-like object
- *scheme* is a version scheme name
"""
+
# TODO document the mapping API and UNKNOWN default key
- def __init__(self, path=None, fileobj=None, mapping=None,
- scheme='default'):
+ def __init__(self, path=None, fileobj=None, mapping=None, scheme='default'):
if [path, fileobj, mapping].count(None) < 2:
raise TypeError('path, fileobj and mapping are exclusive')
self._fields = {}
@@ -290,8 +273,7 @@ class LegacyMetadata(object):
raise KeyError(name)
def __contains__(self, name):
- return (name in self._fields or
- self._convert_name(name) in self._fields)
+ return (name in self._fields or self._convert_name(name) in self._fields)
def _convert_name(self, name):
if name in _ALL_FIELDS:
@@ -319,12 +301,12 @@ class LegacyMetadata(object):
# Public API
#
-# dependencies = property(_get_dependencies, _set_dependencies)
-
def get_fullname(self, filesafe=False):
- """Return the distribution name with version.
+ """
+ Return the distribution name with version.
- If filesafe is true, return a filename-escaped form."""
+ If filesafe is true, return a filename-escaped form.
+ """
return _get_name_and_version(self['Name'], self['Version'], filesafe)
def is_field(self, name):
@@ -415,6 +397,7 @@ class LegacyMetadata(object):
Keys that don't match a metadata field or that have an empty value are
dropped.
"""
+
def _set(key, value):
if key in _ATTR2FIELD and value:
self.set(self._convert_name(key), value)
@@ -437,14 +420,12 @@ class LegacyMetadata(object):
"""Control then set a metadata field."""
name = self._convert_name(name)
- if ((name in _ELEMENTSFIELD or name == 'Platform') and
- not isinstance(value, (list, tuple))):
+ if ((name in _ELEMENTSFIELD or name == 'Platform') and not isinstance(value, (list, tuple))):
if isinstance(value, string_types):
value = [v.strip() for v in value.split(',')]
else:
value = []
- elif (name in _LISTFIELDS and
- not isinstance(value, (list, tuple))):
+ elif (name in _LISTFIELDS and not isinstance(value, (list, tuple))):
if isinstance(value, string_types):
value = [value]
else:
@@ -458,18 +439,14 @@ class LegacyMetadata(object):
for v in value:
# check that the values are valid
if not scheme.is_valid_matcher(v.split(';')[0]):
- logger.warning(
- "'%s': '%s' is not valid (field '%s')",
- project_name, v, name)
+ logger.warning("'%s': '%s' is not valid (field '%s')", project_name, v, name)
# FIXME this rejects UNKNOWN, is that right?
elif name in _VERSIONS_FIELDS and value is not None:
if not scheme.is_valid_constraint_list(value):
- logger.warning("'%s': '%s' is not a valid version (field '%s')",
- project_name, value, name)
+ logger.warning("'%s': '%s' is not a valid version (field '%s')", project_name, value, name)
elif name in _VERSION_FIELDS and value is not None:
if not scheme.is_valid_version(value):
- logger.warning("'%s': '%s' is not a valid version (field '%s')",
- project_name, value, name)
+ logger.warning("'%s': '%s' is not a valid version (field '%s')", project_name, value, name)
if name in _UNICODEFIELDS:
if name == 'Description':
@@ -539,10 +516,8 @@ class LegacyMetadata(object):
return True
for fields, controller in ((_PREDICATE_FIELDS, are_valid_constraints),
- (_VERSIONS_FIELDS,
- scheme.is_valid_constraint_list),
- (_VERSION_FIELDS,
- scheme.is_valid_version)):
+ (_VERSIONS_FIELDS, scheme.is_valid_constraint_list), (_VERSION_FIELDS,
+ scheme.is_valid_version)):
for field in fields:
value = self.get(field, None)
if value is not None and not controller(value):
@@ -598,8 +573,7 @@ class LegacyMetadata(object):
return [(key, self[key]) for key in self.keys()]
def __repr__(self):
- return '<%s %s %s>' % (self.__class__.__name__, self.name,
- self.version)
+ return '<%s %s %s>' % (self.__class__.__name__, self.name, self.version)
METADATA_FILENAME = 'pydist.json'
@@ -631,7 +605,7 @@ class Metadata(object):
MANDATORY_KEYS = {
'name': (),
'version': (),
- 'summary': ('legacy',),
+ 'summary': ('legacy', ),
}
INDEX_KEYS = ('name version license summary description author '
@@ -644,22 +618,21 @@ class Metadata(object):
SYNTAX_VALIDATORS = {
'metadata_version': (METADATA_VERSION_MATCHER, ()),
- 'name': (NAME_MATCHER, ('legacy',)),
- 'version': (VERSION_MATCHER, ('legacy',)),
- 'summary': (SUMMARY_MATCHER, ('legacy',)),
- 'dynamic': (FIELDNAME_MATCHER, ('legacy',)),
+ 'name': (NAME_MATCHER, ('legacy', )),
+ 'version': (VERSION_MATCHER, ('legacy', )),
+ 'summary': (SUMMARY_MATCHER, ('legacy', )),
+ 'dynamic': (FIELDNAME_MATCHER, ('legacy', )),
}
__slots__ = ('_legacy', '_data', 'scheme')
- def __init__(self, path=None, fileobj=None, mapping=None,
- scheme='default'):
+ def __init__(self, path=None, fileobj=None, mapping=None, scheme='default'):
if [path, fileobj, mapping].count(None) < 2:
raise TypeError('path, fileobj and mapping are exclusive')
self._legacy = None
self._data = None
self.scheme = scheme
- #import pdb; pdb.set_trace()
+ # import pdb; pdb.set_trace()
if mapping is not None:
try:
self._validate_mapping(mapping, scheme)
@@ -693,8 +666,7 @@ class Metadata(object):
# The ValueError comes from the json.load - if that
# succeeds and we get a validation error, we want
# that to propagate
- self._legacy = LegacyMetadata(fileobj=StringIO(data),
- scheme=scheme)
+ self._legacy = LegacyMetadata(fileobj=StringIO(data), scheme=scheme)
self.validate()
common_keys = set(('name', 'version', 'license', 'keywords', 'summary'))
@@ -732,8 +704,7 @@ class Metadata(object):
result = self._legacy.get(lk)
else:
value = None if maker is None else maker()
- if key not in ('commands', 'exports', 'modules', 'namespaces',
- 'classifiers'):
+ if key not in ('commands', 'exports', 'modules', 'namespaces', 'classifiers'):
result = self._data.get(key, value)
else:
# special cases for PEP 459
@@ -770,8 +741,7 @@ class Metadata(object):
m = pattern.match(value)
if not m:
raise MetadataInvalidError("'%s' is an invalid value for "
- "the '%s' property" % (value,
- key))
+ "the '%s' property" % (value, key))
def __setattr__(self, key, value):
self._validate_value(key, value)
@@ -783,8 +753,7 @@ class Metadata(object):
if lk is None:
raise NotImplementedError
self._legacy[lk] = value
- elif key not in ('commands', 'exports', 'modules', 'namespaces',
- 'classifiers'):
+ elif key not in ('commands', 'exports', 'modules', 'namespaces', 'classifiers'):
self._data[key] = value
else:
# special cases for PEP 459
@@ -872,8 +841,7 @@ class Metadata(object):
# A recursive call, but it should terminate since 'test'
# has been removed from the extras
reqts = self._data.get('%s_requires' % key, [])
- result.extend(self.get_requirements(reqts, extras=extras,
- env=env))
+ result.extend(self.get_requirements(reqts, extras=extras, env=env))
return result
@property
@@ -914,8 +882,7 @@ class Metadata(object):
if self._legacy:
missing, warnings = self._legacy.check(True)
if missing or warnings:
- logger.warning('Metadata: missing: %s, warnings: %s',
- missing, warnings)
+ logger.warning('Metadata: missing: %s, warnings: %s', missing, warnings)
else:
self._validate_mapping(self._data, self.scheme)
@@ -932,9 +899,8 @@ class Metadata(object):
'metadata_version': self.METADATA_VERSION,
'generator': self.GENERATOR,
}
- lmd = self._legacy.todict(True) # skip missing ones
- for k in ('name', 'version', 'license', 'summary', 'description',
- 'classifier'):
+ lmd = self._legacy.todict(True) # skip missing ones
+ for k in ('name', 'version', 'license', 'summary', 'description', 'classifier'):
if k in lmd:
if k == 'classifier':
nk = 'classifiers'
@@ -945,14 +911,13 @@ class Metadata(object):
if kw == ['']:
kw = []
result['keywords'] = kw
- keys = (('requires_dist', 'run_requires'),
- ('setup_requires_dist', 'build_requires'))
+ keys = (('requires_dist', 'run_requires'), ('setup_requires_dist', 'build_requires'))
for ok, nk in keys:
if ok in lmd and lmd[ok]:
result[nk] = [{'requires': lmd[ok]}]
result['provides'] = self.provides
- author = {}
- maintainer = {}
+ # author = {}
+ # maintainer = {}
return result
LEGACY_MAPPING = {
@@ -969,6 +934,7 @@ class Metadata(object):
}
def _to_legacy(self):
+
def process_entries(entries):
reqts = set()
for e in entries:
@@ -1037,12 +1003,10 @@ class Metadata(object):
else:
d = self._data
if fileobj:
- json.dump(d, fileobj, ensure_ascii=True, indent=2,
- sort_keys=True)
+ json.dump(d, fileobj, ensure_ascii=True, indent=2, sort_keys=True)
else:
with codecs.open(path, 'w', 'utf-8') as f:
- json.dump(d, f, ensure_ascii=True, indent=2,
- sort_keys=True)
+ json.dump(d, f, ensure_ascii=True, indent=2, sort_keys=True)
def add_requirements(self, requirements):
if self._legacy:
@@ -1055,7 +1019,7 @@ class Metadata(object):
always = entry
break
if always is None:
- always = { 'requires': requirements }
+ always = {'requires': requirements}
run_requires.insert(0, always)
else:
rset = set(always['requires']) | set(requirements)
@@ -1064,5 +1028,4 @@ class Metadata(object):
def __repr__(self):
name = self.name or '(no name)'
version = self.version or 'no version'
- return '<%s %s %s (%s)>' % (self.__class__.__name__,
- self.metadata_version, name, version)
+ return '<%s %s %s (%s)>' % (self.__class__.__name__, self.metadata_version, name, version)
diff --git a/contrib/python/pip/pip/_vendor/distlib/scripts.py b/contrib/python/pip/pip/_vendor/distlib/scripts.py
index e5681ff72e..b1fc705b7e 100644
--- a/contrib/python/pip/pip/_vendor/distlib/scripts.py
+++ b/contrib/python/pip/pip/_vendor/distlib/scripts.py
@@ -15,8 +15,7 @@ from zipfile import ZipInfo
from .compat import sysconfig, detect_encoding, ZipFile
from .resources import finder
-from .util import (FileOperator, get_export_entry, convert_path,
- get_executable, get_platform, in_venv)
+from .util import (FileOperator, get_export_entry, convert_path, get_executable, get_platform, in_venv)
logger = logging.getLogger(__name__)
@@ -57,12 +56,16 @@ if __name__ == '__main__':
# location where it was imported from. So we load everything into memory in
# advance.
-# Issue 31: don't hardcode an absolute package name, but
-# determine it relative to the current package
-distlib_package = __name__.rsplit('.', 1)[0]
+if os.name == 'nt' or (os.name == 'java' and os._name == 'nt'):
+ # Issue 31: don't hardcode an absolute package name, but
+ # determine it relative to the current package
+ DISTLIB_PACKAGE = __name__.rsplit('.', 1)[0]
-WRAPPERS = {
-}
+ WRAPPERS = {
+ r.name: r.bytes
+ for r in finder(DISTLIB_PACKAGE).iterator("")
+ if r.name.endswith(".exe")
+ }
def enquote_executable(executable):
@@ -94,25 +97,18 @@ class ScriptMaker(object):
executable = None # for shebangs
- def __init__(self,
- source_dir,
- target_dir,
- add_launchers=True,
- dry_run=False,
- fileop=None):
+ def __init__(self, source_dir, target_dir, add_launchers=True, dry_run=False, fileop=None):
self.source_dir = source_dir
self.target_dir = target_dir
self.add_launchers = add_launchers
self.force = False
self.clobber = False
# It only makes sense to set mode bits on POSIX.
- self.set_mode = (os.name == 'posix') or (os.name == 'java'
- and os._name == 'posix')
+ self.set_mode = (os.name == 'posix') or (os.name == 'java' and os._name == 'posix')
self.variants = set(('', 'X.Y'))
self._fileop = fileop or FileOperator(dry_run)
- self._is_nt = os.name == 'nt' or (os.name == 'java'
- and os._name == 'nt')
+ self._is_nt = os.name == 'nt' or (os.name == 'java' and os._name == 'nt')
self.version_info = sys.version_info
def _get_alternate_executable(self, executable, options):
@@ -161,6 +157,12 @@ class ScriptMaker(object):
"""
if os.name != 'posix':
simple_shebang = True
+ elif getattr(sys, "cross_compiling", False):
+ # In a cross-compiling environment, the shebang will likely be a
+ # script; this *must* be invoked with the "safe" version of the
+ # shebang, or else using os.exec() to run the entry script will
+ # fail, raising "OSError 8 [Errno 8] Exec format error".
+ simple_shebang = False
else:
# Add 3 for '#!' prefix and newline suffix.
shebang_length = len(executable) + len(post_interp) + 3
@@ -168,15 +170,14 @@ class ScriptMaker(object):
max_shebang_length = 512
else:
max_shebang_length = 127
- simple_shebang = ((b' ' not in executable)
- and (shebang_length <= max_shebang_length))
+ simple_shebang = ((b' ' not in executable) and (shebang_length <= max_shebang_length))
if simple_shebang:
result = b'#!' + executable + post_interp + b'\n'
else:
result = b'#!/bin/sh\n'
result += b"'''exec' " + executable + post_interp + b' "$0" "$@"\n'
- result += b"' '''"
+ result += b"' '''\n"
return result
def _get_shebang(self, encoding, post_interp=b'', options=None):
@@ -187,21 +188,17 @@ class ScriptMaker(object):
elif not sysconfig.is_python_build():
executable = get_executable()
elif in_venv(): # pragma: no cover
- executable = os.path.join(
- sysconfig.get_path('scripts'),
- 'python%s' % sysconfig.get_config_var('EXE'))
+ executable = os.path.join(sysconfig.get_path('scripts'), 'python%s' % sysconfig.get_config_var('EXE'))
else: # pragma: no cover
if os.name == 'nt':
# for Python builds from source on Windows, no Python executables with
# a version suffix are created, so we use python.exe
- executable = os.path.join(
- sysconfig.get_config_var('BINDIR'),
- 'python%s' % (sysconfig.get_config_var('EXE')))
+ executable = os.path.join(sysconfig.get_config_var('BINDIR'),
+ 'python%s' % (sysconfig.get_config_var('EXE')))
else:
executable = os.path.join(
sysconfig.get_config_var('BINDIR'),
- 'python%s%s' % (sysconfig.get_config_var('VERSION'),
- sysconfig.get_config_var('EXE')))
+ 'python%s%s' % (sysconfig.get_config_var('VERSION'), sysconfig.get_config_var('EXE')))
if options:
executable = self._get_alternate_executable(executable, options)
@@ -225,8 +222,8 @@ class ScriptMaker(object):
# check that the shebang is decodable using utf-8.
executable = executable.encode('utf-8')
# in case of IronPython, play safe and enable frames support
- if (sys.platform == 'cli' and '-X:Frames' not in post_interp
- and '-X:FullFrames' not in post_interp): # pragma: no cover
+ if (sys.platform == 'cli' and '-X:Frames' not in post_interp and
+ '-X:FullFrames' not in post_interp): # pragma: no cover
post_interp += b' -X:Frames'
shebang = self._build_shebang(executable, post_interp)
# Python parser starts to read a script using UTF-8 until
@@ -237,8 +234,7 @@ class ScriptMaker(object):
try:
shebang.decode('utf-8')
except UnicodeDecodeError: # pragma: no cover
- raise ValueError('The shebang (%r) is not decodable from utf-8' %
- shebang)
+ raise ValueError('The shebang (%r) is not decodable from utf-8' % shebang)
# If the script is encoded to a custom encoding (use a
# #coding:xxx cookie), the shebang has to be decodable from
# the script encoding too.
@@ -247,15 +243,12 @@ class ScriptMaker(object):
shebang.decode(encoding)
except UnicodeDecodeError: # pragma: no cover
raise ValueError('The shebang (%r) is not decodable '
- 'from the script encoding (%r)' %
- (shebang, encoding))
+ 'from the script encoding (%r)' % (shebang, encoding))
return shebang
def _get_script_text(self, entry):
return self.script_template % dict(
- module=entry.prefix,
- import_name=entry.suffix.split('.')[0],
- func=entry.suffix)
+ module=entry.prefix, import_name=entry.suffix.split('.')[0], func=entry.suffix)
manifest = _DEFAULT_MANIFEST
@@ -265,9 +258,6 @@ class ScriptMaker(object):
def _write_script(self, names, shebang, script_bytes, filenames, ext):
use_launcher = self.add_launchers and self._is_nt
- linesep = os.linesep.encode('utf-8')
- if not shebang.endswith(linesep):
- shebang += linesep
if not use_launcher:
script_bytes = shebang + script_bytes
else: # pragma: no cover
@@ -280,8 +270,7 @@ class ScriptMaker(object):
source_date_epoch = os.environ.get('SOURCE_DATE_EPOCH')
if source_date_epoch:
date_time = time.gmtime(int(source_date_epoch))[:6]
- zinfo = ZipInfo(filename='__main__.py',
- date_time=date_time)
+ zinfo = ZipInfo(filename='__main__.py', date_time=date_time)
zf.writestr(zinfo, script_bytes)
else:
zf.writestr('__main__.py', script_bytes)
@@ -312,8 +301,7 @@ class ScriptMaker(object):
except Exception:
pass # still in use - ignore error
else:
- if self._is_nt and not outname.endswith(
- '.' + ext): # pragma: no cover
+ if self._is_nt and not outname.endswith('.' + ext): # pragma: no cover
outname = '%s.%s' % (outname, ext)
if os.path.exists(outname) and not self.clobber:
logger.warning('Skipping existing file %s', outname)
@@ -332,9 +320,7 @@ class ScriptMaker(object):
if 'X' in self.variants:
result.add('%s%s' % (name, self.version_info[0]))
if 'X.Y' in self.variants:
- result.add('%s%s%s.%s' %
- (name, self.variant_separator, self.version_info[0],
- self.version_info[1]))
+ result.add('%s%s%s.%s' % (name, self.variant_separator, self.version_info[0], self.version_info[1]))
return result
def _make_script(self, entry, filenames, options=None):
@@ -389,8 +375,7 @@ class ScriptMaker(object):
self._fileop.set_executable_mode([outname])
filenames.append(outname)
else:
- logger.info('copying and adjusting %s -> %s', script,
- self.target_dir)
+ logger.info('copying and adjusting %s -> %s', script, self.target_dir)
if not self._fileop.dry_run:
encoding, lines = detect_encoding(f.readline)
f.seek(0)
@@ -412,8 +397,7 @@ class ScriptMaker(object):
def dry_run(self, value):
self._fileop.dry_run = value
- if os.name == 'nt' or (os.name == 'java'
- and os._name == 'nt'): # pragma: no cover
+ if os.name == 'nt' or (os.name == 'java' and os._name == 'nt'): # pragma: no cover
# Executable launcher support.
# Launchers are from https://bitbucket.org/vinay.sajip/simple_launcher/
@@ -426,7 +410,7 @@ class ScriptMaker(object):
name = '%s%s%s.exe' % (kind, bits, platform_suffix)
if name not in WRAPPERS:
msg = ('Unable to find resource %s in package %s' %
- (name, distlib_package))
+ (name, DISTLIB_PACKAGE))
raise ValueError(msg)
return WRAPPERS[name]
diff --git a/contrib/python/pip/pip/_vendor/distlib/util.py b/contrib/python/pip/pip/_vendor/distlib/util.py
index ba58858d0f..0d5bd7a8bf 100644
--- a/contrib/python/pip/pip/_vendor/distlib/util.py
+++ b/contrib/python/pip/pip/_vendor/distlib/util.py
@@ -31,11 +31,9 @@ except ImportError: # pragma: no cover
import time
from . import DistlibException
-from .compat import (string_types, text_type, shutil, raw_input, StringIO,
- cache_from_source, urlopen, urljoin, httplib, xmlrpclib,
- HTTPHandler, BaseConfigurator, valid_ident,
- Container, configparser, URLError, ZipFile, fsdecode,
- unquote, urlparse)
+from .compat import (string_types, text_type, shutil, raw_input, StringIO, cache_from_source, urlopen, urljoin, httplib,
+ xmlrpclib, HTTPHandler, BaseConfigurator, valid_ident, Container, configparser, URLError, ZipFile,
+ fsdecode, unquote, urlparse)
logger = logging.getLogger(__name__)
@@ -88,8 +86,7 @@ def parse_marker(marker_string):
else:
m = STRING_CHUNK.match(remaining)
if not m:
- raise SyntaxError('error in string literal: %s' %
- remaining)
+ raise SyntaxError('error in string literal: %s' % remaining)
parts.append(m.groups()[0])
remaining = remaining[m.end():]
else:
@@ -210,8 +207,7 @@ def parse_requirement(req):
ver_remaining = ver_remaining[m.end():]
m = VERSION_IDENTIFIER.match(ver_remaining)
if not m:
- raise SyntaxError('invalid version: %s' %
- ver_remaining)
+ raise SyntaxError('invalid version: %s' % ver_remaining)
v = m.groups()[0]
versions.append((op, v))
ver_remaining = ver_remaining[m.end():]
@@ -224,8 +220,7 @@ def parse_requirement(req):
break
m = COMPARE_OP.match(ver_remaining)
if not m:
- raise SyntaxError('invalid constraint: %s' %
- ver_remaining)
+ raise SyntaxError('invalid constraint: %s' % ver_remaining)
if not versions:
versions = None
return versions, ver_remaining
@@ -235,8 +230,7 @@ def parse_requirement(req):
else:
i = remaining.find(')', 1)
if i < 0:
- raise SyntaxError('unterminated parenthesis: %s' %
- remaining)
+ raise SyntaxError('unterminated parenthesis: %s' % remaining)
s = remaining[1:i]
remaining = remaining[i + 1:].lstrip()
# As a special diversion from PEP 508, allow a version number
@@ -267,14 +261,8 @@ def parse_requirement(req):
if not versions:
rs = distname
else:
- rs = '%s %s' % (distname, ', '.join(
- ['%s %s' % con for con in versions]))
- return Container(name=distname,
- extras=extras,
- constraints=versions,
- marker=mark_expr,
- url=uri,
- requirement=rs)
+ rs = '%s %s' % (distname, ', '.join(['%s %s' % con for con in versions]))
+ return Container(name=distname, extras=extras, constraints=versions, marker=mark_expr, url=uri, requirement=rs)
def get_resources_dests(resources_root, rules):
@@ -524,8 +512,7 @@ class FileOperator(object):
second will have the same "age".
"""
if not os.path.exists(source):
- raise DistlibException("file '%r' does not exist" %
- os.path.abspath(source))
+ raise DistlibException("file '%r' does not exist" % os.path.abspath(source))
if not os.path.exists(target):
return True
@@ -601,12 +588,7 @@ class FileOperator(object):
if self.record:
self.dirs_created.add(path)
- def byte_compile(self,
- path,
- optimize=False,
- force=False,
- prefix=None,
- hashed_invalidation=False):
+ def byte_compile(self, path, optimize=False, force=False, prefix=None, hashed_invalidation=False):
dpath = cache_from_source(path, not optimize)
logger.info('Byte-compiling %s to %s', path, dpath)
if not self.dry_run:
@@ -617,12 +599,11 @@ class FileOperator(object):
assert path.startswith(prefix)
diagpath = path[len(prefix):]
compile_kwargs = {}
- if hashed_invalidation and hasattr(py_compile,
- 'PycInvalidationMode'):
- compile_kwargs[
- 'invalidation_mode'] = py_compile.PycInvalidationMode.CHECKED_HASH
- py_compile.compile(path, dpath, diagpath, True,
- **compile_kwargs) # raise error
+ if hashed_invalidation and hasattr(py_compile, 'PycInvalidationMode'):
+ if not isinstance(hashed_invalidation, py_compile.PycInvalidationMode):
+ hashed_invalidation = py_compile.PycInvalidationMode.CHECKED_HASH
+ compile_kwargs['invalidation_mode'] = hashed_invalidation
+ py_compile.compile(path, dpath, diagpath, True, **compile_kwargs) # raise error
self.record_as_written(dpath)
return dpath
@@ -716,16 +697,14 @@ class ExportEntry(object):
return resolve(self.prefix, self.suffix)
def __repr__(self): # pragma: no cover
- return '<ExportEntry %s = %s:%s %s>' % (self.name, self.prefix,
- self.suffix, self.flags)
+ return '<ExportEntry %s = %s:%s %s>' % (self.name, self.prefix, self.suffix, self.flags)
def __eq__(self, other):
if not isinstance(other, ExportEntry):
result = False
else:
- result = (self.name == other.name and self.prefix == other.prefix
- and self.suffix == other.suffix
- and self.flags == other.flags)
+ result = (self.name == other.name and self.prefix == other.prefix and self.suffix == other.suffix and
+ self.flags == other.flags)
return result
__hash__ = object.__hash__
@@ -810,7 +789,7 @@ def get_cache_base(suffix=None):
return os.path.join(result, suffix)
-def path_to_cache_dir(path):
+def path_to_cache_dir(path, use_abspath=True):
"""
Convert an absolute path to a directory name for use in a cache.
@@ -820,7 +799,7 @@ def path_to_cache_dir(path):
#. Any occurrence of ``os.sep`` is replaced with ``'--'``.
#. ``'.cache'`` is appended.
"""
- d, p = os.path.splitdrive(os.path.abspath(path))
+ d, p = os.path.splitdrive(os.path.abspath(path) if use_abspath else path)
if d:
d = d.replace(':', '---')
p = p.replace(os.sep, '--')
@@ -865,9 +844,8 @@ def is_string_sequence(seq):
return result
-PROJECT_NAME_AND_VERSION = re.compile(
- '([a-z0-9_]+([.-][a-z_][a-z0-9_]*)*)-'
- '([a-z0-9_.+-]+)', re.I)
+PROJECT_NAME_AND_VERSION = re.compile('([a-z0-9_]+([.-][a-z_][a-z0-9_]*)*)-'
+ '([a-z0-9_.+-]+)', re.I)
PYTHON_VERSION = re.compile(r'-py(\d\.?\d?)')
@@ -1003,11 +981,11 @@ class Cache(object):
logger.warning('Directory \'%s\' is not private', base)
self.base = os.path.abspath(os.path.normpath(base))
- def prefix_to_dir(self, prefix):
+ def prefix_to_dir(self, prefix, use_abspath=True):
"""
Converts a resource prefix to a directory name in the cache.
"""
- return path_to_cache_dir(prefix)
+ return path_to_cache_dir(prefix, use_abspath=use_abspath)
def clear(self):
"""
@@ -1092,8 +1070,7 @@ class EventMixin(object):
logger.exception('Exception during event publication')
value = None
result.append(value)
- logger.debug('publish %s: args = %s, kwargs = %s, result = %s', event,
- args, kwargs, result)
+ logger.debug('publish %s: args = %s, kwargs = %s, result = %s', event, args, kwargs, result)
return result
@@ -1145,8 +1122,7 @@ class Sequencer(object):
raise ValueError('%r not a successor of %r' % (succ, pred))
def is_step(self, step):
- return (step in self._preds or step in self._succs
- or step in self._nodes)
+ return (step in self._preds or step in self._succs or step in self._nodes)
def get_steps(self, final):
if not self.is_step(final):
@@ -1242,8 +1218,7 @@ class Sequencer(object):
# Unarchiving functionality for zip, tar, tgz, tbz, whl
#
-ARCHIVE_EXTENSIONS = ('.tar.gz', '.tar.bz2', '.tar', '.zip', '.tgz', '.tbz',
- '.whl')
+ARCHIVE_EXTENSIONS = ('.tar.gz', '.tar.bz2', '.tar', '.zip', '.tgz', '.tbz', '.whl')
def unarchive(archive_filename, dest_dir, format=None, check=True):
@@ -1474,8 +1449,7 @@ def _iglob(path_glob):
if ssl:
- from .compat import (HTTPSHandler as BaseHTTPSHandler, match_hostname,
- CertificateError)
+ from .compat import (HTTPSHandler as BaseHTTPSHandler, match_hostname, CertificateError)
#
# HTTPSConnection which verifies certificates/matches domains
@@ -1487,8 +1461,7 @@ if ssl:
# noinspection PyPropertyAccess
def connect(self):
- sock = socket.create_connection((self.host, self.port),
- self.timeout)
+ sock = socket.create_connection((self.host, self.port), self.timeout)
if getattr(self, '_tunnel_host', False):
self.sock = sock
self._tunnel()
@@ -1543,9 +1516,8 @@ if ssl:
return self.do_open(self._conn_maker, req)
except URLError as e:
if 'certificate verify failed' in str(e.reason):
- raise CertificateError(
- 'Unable to verify server certificate '
- 'for %s' % req.host)
+ raise CertificateError('Unable to verify server certificate '
+ 'for %s' % req.host)
else:
raise
@@ -1561,9 +1533,8 @@ if ssl:
class HTTPSOnlyHandler(HTTPSHandler, HTTPHandler):
def http_open(self, req):
- raise URLError(
- 'Unexpected HTTP request on what should be a secure '
- 'connection: %s' % req)
+ raise URLError('Unexpected HTTP request on what should be a secure '
+ 'connection: %s' % req)
#
@@ -1598,8 +1569,7 @@ if ssl:
kwargs['timeout'] = self.timeout
if not self._connection or host != self._connection[0]:
self._extra_headers = eh
- self._connection = host, httplib.HTTPSConnection(
- h, None, **kwargs)
+ self._connection = host, httplib.HTTPSConnection(h, None, **kwargs)
return self._connection[1]
@@ -1789,10 +1759,7 @@ class SubprocessMixin(object):
stream.close()
def run_command(self, cmd, **kwargs):
- p = subprocess.Popen(cmd,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- **kwargs)
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
t1 = threading.Thread(target=self.reader, args=(p.stdout, 'stdout'))
t1.start()
t2 = threading.Thread(target=self.reader, args=(p.stderr, 'stderr'))
@@ -1847,10 +1814,7 @@ class PyPIRCFile(object):
if 'distutils' in sections:
# let's get the list of servers
index_servers = config.get('distutils', 'index-servers')
- _servers = [
- server.strip() for server in index_servers.split('\n')
- if server.strip() != ''
- ]
+ _servers = [server.strip() for server in index_servers.split('\n') if server.strip() != '']
if _servers == []:
# nothing set, let's try to get the default pypi
if 'pypi' in sections:
@@ -1861,9 +1825,7 @@ class PyPIRCFile(object):
result['username'] = config.get(server, 'username')
# optional params
- for key, default in (('repository',
- self.DEFAULT_REPOSITORY),
- ('realm', self.DEFAULT_REALM),
+ for key, default in (('repository', self.DEFAULT_REPOSITORY), ('realm', self.DEFAULT_REALM),
('password', None)):
if config.has_option(server, key):
result[key] = config.get(server, key)
@@ -1873,11 +1835,9 @@ class PyPIRCFile(object):
# work around people having "repository" for the "pypi"
# section of their config set to the HTTP (rather than
# HTTPS) URL
- if (server == 'pypi' and repository
- in (self.DEFAULT_REPOSITORY, 'pypi')):
+ if (server == 'pypi' and repository in (self.DEFAULT_REPOSITORY, 'pypi')):
result['repository'] = self.DEFAULT_REPOSITORY
- elif (result['server'] != repository
- and result['repository'] != repository):
+ elif (result['server'] != repository and result['repository'] != repository):
result = {}
elif 'server-login' in sections:
# old format
@@ -2003,8 +1963,7 @@ def get_host_platform():
from distutils import sysconfig
except ImportError:
import sysconfig
- osname, release, machine = _osx_support.get_platform_osx(
- sysconfig.get_config_vars(), osname, release, machine)
+ osname, release, machine = _osx_support.get_platform_osx(sysconfig.get_config_vars(), osname, release, machine)
return '%s-%s-%s' % (osname, release, machine)
diff --git a/contrib/python/pip/pip/_vendor/distlib/version.py b/contrib/python/pip/pip/_vendor/distlib/version.py
index 14171ac938..d70a96ef51 100644
--- a/contrib/python/pip/pip/_vendor/distlib/version.py
+++ b/contrib/python/pip/pip/_vendor/distlib/version.py
@@ -619,8 +619,7 @@ class LegacyVersion(Version):
def is_prerelease(self):
result = False
for x in self._parts:
- if (isinstance(x, string_types) and x.startswith('*') and
- x < '*final'):
+ if (isinstance(x, string_types) and x.startswith('*') and x < '*final'):
result = True
break
return result
diff --git a/contrib/python/pip/pip/_vendor/distlib/wheel.py b/contrib/python/pip/pip/_vendor/distlib/wheel.py
index 4a5a30e1d8..62ab10fb3a 100644
--- a/contrib/python/pip/pip/_vendor/distlib/wheel.py
+++ b/contrib/python/pip/pip/_vendor/distlib/wheel.py
@@ -25,9 +25,8 @@ from . import __version__, DistlibException
from .compat import sysconfig, ZipFile, fsdecode, text_type, filter
from .database import InstalledDistribution
from .metadata import Metadata, WHEEL_METADATA_FILENAME, LEGACY_METADATA_FILENAME
-from .util import (FileOperator, convert_path, CSVReader, CSVWriter, Cache,
- cached_property, get_cache_base, read_exports, tempdir,
- get_platform)
+from .util import (FileOperator, convert_path, CSVReader, CSVWriter, Cache, cached_property, get_cache_base,
+ read_exports, tempdir, get_platform)
from .version import NormalizedVersion, UnsupportedVersionError
logger = logging.getLogger(__name__)
@@ -88,8 +87,7 @@ FILENAME_RE = re.compile(
\.whl$
''', re.IGNORECASE | re.VERBOSE)
-NAME_VERSION_RE = re.compile(
- r'''
+NAME_VERSION_RE = re.compile(r'''
(?P<nm>[^-]+)
-(?P<vn>\d+[^-]*)
(-(?P<bn>\d+[^-]*))?$
@@ -235,8 +233,7 @@ class Wheel(object):
arch = '.'.join(self.arch)
# replace - with _ as a local version separator
version = self.version.replace('-', '_')
- return '%s-%s%s-%s-%s-%s.whl' % (self.name, version, buildver, pyver,
- abi, arch)
+ return '%s-%s%s-%s-%s-%s.whl' % (self.name, version, buildver, pyver, abi, arch)
@property
def exists(self):
@@ -334,8 +331,7 @@ class Wheel(object):
try:
hasher = getattr(hashlib, hash_kind)
except AttributeError:
- raise DistlibException('Unsupported hash algorithm: %r' %
- hash_kind)
+ raise DistlibException('Unsupported hash algorithm: %r' % hash_kind)
result = hasher(data).digest()
result = base64.urlsafe_b64encode(result).rstrip(b'=').decode('ascii')
return hash_kind, result
@@ -513,7 +509,7 @@ class Wheel(object):
installed, and the headers, scripts, data and dist-info metadata are
not written. If kwarg ``bytecode_hashed_invalidation`` is True, written
bytecode will try to use file-hash based invalidation (PEP-552) on
- supported interpreter versions (CPython 2.7+).
+ supported interpreter versions (CPython 3.7+).
The return value is a :class:`InstalledDistribution` instance unless
``options.lib_only`` is True, in which case the return value is ``None``.
@@ -522,8 +518,7 @@ class Wheel(object):
dry_run = maker.dry_run
warner = kwargs.get('warner')
lib_only = kwargs.get('lib_only', False)
- bc_hashed_invalidation = kwargs.get('bytecode_hashed_invalidation',
- False)
+ bc_hashed_invalidation = kwargs.get('bytecode_hashed_invalidation', False)
pathname = os.path.join(self.dirname, self.filename)
name_ver = '%s-%s' % (self.name, self.version)
@@ -602,8 +597,7 @@ class Wheel(object):
if lib_only and u_arcname.startswith((info_pfx, data_pfx)):
logger.debug('lib_only: skipping %s', u_arcname)
continue
- is_script = (u_arcname.startswith(script_pfx)
- and not u_arcname.endswith('.exe'))
+ is_script = (u_arcname.startswith(script_pfx) and not u_arcname.endswith('.exe'))
if u_arcname.startswith(data_pfx):
_, where, rp = u_arcname.split('/', 2)
@@ -622,8 +616,7 @@ class Wheel(object):
# So ... manually preserve permission bits as given in zinfo
if os.name == 'posix':
# just set the normal permission bits
- os.chmod(outfile,
- (zinfo.external_attr >> 16) & 0x1FF)
+ os.chmod(outfile, (zinfo.external_attr >> 16) & 0x1FF)
outfiles.append(outfile)
# Double check the digest of the written file
if not dry_run and row[1]:
@@ -636,15 +629,12 @@ class Wheel(object):
'%s' % outfile)
if bc and outfile.endswith('.py'):
try:
- pyc = fileop.byte_compile(
- outfile,
- hashed_invalidation=bc_hashed_invalidation)
+ pyc = fileop.byte_compile(outfile, hashed_invalidation=bc_hashed_invalidation)
outfiles.append(pyc)
except Exception:
# Don't give up if byte-compilation fails,
# but log it and perhaps warn the user
- logger.warning('Byte-compilation failed',
- exc_info=True)
+ logger.warning('Byte-compilation failed', exc_info=True)
else:
fn = os.path.basename(convert_path(arcname))
workname = os.path.join(workdir, fn)
@@ -732,8 +722,7 @@ class Wheel(object):
outfiles.append(p)
# Write RECORD
- dist.write_installed_files(outfiles, paths['prefix'],
- dry_run)
+ dist.write_installed_files(outfiles, paths['prefix'], dry_run)
return dist
except Exception: # pragma: no cover
logger.exception('installation failed.')
@@ -746,8 +735,7 @@ class Wheel(object):
global cache
if cache is None:
# Use native string to avoid issues on 2.x: see Python #20140.
- base = os.path.join(get_cache_base(), str('dylib-cache'),
- '%s.%s' % sys.version_info[:2])
+ base = os.path.join(get_cache_base(), str('dylib-cache'), '%s.%s' % sys.version_info[:2])
cache = Cache(base)
return cache
@@ -764,7 +752,7 @@ class Wheel(object):
wf = wrapper(bf)
extensions = json.load(wf)
cache = self._get_dylib_cache()
- prefix = cache.prefix_to_dir(pathname)
+ prefix = cache.prefix_to_dir(self.filename, use_abspath=False)
cache_base = os.path.join(cache.base, prefix)
if not os.path.isdir(cache_base):
os.makedirs(cache_base)
@@ -774,8 +762,7 @@ class Wheel(object):
extract = True
else:
file_time = os.stat(dest).st_mtime
- file_time = datetime.datetime.fromtimestamp(
- file_time)
+ file_time = datetime.datetime.fromtimestamp(file_time)
info = zf.getinfo(relpath)
wheel_time = datetime.datetime(*info.date_time)
extract = wheel_time > file_time
@@ -924,12 +911,10 @@ class Wheel(object):
else:
parts = [int(s) for s in version[i + 1:].split('.')]
parts[-1] += 1
- updated = '%s+%s' % (version[:i], '.'.join(
- str(i) for i in parts))
+ updated = '%s+%s' % (version[:i], '.'.join(str(i) for i in parts))
except UnsupportedVersionError:
- logger.debug(
- 'Cannot update non-compliant (PEP-440) '
- 'version %r', version)
+ logger.debug('Cannot update non-compliant (PEP-440) '
+ 'version %r', version)
if updated:
md = Metadata(path=path)
md.version = updated
@@ -971,14 +956,11 @@ class Wheel(object):
update_version(current_version, path)
# Decide where the new wheel goes.
if dest_dir is None:
- fd, newpath = tempfile.mkstemp(suffix='.whl',
- prefix='wheel-update-',
- dir=workdir)
+ fd, newpath = tempfile.mkstemp(suffix='.whl', prefix='wheel-update-', dir=workdir)
os.close(fd)
else:
if not os.path.isdir(dest_dir):
- raise DistlibException('Not a directory: %r' %
- dest_dir)
+ raise DistlibException('Not a directory: %r' % dest_dir)
newpath = os.path.join(dest_dir, self.filename)
archive_paths = list(path_map.items())
distinfo = os.path.join(workdir, info_dir)
@@ -1005,11 +987,20 @@ def compatible_tags():
"""
Return (pyver, abi, arch) tuples compatible with this Python.
"""
- versions = [VER_SUFFIX]
- major = VER_SUFFIX[0]
- for minor in range(sys.version_info[1] - 1, -1, -1):
- versions.append(''.join([major, str(minor)]))
+ class _Version:
+ def __init__(self, major, minor):
+ self.major = major
+ self.major_minor = (major, minor)
+ self.string = ''.join((str(major), str(minor)))
+
+ def __str__(self):
+ return self.string
+
+ versions = [
+ _Version(sys.version_info.major, minor_version)
+ for minor_version in range(sys.version_info.minor, -1, -1)
+ ]
abis = []
for suffix in _get_suffixes():
if suffix.startswith('.abi'):
@@ -1045,35 +1036,45 @@ def compatible_tags():
minor -= 1
# Most specific - our Python version, ABI and arch
- for abi in abis:
- for arch in arches:
- result.append((''.join((IMP_PREFIX, versions[0])), abi, arch))
- # manylinux
- if abi != 'none' and sys.platform.startswith('linux'):
- arch = arch.replace('linux_', '')
- parts = _get_glibc_version()
- if len(parts) == 2:
- if parts >= (2, 5):
- result.append((''.join((IMP_PREFIX, versions[0])), abi,
- 'manylinux1_%s' % arch))
- if parts >= (2, 12):
- result.append((''.join((IMP_PREFIX, versions[0])), abi,
- 'manylinux2010_%s' % arch))
- if parts >= (2, 17):
- result.append((''.join((IMP_PREFIX, versions[0])), abi,
- 'manylinux2014_%s' % arch))
- result.append(
- (''.join((IMP_PREFIX, versions[0])), abi,
- 'manylinux_%s_%s_%s' % (parts[0], parts[1], arch)))
+ for i, version_object in enumerate(versions):
+ version = str(version_object)
+ add_abis = []
+
+ if i == 0:
+ add_abis = abis
+
+ if IMP_PREFIX == 'cp' and version_object.major_minor >= (3, 2):
+ limited_api_abi = 'abi' + str(version_object.major)
+ if limited_api_abi not in add_abis:
+ add_abis.append(limited_api_abi)
+
+ for abi in add_abis:
+ for arch in arches:
+ result.append((''.join((IMP_PREFIX, version)), abi, arch))
+ # manylinux
+ if abi != 'none' and sys.platform.startswith('linux'):
+ arch = arch.replace('linux_', '')
+ parts = _get_glibc_version()
+ if len(parts) == 2:
+ if parts >= (2, 5):
+ result.append((''.join((IMP_PREFIX, version)), abi, 'manylinux1_%s' % arch))
+ if parts >= (2, 12):
+ result.append((''.join((IMP_PREFIX, version)), abi, 'manylinux2010_%s' % arch))
+ if parts >= (2, 17):
+ result.append((''.join((IMP_PREFIX, version)), abi, 'manylinux2014_%s' % arch))
+ result.append((''.join(
+ (IMP_PREFIX, version)), abi, 'manylinux_%s_%s_%s' % (parts[0], parts[1], arch)))
# where no ABI / arch dependency, but IMP_PREFIX dependency
- for i, version in enumerate(versions):
+ for i, version_object in enumerate(versions):
+ version = str(version_object)
result.append((''.join((IMP_PREFIX, version)), 'none', 'any'))
if i == 0:
result.append((''.join((IMP_PREFIX, version[0])), 'none', 'any'))
# no IMP_PREFIX, ABI or arch dependency
- for i, version in enumerate(versions):
+ for i, version_object in enumerate(versions):
+ version = str(version_object)
result.append((''.join(('py', version)), 'none', 'any'))
if i == 0:
result.append((''.join(('py', version[0])), 'none', 'any'))
diff --git a/contrib/python/pip/pip/_vendor/packaging/tags.py b/contrib/python/pip/pip/_vendor/packaging/tags.py
index 6667d29908..703f0ed53c 100644
--- a/contrib/python/pip/pip/_vendor/packaging/tags.py
+++ b/contrib/python/pip/pip/_vendor/packaging/tags.py
@@ -25,7 +25,7 @@ from . import _manylinux, _musllinux
logger = logging.getLogger(__name__)
PythonVersion = Sequence[int]
-MacVersion = Tuple[int, int]
+AppleVersion = Tuple[int, int]
INTERPRETER_SHORT_NAMES: dict[str, str] = {
"python": "py", # Generic.
@@ -363,7 +363,7 @@ def _mac_arch(arch: str, is_32bit: bool = _32_BIT_INTERPRETER) -> str:
return "i386"
-def _mac_binary_formats(version: MacVersion, cpu_arch: str) -> list[str]:
+def _mac_binary_formats(version: AppleVersion, cpu_arch: str) -> list[str]:
formats = [cpu_arch]
if cpu_arch == "x86_64":
if version < (10, 4):
@@ -396,7 +396,7 @@ def _mac_binary_formats(version: MacVersion, cpu_arch: str) -> list[str]:
def mac_platforms(
- version: MacVersion | None = None, arch: str | None = None
+ version: AppleVersion | None = None, arch: str | None = None
) -> Iterator[str]:
"""
Yields the platform tags for a macOS system.
@@ -408,7 +408,7 @@ def mac_platforms(
"""
version_str, _, cpu_arch = platform.mac_ver()
if version is None:
- version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2])))
+ version = cast("AppleVersion", tuple(map(int, version_str.split(".")[:2])))
if version == (10, 16):
# When built against an older macOS SDK, Python will report macOS 10.16
# instead of the real version.
@@ -424,7 +424,7 @@ def mac_platforms(
stdout=subprocess.PIPE,
text=True,
).stdout
- version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2])))
+ version = cast("AppleVersion", tuple(map(int, version_str.split(".")[:2])))
else:
version = version
if arch is None:
@@ -483,6 +483,63 @@ def mac_platforms(
)
+def ios_platforms(
+ version: AppleVersion | None = None, multiarch: str | None = None
+) -> Iterator[str]:
+ """
+ Yields the platform tags for an iOS system.
+
+ :param version: A two-item tuple specifying the iOS version to generate
+ platform tags for. Defaults to the current iOS version.
+ :param multiarch: The CPU architecture+ABI to generate platform tags for -
+ (the value used by `sys.implementation._multiarch` e.g.,
+ `arm64_iphoneos` or `x84_64_iphonesimulator`). Defaults to the current
+ multiarch value.
+ """
+ if version is None:
+ # if iOS is the current platform, ios_ver *must* be defined. However,
+ # it won't exist for CPython versions before 3.13, which causes a mypy
+ # error.
+ _, release, _, _ = platform.ios_ver() # type: ignore[attr-defined]
+ version = cast("AppleVersion", tuple(map(int, release.split(".")[:2])))
+
+ if multiarch is None:
+ multiarch = sys.implementation._multiarch
+ multiarch = multiarch.replace("-", "_")
+
+ ios_platform_template = "ios_{major}_{minor}_{multiarch}"
+
+ # Consider any iOS major.minor version from the version requested, down to
+ # 12.0. 12.0 is the first iOS version that is known to have enough features
+ # to support CPython. Consider every possible minor release up to X.9. There
+ # highest the minor has ever gone is 8 (14.8 and 15.8) but having some extra
+ # candidates that won't ever match doesn't really hurt, and it saves us from
+ # having to keep an explicit list of known iOS versions in the code. Return
+ # the results descending order of version number.
+
+ # If the requested major version is less than 12, there won't be any matches.
+ if version[0] < 12:
+ return
+
+ # Consider the actual X.Y version that was requested.
+ yield ios_platform_template.format(
+ major=version[0], minor=version[1], multiarch=multiarch
+ )
+
+ # Consider every minor version from X.0 to the minor version prior to the
+ # version requested by the platform.
+ for minor in range(version[1] - 1, -1, -1):
+ yield ios_platform_template.format(
+ major=version[0], minor=minor, multiarch=multiarch
+ )
+
+ for major in range(version[0] - 1, 11, -1):
+ for minor in range(9, -1, -1):
+ yield ios_platform_template.format(
+ major=major, minor=minor, multiarch=multiarch
+ )
+
+
def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]:
linux = _normalize_string(sysconfig.get_platform())
if not linux.startswith("linux_"):
@@ -512,6 +569,8 @@ def platform_tags() -> Iterator[str]:
"""
if platform.system() == "Darwin":
return mac_platforms()
+ elif platform.system() == "iOS":
+ return ios_platforms()
elif platform.system() == "Linux":
return _linux_platforms()
else:
diff --git a/contrib/python/pip/pip/_vendor/truststore/__init__.py b/contrib/python/pip/pip/_vendor/truststore/__init__.py
index 86368145a7..e468bf8ceb 100644
--- a/contrib/python/pip/pip/_vendor/truststore/__init__.py
+++ b/contrib/python/pip/pip/_vendor/truststore/__init__.py
@@ -5,9 +5,32 @@ import sys as _sys
if _sys.version_info < (3, 10):
raise ImportError("truststore requires Python 3.10 or later")
+# Detect Python runtimes which don't implement SSLObject.get_unverified_chain() API
+# This API only became public in Python 3.13 but was available in CPython and PyPy since 3.10.
+if _sys.version_info < (3, 13):
+ try:
+ import ssl as _ssl
+ except ImportError:
+ raise ImportError("truststore requires the 'ssl' module")
+ else:
+ _sslmem = _ssl.MemoryBIO()
+ _sslobj = _ssl.create_default_context().wrap_bio(
+ _sslmem,
+ _sslmem,
+ )
+ try:
+ while not hasattr(_sslobj, "get_unverified_chain"):
+ _sslobj = _sslobj._sslobj # type: ignore[attr-defined]
+ except AttributeError:
+ raise ImportError(
+ "truststore requires peer certificate chain APIs to be available"
+ ) from None
+
+ del _ssl, _sslobj, _sslmem # noqa: F821
+
from ._api import SSLContext, extract_from_ssl, inject_into_ssl # noqa: E402
del _api, _sys # type: ignore[name-defined] # noqa: F821
__all__ = ["SSLContext", "inject_into_ssl", "extract_from_ssl"]
-__version__ = "0.9.1"
+__version__ = "0.10.0"
diff --git a/contrib/python/pip/pip/_vendor/truststore/_api.py b/contrib/python/pip/pip/_vendor/truststore/_api.py
index b1ea3b05c6..aeb023af75 100644
--- a/contrib/python/pip/pip/_vendor/truststore/_api.py
+++ b/contrib/python/pip/pip/_vendor/truststore/_api.py
@@ -169,6 +169,9 @@ class SSLContext(_truststore_SSLContext_super_class): # type: ignore[misc]
def cert_store_stats(self) -> dict[str, int]:
raise NotImplementedError()
+ def set_default_verify_paths(self) -> None:
+ self._ctx.set_default_verify_paths()
+
@typing.overload
def get_ca_certs(
self, binary_form: typing.Literal[False] = ...
diff --git a/contrib/python/pip/pip/_vendor/truststore/_macos.py b/contrib/python/pip/pip/_vendor/truststore/_macos.py
index b234ffec72..3450307724 100644
--- a/contrib/python/pip/pip/_vendor/truststore/_macos.py
+++ b/contrib/python/pip/pip/_vendor/truststore/_macos.py
@@ -25,6 +25,8 @@ if _mac_version_info < (10, 8):
f"Only OS X 10.8 and newer are supported, not {_mac_version_info[0]}.{_mac_version_info[1]}"
)
+_is_macos_version_10_14_or_later = _mac_version_info >= (10, 14)
+
def _load_cdll(name: str, macos10_16_path: str) -> CDLL:
"""Loads a CDLL by name, falling back to known path on 10.16+"""
@@ -115,6 +117,12 @@ try:
]
Security.SecTrustGetTrustResult.restype = OSStatus
+ Security.SecTrustEvaluate.argtypes = [
+ SecTrustRef,
+ POINTER(SecTrustResultType),
+ ]
+ Security.SecTrustEvaluate.restype = OSStatus
+
Security.SecTrustRef = SecTrustRef # type: ignore[attr-defined]
Security.SecTrustResultType = SecTrustResultType # type: ignore[attr-defined]
Security.OSStatus = OSStatus # type: ignore[attr-defined]
@@ -197,8 +205,19 @@ try:
CoreFoundation.CFStringRef = CFStringRef # type: ignore[attr-defined]
CoreFoundation.CFErrorRef = CFErrorRef # type: ignore[attr-defined]
-except AttributeError:
- raise ImportError("Error initializing ctypes") from None
+except AttributeError as e:
+ raise ImportError(f"Error initializing ctypes: {e}") from None
+
+# SecTrustEvaluateWithError is macOS 10.14+
+if _is_macos_version_10_14_or_later:
+ try:
+ Security.SecTrustEvaluateWithError.argtypes = [
+ SecTrustRef,
+ POINTER(CFErrorRef),
+ ]
+ Security.SecTrustEvaluateWithError.restype = c_bool
+ except AttributeError as e:
+ raise ImportError(f"Error initializing ctypes: {e}") from None
def _handle_osstatus(result: OSStatus, _: typing.Any, args: typing.Any) -> typing.Any:
@@ -258,6 +277,7 @@ Security.SecTrustCreateWithCertificates.errcheck = _handle_osstatus # type: ign
Security.SecTrustSetAnchorCertificates.errcheck = _handle_osstatus # type: ignore[assignment]
Security.SecTrustSetAnchorCertificatesOnly.errcheck = _handle_osstatus # type: ignore[assignment]
Security.SecTrustGetTrustResult.errcheck = _handle_osstatus # type: ignore[assignment]
+Security.SecTrustEvaluate.errcheck = _handle_osstatus # type: ignore[assignment]
class CFConst:
@@ -365,9 +385,10 @@ def _verify_peercerts_impl(
certs = None
policies = None
trust = None
- cf_error = None
try:
- if server_hostname is not None:
+ # Only set a hostname on the policy if we're verifying the hostname
+ # on the leaf certificate.
+ if server_hostname is not None and ssl_context.check_hostname:
cf_str_hostname = None
try:
cf_str_hostname = _bytes_to_cf_string(server_hostname.encode("ascii"))
@@ -431,69 +452,120 @@ def _verify_peercerts_impl(
# We always want system certificates.
Security.SecTrustSetAnchorCertificatesOnly(trust, False)
- cf_error = CoreFoundation.CFErrorRef()
- sec_trust_eval_result = Security.SecTrustEvaluateWithError(
- trust, ctypes.byref(cf_error)
- )
- # sec_trust_eval_result is a bool (0 or 1)
- # where 1 means that the certs are trusted.
- if sec_trust_eval_result == 1:
- is_trusted = True
- elif sec_trust_eval_result == 0:
- is_trusted = False
+ # macOS 10.13 and earlier don't support SecTrustEvaluateWithError()
+ # so we use SecTrustEvaluate() which means we need to construct error
+ # messages ourselves.
+ if _is_macos_version_10_14_or_later:
+ _verify_peercerts_impl_macos_10_14(ssl_context, trust)
else:
- raise ssl.SSLError(
- f"Unknown result from Security.SecTrustEvaluateWithError: {sec_trust_eval_result!r}"
- )
-
- cf_error_code = 0
- if not is_trusted:
- cf_error_code = CoreFoundation.CFErrorGetCode(cf_error)
-
- # If the error is a known failure that we're
- # explicitly okay with from SSLContext configuration
- # we can set is_trusted accordingly.
- if ssl_context.verify_mode != ssl.CERT_REQUIRED and (
- cf_error_code == CFConst.errSecNotTrusted
- or cf_error_code == CFConst.errSecCertificateExpired
- ):
- is_trusted = True
- elif (
- not ssl_context.check_hostname
- and cf_error_code == CFConst.errSecHostNameMismatch
- ):
- is_trusted = True
-
- # If we're still not trusted then we start to
- # construct and raise the SSLCertVerificationError.
- if not is_trusted:
- cf_error_string_ref = None
- try:
- cf_error_string_ref = CoreFoundation.CFErrorCopyDescription(cf_error)
-
- # Can this ever return 'None' if there's a CFError?
- cf_error_message = (
- _cf_string_ref_to_str(cf_error_string_ref)
- or "Certificate verification failed"
- )
-
- # TODO: Not sure if we need the SecTrustResultType for anything?
- # We only care whether or not it's a success or failure for now.
- sec_trust_result_type = Security.SecTrustResultType()
- Security.SecTrustGetTrustResult(
- trust, ctypes.byref(sec_trust_result_type)
- )
-
- err = ssl.SSLCertVerificationError(cf_error_message)
- err.verify_message = cf_error_message
- err.verify_code = cf_error_code
- raise err
- finally:
- if cf_error_string_ref:
- CoreFoundation.CFRelease(cf_error_string_ref)
-
+ _verify_peercerts_impl_macos_10_13(ssl_context, trust)
finally:
if policies:
CoreFoundation.CFRelease(policies)
if trust:
CoreFoundation.CFRelease(trust)
+
+
+def _verify_peercerts_impl_macos_10_13(
+ ssl_context: ssl.SSLContext, sec_trust_ref: typing.Any
+) -> None:
+ """Verify using 'SecTrustEvaluate' API for macOS 10.13 and earlier.
+ macOS 10.14 added the 'SecTrustEvaluateWithError' API.
+ """
+ sec_trust_result_type = Security.SecTrustResultType()
+ Security.SecTrustEvaluate(sec_trust_ref, ctypes.byref(sec_trust_result_type))
+
+ try:
+ sec_trust_result_type_as_int = int(sec_trust_result_type.value)
+ except (ValueError, TypeError):
+ sec_trust_result_type_as_int = -1
+
+ # Apple doesn't document these values in their own API docs.
+ # See: https://github.com/xybp888/iOS-SDKs/blob/master/iPhoneOS13.0.sdk/System/Library/Frameworks/Security.framework/Headers/SecTrust.h#L84
+ if (
+ ssl_context.verify_mode == ssl.CERT_REQUIRED
+ and sec_trust_result_type_as_int not in (1, 4)
+ ):
+ # Note that we're not able to ignore only hostname errors
+ # for macOS 10.13 and earlier, so check_hostname=False will
+ # still return an error.
+ sec_trust_result_type_to_message = {
+ 0: "Invalid trust result type",
+ # 1: "Trust evaluation succeeded",
+ 2: "User confirmation required",
+ 3: "User specified that certificate is not trusted",
+ # 4: "Trust result is unspecified",
+ 5: "Recoverable trust failure occurred",
+ 6: "Fatal trust failure occurred",
+ 7: "Other error occurred, certificate may be revoked",
+ }
+ error_message = sec_trust_result_type_to_message.get(
+ sec_trust_result_type_as_int,
+ f"Unknown trust result: {sec_trust_result_type_as_int}",
+ )
+
+ err = ssl.SSLCertVerificationError(error_message)
+ err.verify_message = error_message
+ err.verify_code = sec_trust_result_type_as_int
+ raise err
+
+
+def _verify_peercerts_impl_macos_10_14(
+ ssl_context: ssl.SSLContext, sec_trust_ref: typing.Any
+) -> None:
+ """Verify using 'SecTrustEvaluateWithError' API for macOS 10.14+."""
+ cf_error = CoreFoundation.CFErrorRef()
+ sec_trust_eval_result = Security.SecTrustEvaluateWithError(
+ sec_trust_ref, ctypes.byref(cf_error)
+ )
+ # sec_trust_eval_result is a bool (0 or 1)
+ # where 1 means that the certs are trusted.
+ if sec_trust_eval_result == 1:
+ is_trusted = True
+ elif sec_trust_eval_result == 0:
+ is_trusted = False
+ else:
+ raise ssl.SSLError(
+ f"Unknown result from Security.SecTrustEvaluateWithError: {sec_trust_eval_result!r}"
+ )
+
+ cf_error_code = 0
+ if not is_trusted:
+ cf_error_code = CoreFoundation.CFErrorGetCode(cf_error)
+
+ # If the error is a known failure that we're
+ # explicitly okay with from SSLContext configuration
+ # we can set is_trusted accordingly.
+ if ssl_context.verify_mode != ssl.CERT_REQUIRED and (
+ cf_error_code == CFConst.errSecNotTrusted
+ or cf_error_code == CFConst.errSecCertificateExpired
+ ):
+ is_trusted = True
+
+ # If we're still not trusted then we start to
+ # construct and raise the SSLCertVerificationError.
+ if not is_trusted:
+ cf_error_string_ref = None
+ try:
+ cf_error_string_ref = CoreFoundation.CFErrorCopyDescription(cf_error)
+
+ # Can this ever return 'None' if there's a CFError?
+ cf_error_message = (
+ _cf_string_ref_to_str(cf_error_string_ref)
+ or "Certificate verification failed"
+ )
+
+ # TODO: Not sure if we need the SecTrustResultType for anything?
+ # We only care whether or not it's a success or failure for now.
+ sec_trust_result_type = Security.SecTrustResultType()
+ Security.SecTrustGetTrustResult(
+ sec_trust_ref, ctypes.byref(sec_trust_result_type)
+ )
+
+ err = ssl.SSLCertVerificationError(cf_error_message)
+ err.verify_message = cf_error_message
+ err.verify_code = cf_error_code
+ raise err
+ finally:
+ if cf_error_string_ref:
+ CoreFoundation.CFRelease(cf_error_string_ref)
diff --git a/contrib/python/pip/pip/_vendor/truststore/_windows.py b/contrib/python/pip/pip/_vendor/truststore/_windows.py
index 3d00d467f9..a9bf9abdfc 100644
--- a/contrib/python/pip/pip/_vendor/truststore/_windows.py
+++ b/contrib/python/pip/pip/_vendor/truststore/_windows.py
@@ -212,6 +212,7 @@ CERT_CHAIN_POLICY_IGNORE_INVALID_POLICY_FLAG = 0x00000080
CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS = 0x00000F00
CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG = 0x00008000
CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG = 0x00004000
+SECURITY_FLAG_IGNORE_CERT_CN_INVALID = 0x00001000
AUTHTYPE_SERVER = 2
CERT_CHAIN_POLICY_SSL = 4
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
@@ -443,6 +444,10 @@ def _get_and_verify_cert_chain(
)
ssl_extra_cert_chain_policy_para.dwAuthType = AUTHTYPE_SERVER
ssl_extra_cert_chain_policy_para.fdwChecks = 0
+ if ssl_context.check_hostname is False:
+ ssl_extra_cert_chain_policy_para.fdwChecks = (
+ SECURITY_FLAG_IGNORE_CERT_CN_INVALID
+ )
if server_hostname:
ssl_extra_cert_chain_policy_para.pwszServerName = c_wchar_p(server_hostname)
@@ -452,8 +457,6 @@ def _get_and_verify_cert_chain(
)
if ssl_context.verify_mode == ssl.CERT_NONE:
chain_policy.dwFlags |= CERT_CHAIN_POLICY_VERIFY_MODE_NONE_FLAGS
- if not ssl_context.check_hostname:
- chain_policy.dwFlags |= CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG
chain_policy.cbSize = sizeof(chain_policy)
pPolicyPara = pointer(chain_policy)
diff --git a/contrib/python/pip/pip/_vendor/urllib3/_version.py b/contrib/python/pip/pip/_vendor/urllib3/_version.py
index 85e725eaf4..d49df2a0c5 100644
--- a/contrib/python/pip/pip/_vendor/urllib3/_version.py
+++ b/contrib/python/pip/pip/_vendor/urllib3/_version.py
@@ -1,2 +1,2 @@
# This file is protected via CODEOWNERS
-__version__ = "1.26.18"
+__version__ = "1.26.20"
diff --git a/contrib/python/pip/pip/_vendor/urllib3/connection.py b/contrib/python/pip/pip/_vendor/urllib3/connection.py
index 54b96b1915..de35b63d67 100644
--- a/contrib/python/pip/pip/_vendor/urllib3/connection.py
+++ b/contrib/python/pip/pip/_vendor/urllib3/connection.py
@@ -68,7 +68,7 @@ port_by_scheme = {"http": 80, "https": 443}
# When it comes time to update this value as a part of regular maintenance
# (ie test_recent_date is failing) update it to ~6 months before the current date.
-RECENT_DATE = datetime.date(2022, 1, 1)
+RECENT_DATE = datetime.date(2024, 1, 1)
_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]")
@@ -437,7 +437,7 @@ class HTTPSConnection(HTTPConnection):
and self.ssl_version is None
and hasattr(self.sock, "version")
and self.sock.version() in {"TLSv1", "TLSv1.1"}
- ):
+ ): # Defensive:
warnings.warn(
"Negotiating TLSv1/TLSv1.1 by default is deprecated "
"and will be disabled in urllib3 v2.0.0. Connecting to "
diff --git a/contrib/python/pip/pip/_vendor/urllib3/connectionpool.py b/contrib/python/pip/pip/_vendor/urllib3/connectionpool.py
index 5a6adcbdc7..0872ed7701 100644
--- a/contrib/python/pip/pip/_vendor/urllib3/connectionpool.py
+++ b/contrib/python/pip/pip/_vendor/urllib3/connectionpool.py
@@ -423,12 +423,13 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
pass
except IOError as e:
# Python 2 and macOS/Linux
- # EPIPE and ESHUTDOWN are BrokenPipeError on Python 2, and EPROTOTYPE is needed on macOS
+ # EPIPE and ESHUTDOWN are BrokenPipeError on Python 2, and EPROTOTYPE/ECONNRESET are needed on macOS
# https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/
if e.errno not in {
errno.EPIPE,
errno.ESHUTDOWN,
errno.EPROTOTYPE,
+ errno.ECONNRESET,
}:
raise
@@ -768,7 +769,9 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
# so we try to cover our bases here!
message = " ".join(re.split("[^a-z]", str(ssl_error).lower()))
return (
- "wrong version number" in message or "unknown protocol" in message
+ "wrong version number" in message
+ or "unknown protocol" in message
+ or "record layer failure" in message
)
# Try to detect a common user error with proxies which is to
diff --git a/contrib/python/pip/pip/_vendor/urllib3/util/retry.py b/contrib/python/pip/pip/_vendor/urllib3/util/retry.py
index 60ef6c4f3f..9a1e90d0b2 100644
--- a/contrib/python/pip/pip/_vendor/urllib3/util/retry.py
+++ b/contrib/python/pip/pip/_vendor/urllib3/util/retry.py
@@ -235,7 +235,9 @@ class Retry(object):
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
#: Default headers to be used for ``remove_headers_on_redirect``
- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Cookie", "Authorization"])
+ DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(
+ ["Cookie", "Authorization", "Proxy-Authorization"]
+ )
#: Maximum backoff time.
DEFAULT_BACKOFF_MAX = 120
diff --git a/contrib/python/pip/pip/_vendor/urllib3/util/ssl_.py b/contrib/python/pip/pip/_vendor/urllib3/util/ssl_.py
index 2b45d391d4..0a6a0e06a0 100644
--- a/contrib/python/pip/pip/_vendor/urllib3/util/ssl_.py
+++ b/contrib/python/pip/pip/_vendor/urllib3/util/ssl_.py
@@ -1,11 +1,11 @@
from __future__ import absolute_import
+import hashlib
import hmac
import os
import sys
import warnings
from binascii import hexlify, unhexlify
-from hashlib import md5, sha1, sha256
from ..exceptions import (
InsecurePlatformWarning,
@@ -24,7 +24,10 @@ IS_SECURETRANSPORT = False
ALPN_PROTOCOLS = ["http/1.1"]
# Maps the length of a digest to a possible hash function producing this digest
-HASHFUNC_MAP = {32: md5, 40: sha1, 64: sha256}
+HASHFUNC_MAP = {
+ length: getattr(hashlib, algorithm, None)
+ for length, algorithm in ((32, "md5"), (40, "sha1"), (64, "sha256"))
+}
def _const_compare_digest_backport(a, b):
@@ -191,9 +194,15 @@ def assert_fingerprint(cert, fingerprint):
fingerprint = fingerprint.replace(":", "").lower()
digest_length = len(fingerprint)
- hashfunc = HASHFUNC_MAP.get(digest_length)
- if not hashfunc:
+ if digest_length not in HASHFUNC_MAP:
raise SSLError("Fingerprint of invalid length: {0}".format(fingerprint))
+ hashfunc = HASHFUNC_MAP.get(digest_length)
+ if hashfunc is None:
+ raise SSLError(
+ "Hash function implementation unavailable for fingerprint length: {0}".format(
+ digest_length
+ )
+ )
# We need encode() here for py32; works on py2 and p33.
fingerprint_bytes = unhexlify(fingerprint.encode())
diff --git a/contrib/python/pip/pip/_vendor/vendor.txt b/contrib/python/pip/pip/_vendor/vendor.txt
index fd92690602..2ba053a6e5 100644
--- a/contrib/python/pip/pip/_vendor/vendor.txt
+++ b/contrib/python/pip/pip/_vendor/vendor.txt
@@ -1,18 +1,18 @@
CacheControl==0.14.0
-distlib==0.3.8
+distlib==0.3.9
distro==1.9.0
msgpack==1.0.8
packaging==24.1
platformdirs==4.2.2
pyproject-hooks==1.0.0
requests==2.32.3
- certifi==2024.7.4
+ certifi==2024.8.30
idna==3.7
- urllib3==1.26.18
+ urllib3==1.26.20
rich==13.7.1
pygments==2.18.0
typing_extensions==4.12.2
resolvelib==1.0.1
setuptools==70.3.0
tomli==2.0.1
-truststore==0.9.1
+truststore==0.10.0
diff --git a/contrib/python/pip/ya.make b/contrib/python/pip/ya.make
index 258dd0af73..64b3b100b7 100644
--- a/contrib/python/pip/ya.make
+++ b/contrib/python/pip/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(24.2)
+VERSION(24.3.1)
LICENSE(MIT)