diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 170bd6d8b60..2af281c7027 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -178,7 +178,7 @@ jobs: # - "3.9" # - "3.10" # - "3.11" - - "3.12" # Comment out when 3.13 is final + # - "3.12" - "3.13" group: [1, 2] diff --git a/docs/html/development/ci.rst b/docs/html/development/ci.rst index 2e950232fca..ef1f7125dfe 100644 --- a/docs/html/development/ci.rst +++ b/docs/html/development/ci.rst @@ -23,6 +23,7 @@ pip support a variety of Python interpreters: - CPython 3.10 - CPython 3.11 - CPython 3.12 +- CPython 3.13 - Latest PyPy3 on different operating systems: @@ -35,8 +36,9 @@ and on different architectures: - x64 - x86 +- arm64 (macOS only) -so 42 hypothetical interpreters. +so 49 hypothetical interpreters. Checks @@ -99,6 +101,8 @@ Actual testing | | +-------+---------------+-----------------+ | | | CP3.12| | | | | +-------+---------------+-----------------+ +| | | CP3.13| | | +| | +-------+---------------+-----------------+ | | | PyPy3 | | | | Windows +----------+-------+---------------+-----------------+ | | x64 | CP3.8 | GitHub | GitHub | @@ -107,10 +111,12 @@ Actual testing | | +-------+---------------+-----------------+ | | | CP3.10| | | | | +-------+---------------+-----------------+ -| | | CP3.11| GitHub | GitHub | +| | | CP3.11| | | | | +-------+---------------+-----------------+ | | | CP3.12| | | | | +-------+---------------+-----------------+ +| | | CP3.13| GitHub | GitHub | +| | +-------+---------------+-----------------+ | | | PyPy3 | | | +-----------+----------+-------+---------------+-----------------+ | | x86 | CP3.8 | | | @@ -123,6 +129,8 @@ Actual testing | | +-------+---------------+-----------------+ | | | CP3.12| | | | | +-------+---------------+-----------------+ +| | | CP3.13| | | +| | +-------+---------------+-----------------+ | | | PyPy3 | | | | Linux +----------+-------+---------------+-----------------+ | | x64 | CP3.8 | GitHub | GitHub | @@ -135,17 +143,21 @@ Actual testing | | +-------+---------------+-----------------+ | | | CP3.12| GitHub | GitHub | | | +-------+---------------+-----------------+ +| | | CP3.13| GitHub | GitHub | +| | +-------+---------------+-----------------+ | | | PyPy3 | | | +-----------+----------+-------+---------------+-----------------+ -| | arm64 | CP3.8 | | | +| | arm64 | CP3.8 | GitHub | GitHub | | | +-------+---------------+-----------------+ -| | | CP3.9 | | | +| | | CP3.9 | GitHub | GitHub | | | +-------+---------------+-----------------+ -| | | CP3.10| | | +| | | CP3.10| GitHub | GitHub | | | +-------+---------------+-----------------+ -| | | CP3.11| | | +| | | CP3.11| GitHub | GitHub | | | +-------+---------------+-----------------+ -| | | CP3.12| | | +| | | CP3.12| GitHub | GitHub | +| | +-------+---------------+-----------------+ +| | | CP3.13| GitHub | GitHub | | | +-------+---------------+-----------------+ | | | PyPy3 | | | | macOS +----------+-------+---------------+-----------------+ @@ -159,5 +171,7 @@ Actual testing | | +-------+---------------+-----------------+ | | | CP3.12| GitHub | GitHub | | | +-------+---------------+-----------------+ +| | | CP3.13| GitHub | GitHub | +| | +-------+---------------+-----------------+ | | | PyPy3 | | | +-----------+----------+-------+---------------+-----------------+ diff --git a/docs/html/installation.md b/docs/html/installation.md index 80a09f39dba..ffc8199ddc2 100644 --- a/docs/html/installation.md +++ b/docs/html/installation.md @@ -126,7 +126,7 @@ $ pip install --upgrade pip The current version of pip works on: - Windows, Linux and macOS. -- CPython 3.8, 3.9, 3.10, 3.11, 3.12, and latest PyPy3. +- CPython 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, and latest PyPy3. pip is tested to work on the latest patch version of the Python interpreter, for each of the minor versions listed above. Previous patch versions are diff --git a/news/12678.trivial.rst b/news/12678.trivial.rst new file mode 100644 index 00000000000..57f38781bc4 --- /dev/null +++ b/news/12678.trivial.rst @@ -0,0 +1 @@ +Update classifier to support Python 3.13 diff --git a/news/12939.trivial.rst b/news/12939.trivial.rst new file mode 100644 index 00000000000..c9acd4f8c54 --- /dev/null +++ b/news/12939.trivial.rst @@ -0,0 +1 @@ +Update non PEP 440 wheel filename deprecation notice. diff --git a/news/12961.feature.rst b/news/12961.feature.rst new file mode 100644 index 00000000000..e4e982db13b --- /dev/null +++ b/news/12961.feature.rst @@ -0,0 +1 @@ +Support for PEP 730 iOS wheels was added. diff --git a/news/12974.trivial.rst b/news/12974.trivial.rst new file mode 100644 index 00000000000..d1c31fb177a --- /dev/null +++ b/news/12974.trivial.rst @@ -0,0 +1 @@ +Create two new import groups, "vendored" and "import", this only affects tests. diff --git a/news/13012.trivial.rst b/news/13012.trivial.rst new file mode 100644 index 00000000000..623523a9e09 --- /dev/null +++ b/news/13012.trivial.rst @@ -0,0 +1 @@ +Clean up non PEP 440 wheel filename deprecation language. diff --git a/news/13013.trivial.rst b/news/13013.trivial.rst new file mode 100644 index 00000000000..75e724363a3 --- /dev/null +++ b/news/13013.trivial.rst @@ -0,0 +1 @@ +Remove InvalidVersion exception catch for parse_{sdist,wheel}_filename. diff --git a/news/truststore.vendor.rst b/news/truststore.vendor.rst new file mode 100644 index 00000000000..b75c1316454 --- /dev/null +++ b/news/truststore.vendor.rst @@ -0,0 +1 @@ +Upgrade truststore to 0.9.2 diff --git a/pyproject.toml b/pyproject.toml index 4d8d1181697..711e6bc8485 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ] @@ -185,9 +186,19 @@ select = [ ] [tool.ruff.lint.isort] -# Explicitly make tests "first party" as it's not in the "src" directory -known-first-party = ["tests"] -known-third-party = ["pip._vendor"] +section-order = [ + "future", + "standard-library", + "third-party", + "vendored", + "first-party", + "tests", + "local-folder", +] + +[tool.ruff.lint.isort.sections] +"vendored" = ["pip._vendor"] +"tests" = ["tests"] [tool.ruff.lint.mccabe] max-complexity = 33 # default is 10 diff --git a/src/pip/_internal/index/sources.py b/src/pip/_internal/index/sources.py index f4626d71ab4..3dafb30e6eb 100644 --- a/src/pip/_internal/index/sources.py +++ b/src/pip/_internal/index/sources.py @@ -6,7 +6,6 @@ from pip._vendor.packaging.utils import ( InvalidSdistFilename, - InvalidVersion, InvalidWheelFilename, canonicalize_name, parse_sdist_filename, @@ -68,10 +67,10 @@ def _scan_directory(self) -> None: # 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/src/pip/_internal/metadata/importlib/_envs.py b/src/pip/_internal/metadata/importlib/_envs.py index 70cb7a6009a..4d906fd3149 100644 --- a/src/pip/_internal/metadata/importlib/_envs.py +++ b/src/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/src/pip/_internal/models/wheel.py b/src/pip/_internal/models/wheel.py index 63db978f1f5..ea8560089d3 100644 --- a/src/pip/_internal/models/wheel.py +++ b/src/pip/_internal/models/wheel.py @@ -6,6 +6,10 @@ 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 @@ -32,20 +36,24 @@ def __init__(self, filename: str) -> None: self.name = wheel_info.group("name").replace("_", "-") _version = wheel_info.group("ver") if "_" in _version: - deprecated( - reason=( - f"Wheel filename {filename!r} uses an invalid filename format, " - f"as the version part {_version!r} is not correctly normalised, " - "and contains an underscore character. Future versions of pip may " - "fail to recognise this wheel." - ), - replacement=( - "rename the wheel to use a correctly normalised version part " - "(this may require updating the version in the project metadata)" - ), - gone_in="25.1", - issue=12914, - ) + 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 diff --git a/src/pip/_internal/utils/compatibility_tags.py b/src/pip/_internal/utils/compatibility_tags.py index b6ed9a78e55..2e7b7450dce 100644 --- a/src/pip/_internal/utils/compatibility_tags.py +++ b/src/pip/_internal/utils/compatibility_tags.py @@ -12,10 +12,11 @@ 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/src/pip/_vendor/distlib/scripts.py b/src/pip/_vendor/distlib/scripts.py index e16292b8330..0982e6b726e 100644 --- a/src/pip/_vendor/distlib/scripts.py +++ b/src/pip/_vendor/distlib/scripts.py @@ -164,6 +164,12 @@ def _build_shebang(self, executable, post_interp): """ 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 diff --git a/src/pip/_vendor/packaging/tags.py b/src/pip/_vendor/packaging/tags.py index 6667d299085..703f0ed53c0 100644 --- a/src/pip/_vendor/packaging/tags.py +++ b/src/pip/_vendor/packaging/tags.py @@ -25,7 +25,7 @@ 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/src/pip/_vendor/truststore/__init__.py b/src/pip/_vendor/truststore/__init__.py index 86368145a7e..b7d46aee262 100644 --- a/src/pip/_vendor/truststore/__init__.py +++ b/src/pip/_vendor/truststore/__init__.py @@ -5,9 +5,32 @@ 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.9.2" diff --git a/src/pip/_vendor/vendor.txt b/src/pip/_vendor/vendor.txt index 5c51aae0443..8f9e3773cb3 100644 --- a/src/pip/_vendor/vendor.txt +++ b/src/pip/_vendor/vendor.txt @@ -15,4 +15,4 @@ rich==13.7.1 resolvelib==1.0.1 setuptools==70.3.0 tomli==2.0.1 -truststore==0.9.1 +truststore==0.9.2 diff --git a/tests/conftest.py b/tests/conftest.py index da4ab5b9dfb..d093eea462b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -47,6 +47,7 @@ from pip import __file__ as pip_location from pip._internal.locations import _USE_SYSCONFIG from pip._internal.utils.temp_dir import global_tempdir_manager + from tests.lib import ( DATA_DIR, SRC_DIR, diff --git a/tests/functional/test_build_env.py b/tests/functional/test_build_env.py index 11164be0500..c950a8a6de9 100644 --- a/tests/functional/test_build_env.py +++ b/tests/functional/test_build_env.py @@ -6,6 +6,7 @@ import pytest from pip._internal.build_env import BuildEnvironment, _get_system_sitepackages + from tests.lib import ( PipTestEnvironment, TestPipResult, diff --git a/tests/functional/test_cli.py b/tests/functional/test_cli.py index e1ccf04ea1c..5be66d88eac 100644 --- a/tests/functional/test_cli.py +++ b/tests/functional/test_cli.py @@ -9,6 +9,7 @@ import pytest from pip._internal.commands import commands_dict + from tests.lib import PipTestEnvironment diff --git a/tests/functional/test_config_settings.py b/tests/functional/test_config_settings.py index 857722dd10d..4e0b12ca185 100644 --- a/tests/functional/test_config_settings.py +++ b/tests/functional/test_config_settings.py @@ -5,6 +5,7 @@ from zipfile import ZipFile from pip._internal.utils.urls import path_to_url + from tests.lib import PipTestEnvironment, create_basic_sdist_for_package PYPROJECT_TOML = """\ diff --git a/tests/functional/test_configuration.py b/tests/functional/test_configuration.py index 854fb3694b1..56cac572c4f 100644 --- a/tests/functional/test_configuration.py +++ b/tests/functional/test_configuration.py @@ -6,6 +6,7 @@ from pip._internal.cli.status_codes import ERROR from pip._internal.configuration import CONFIG_BASENAME, get_configuration_files + from tests.lib import PipTestEnvironment from tests.lib.configuration_helpers import ConfigurationMixin, kinds from tests.lib.venv import VirtualEnvironment diff --git a/tests/functional/test_debug.py b/tests/functional/test_debug.py index 77d4bea335f..82557299904 100644 --- a/tests/functional/test_debug.py +++ b/tests/functional/test_debug.py @@ -2,10 +2,12 @@ from typing import List import pytest + from pip._vendor.packaging.version import Version from pip._internal.commands.debug import create_vendor_txt_map from pip._internal.utils import compatibility_tags + from tests.lib import PipTestEnvironment diff --git a/tests/functional/test_download.py b/tests/functional/test_download.py index d469e71c360..3906885a19b 100644 --- a/tests/functional/test_download.py +++ b/tests/functional/test_download.py @@ -11,6 +11,7 @@ from pip._internal.cli.status_codes import ERROR from pip._internal.utils.urls import path_to_url + from tests.lib import ( PipTestEnvironment, ScriptFactory, diff --git a/tests/functional/test_fast_deps.py b/tests/functional/test_fast_deps.py index 5a910b89763..85c9bbd7072 100644 --- a/tests/functional/test_fast_deps.py +++ b/tests/functional/test_fast_deps.py @@ -7,9 +7,11 @@ from typing import Iterable import pytest + from pip._vendor.packaging.utils import canonicalize_name from pip._internal.utils.misc import hash_file + from tests.lib import PipTestEnvironment, TestData, TestPipResult diff --git a/tests/functional/test_freeze.py b/tests/functional/test_freeze.py index b7af974ea61..0a7cedd11cb 100644 --- a/tests/functional/test_freeze.py +++ b/tests/functional/test_freeze.py @@ -6,9 +6,11 @@ from pathlib import Path import pytest + from pip._vendor.packaging.utils import canonicalize_name from pip._internal.models.direct_url import DirectUrl, DirInfo + from tests.lib import ( PipTestEnvironment, TestData, diff --git a/tests/functional/test_help.py b/tests/functional/test_help.py index 75414214a93..cba036927c8 100644 --- a/tests/functional/test_help.py +++ b/tests/functional/test_help.py @@ -5,6 +5,7 @@ from pip._internal.cli.status_codes import ERROR, SUCCESS from pip._internal.commands import commands_dict, create_command from pip._internal.exceptions import CommandError + from tests.lib import InMemoryPip, PipTestEnvironment diff --git a/tests/functional/test_index.py b/tests/functional/test_index.py index 43b8f09c311..5a3c27bac9d 100644 --- a/tests/functional/test_index.py +++ b/tests/functional/test_index.py @@ -2,6 +2,7 @@ from pip._internal.cli.status_codes import ERROR, SUCCESS from pip._internal.commands import create_command + from tests.lib import PipTestEnvironment diff --git a/tests/functional/test_install.py b/tests/functional/test_install.py index 8c30a69b515..4718beb948c 100644 --- a/tests/functional/test_install.py +++ b/tests/functional/test_install.py @@ -17,6 +17,7 @@ from pip._internal.models.index import PyPI, TestPyPI from pip._internal.utils.misc import rmtree from pip._internal.utils.urls import path_to_url + from tests.lib import ( CertFactory, PipTestEnvironment, diff --git a/tests/functional/test_install_direct_url.py b/tests/functional/test_install_direct_url.py index 139ef178e77..5aefab09cb3 100644 --- a/tests/functional/test_install_direct_url.py +++ b/tests/functional/test_install_direct_url.py @@ -1,6 +1,7 @@ import pytest from pip._internal.models.direct_url import VcsInfo + from tests.lib import PipTestEnvironment, TestData, _create_test_package from tests.lib.direct_url import get_created_direct_url diff --git a/tests/functional/test_invalid_versions_and_specifiers.py b/tests/functional/test_invalid_versions_and_specifiers.py index 4867fe54beb..6349036bf52 100644 --- a/tests/functional/test_invalid_versions_and_specifiers.py +++ b/tests/functional/test_invalid_versions_and_specifiers.py @@ -3,6 +3,7 @@ import pytest from pip._internal.metadata import select_backend + from tests.lib import PipTestEnvironment, TestData diff --git a/tests/functional/test_list.py b/tests/functional/test_list.py index 43998600eb6..e611fe7cb64 100644 --- a/tests/functional/test_list.py +++ b/tests/functional/test_list.py @@ -5,6 +5,7 @@ import pytest from pip._internal.models.direct_url import DirectUrl, DirInfo + from tests.lib import ( PipTestEnvironment, ScriptFactory, diff --git a/tests/functional/test_new_resolver_target.py b/tests/functional/test_new_resolver_target.py index 4434c276fca..58b2d548b65 100644 --- a/tests/functional/test_new_resolver_target.py +++ b/tests/functional/test_new_resolver_target.py @@ -4,6 +4,7 @@ import pytest from pip._internal.cli.status_codes import ERROR, SUCCESS + from tests.lib import PipTestEnvironment from tests.lib.wheel import make_wheel diff --git a/tests/functional/test_pep517.py b/tests/functional/test_pep517.py index 4e0c16358af..fd9380d0eb6 100644 --- a/tests/functional/test_pep517.py +++ b/tests/functional/test_pep517.py @@ -7,6 +7,7 @@ from pip._internal.build_env import BuildEnvironment from pip._internal.req import InstallRequirement + from tests.lib import ( PipTestEnvironment, TestData, diff --git a/tests/functional/test_pip_runner_script.py b/tests/functional/test_pip_runner_script.py index f2f879b824d..ba73f936321 100644 --- a/tests/functional/test_pip_runner_script.py +++ b/tests/functional/test_pip_runner_script.py @@ -2,6 +2,7 @@ from pathlib import Path from pip import __version__ + from tests.lib import PipTestEnvironment diff --git a/tests/functional/test_search.py b/tests/functional/test_search.py index 3d4baeb4832..9491b492400 100644 --- a/tests/functional/test_search.py +++ b/tests/functional/test_search.py @@ -7,6 +7,7 @@ from pip._internal.cli.status_codes import NO_MATCHES_FOUND, SUCCESS from pip._internal.commands import create_command from pip._internal.commands.search import highest_version, print_results, transform_hits + from tests.lib import PipTestEnvironment if TYPE_CHECKING: diff --git a/tests/functional/test_show.py b/tests/functional/test_show.py index 7797de9e992..4cc1587733f 100644 --- a/tests/functional/test_show.py +++ b/tests/functional/test_show.py @@ -8,6 +8,7 @@ from pip import __version__ from pip._internal.commands.show import search_packages_info from pip._internal.utils.unpacking import untar_file + from tests.lib import ( PipTestEnvironment, TestData, diff --git a/tests/functional/test_uninstall.py b/tests/functional/test_uninstall.py index 58e141e54ad..d86ba172002 100644 --- a/tests/functional/test_uninstall.py +++ b/tests/functional/test_uninstall.py @@ -12,6 +12,7 @@ from pip._internal.req.constructors import install_req_from_line from pip._internal.utils.misc import rmtree + from tests.lib import ( PipTestEnvironment, TestData, diff --git a/tests/functional/test_vcs_bazaar.py b/tests/functional/test_vcs_bazaar.py index 63955d6e701..821427ed841 100644 --- a/tests/functional/test_vcs_bazaar.py +++ b/tests/functional/test_vcs_bazaar.py @@ -10,6 +10,7 @@ from pip._internal.vcs.bazaar import Bazaar from pip._internal.vcs.versioncontrol import RemoteNotFoundError + from tests.lib import PipTestEnvironment, is_bzr_installed, need_bzr diff --git a/tests/functional/test_vcs_git.py b/tests/functional/test_vcs_git.py index a7276e2b6a5..f917fa8b39e 100644 --- a/tests/functional/test_vcs_git.py +++ b/tests/functional/test_vcs_git.py @@ -13,6 +13,7 @@ from pip._internal.utils.misc import HiddenText from pip._internal.vcs import vcs from pip._internal.vcs.git import Git, RemoteNotFoundError + from tests.lib import PipTestEnvironment, _create_test_package, _git_commit diff --git a/tests/functional/test_vcs_mercurial.py b/tests/functional/test_vcs_mercurial.py index 9a909e71f24..a511c40aae2 100644 --- a/tests/functional/test_vcs_mercurial.py +++ b/tests/functional/test_vcs_mercurial.py @@ -1,6 +1,7 @@ import os from pip._internal.vcs.mercurial import Mercurial + from tests.lib import PipTestEnvironment, _create_test_package, need_mercurial diff --git a/tests/functional/test_vcs_subversion.py b/tests/functional/test_vcs_subversion.py index 05c20c7c145..987f481edd4 100644 --- a/tests/functional/test_vcs_subversion.py +++ b/tests/functional/test_vcs_subversion.py @@ -4,6 +4,7 @@ from pip._internal.vcs.subversion import Subversion from pip._internal.vcs.versioncontrol import RemoteNotFoundError + from tests.lib import PipTestEnvironment, _create_svn_repo, need_svn diff --git a/tests/functional/test_wheel.py b/tests/functional/test_wheel.py index 1bddd40dc41..da2bd2d7904 100644 --- a/tests/functional/test_wheel.py +++ b/tests/functional/test_wheel.py @@ -8,6 +8,7 @@ import pytest from pip._internal.cli.status_codes import ERROR + from tests.lib import ( PipTestEnvironment, TestData, diff --git a/tests/lib/__init__.py b/tests/lib/__init__.py index e318f7155d2..df142ba4438 100644 --- a/tests/lib/__init__.py +++ b/tests/lib/__init__.py @@ -32,9 +32,10 @@ from zipfile import ZipFile import pytest -from pip._vendor.packaging.utils import canonicalize_name from scripttest import FoundDir, FoundFile, ProcResult, TestFileEnvironment +from pip._vendor.packaging.utils import canonicalize_name + from pip._internal.cli.main import main as pip_entry_point from pip._internal.index.collector import LinkCollector from pip._internal.index.package_finder import PackageFinder @@ -44,6 +45,7 @@ from pip._internal.models.target_python import TargetPython from pip._internal.network.session import PipSession from pip._internal.utils.egg_link import _egg_link_names + from tests.lib.venv import VirtualEnvironment from tests.lib.wheel import make_wheel diff --git a/tests/lib/direct_url.py b/tests/lib/direct_url.py index e0dac032062..fff1ae966cd 100644 --- a/tests/lib/direct_url.py +++ b/tests/lib/direct_url.py @@ -4,6 +4,7 @@ from typing import Optional from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl + from tests.lib import TestPipResult diff --git a/tests/unit/metadata/test_metadata.py b/tests/unit/metadata/test_metadata.py index caa2dea8c91..404d858bdd5 100644 --- a/tests/unit/metadata/test_metadata.py +++ b/tests/unit/metadata/test_metadata.py @@ -5,6 +5,7 @@ from unittest import mock import pytest + from pip._vendor.packaging.utils import NormalizedName from pip._internal.metadata import ( @@ -15,6 +16,7 @@ ) from pip._internal.metadata.base import FilesystemWheel from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, ArchiveInfo + from tests.lib.wheel import make_wheel diff --git a/tests/unit/metadata/test_metadata_pkg_resources.py b/tests/unit/metadata/test_metadata_pkg_resources.py index 6044c14e4ca..6b3a302fb3c 100644 --- a/tests/unit/metadata/test_metadata_pkg_resources.py +++ b/tests/unit/metadata/test_metadata_pkg_resources.py @@ -4,6 +4,7 @@ from unittest import mock import pytest + from pip._vendor.packaging.requirements import Requirement from pip._vendor.packaging.specifiers import SpecifierSet from pip._vendor.packaging.utils import canonicalize_name diff --git a/tests/unit/resolution_resolvelib/conftest.py b/tests/unit/resolution_resolvelib/conftest.py index 348396bafe2..6aa5f505dbb 100644 --- a/tests/unit/resolution_resolvelib/conftest.py +++ b/tests/unit/resolution_resolvelib/conftest.py @@ -17,6 +17,7 @@ from pip._internal.resolution.resolvelib.factory import Factory from pip._internal.resolution.resolvelib.provider import PipProvider from pip._internal.utils.temp_dir import TempDirectory, global_tempdir_manager + from tests.lib import TestData diff --git a/tests/unit/resolution_resolvelib/test_requirement.py b/tests/unit/resolution_resolvelib/test_requirement.py index 436081b1d8f..cde6256a206 100644 --- a/tests/unit/resolution_resolvelib/test_requirement.py +++ b/tests/unit/resolution_resolvelib/test_requirement.py @@ -3,11 +3,13 @@ from typing import List, Tuple import pytest + from pip._vendor.resolvelib import BaseReporter, Resolver from pip._internal.resolution.resolvelib.base import Candidate, Constraint, Requirement from pip._internal.resolution.resolvelib.factory import Factory from pip._internal.resolution.resolvelib.provider import PipProvider + from tests.lib import TestData # NOTE: All tests are prefixed `test_rlr` (for "test resolvelib resolver"). diff --git a/tests/unit/resolution_resolvelib/test_resolver.py b/tests/unit/resolution_resolvelib/test_resolver.py index f2f36770fe6..18238eef134 100644 --- a/tests/unit/resolution_resolvelib/test_resolver.py +++ b/tests/unit/resolution_resolvelib/test_resolver.py @@ -2,6 +2,7 @@ from unittest import mock import pytest + from pip._vendor.packaging.utils import canonicalize_name from pip._vendor.resolvelib.resolvers import Result from pip._vendor.resolvelib.structs import DirectedGraph diff --git a/tests/unit/test_appdirs.py b/tests/unit/test_appdirs.py index fd3ea143bcb..6e6521dd5c0 100644 --- a/tests/unit/test_appdirs.py +++ b/tests/unit/test_appdirs.py @@ -5,6 +5,7 @@ from unittest import mock import pytest + from pip._vendor import platformdirs from pip._internal.utils import appdirs diff --git a/tests/unit/test_collector.py b/tests/unit/test_collector.py index 882f82ae4fe..c527d5610a3 100644 --- a/tests/unit/test_collector.py +++ b/tests/unit/test_collector.py @@ -10,6 +10,7 @@ from unittest import mock import pytest + from pip._vendor import requests from pip._vendor.packaging.requirements import Requirement @@ -35,6 +36,7 @@ _ensure_quoted_url, ) from pip._internal.network.session import PipSession + from tests.lib import ( TestData, make_test_link_collector, diff --git a/tests/unit/test_configuration.py b/tests/unit/test_configuration.py index 1a0acb7b411..29a268c7875 100644 --- a/tests/unit/test_configuration.py +++ b/tests/unit/test_configuration.py @@ -8,6 +8,7 @@ from pip._internal.configuration import get_configuration_files, kinds from pip._internal.exceptions import ConfigurationError + from tests.lib.configuration_helpers import ConfigurationMixin diff --git a/tests/unit/test_exceptions.py b/tests/unit/test_exceptions.py index 12a17dcd1f3..90a44348f0a 100644 --- a/tests/unit/test_exceptions.py +++ b/tests/unit/test_exceptions.py @@ -9,6 +9,7 @@ from typing import Optional, Tuple import pytest + from pip._vendor import rich from pip._internal.exceptions import DiagnosticPipError, ExternallyManagedEnvironment diff --git a/tests/unit/test_finder.py b/tests/unit/test_finder.py index 35c7e89b765..8c923dcd36f 100644 --- a/tests/unit/test_finder.py +++ b/tests/unit/test_finder.py @@ -3,6 +3,7 @@ from unittest.mock import Mock, patch import pytest + from pip._vendor.packaging.specifiers import SpecifierSet from pip._vendor.packaging.tags import Tag from pip._vendor.packaging.version import parse as parse_version @@ -18,6 +19,7 @@ ) from pip._internal.models.target_python import TargetPython from pip._internal.req.constructors import install_req_from_line + from tests.lib import TestData, make_test_finder diff --git a/tests/unit/test_index.py b/tests/unit/test_index.py index d02c70b260e..8faa4a56a0a 100644 --- a/tests/unit/test_index.py +++ b/tests/unit/test_index.py @@ -2,6 +2,7 @@ from typing import FrozenSet, List, Optional, Set, Tuple import pytest + from pip._vendor.packaging.specifiers import SpecifierSet from pip._vendor.packaging.tags import Tag @@ -25,6 +26,7 @@ from pip._internal.network.session import PipSession from pip._internal.utils.compatibility_tags import get_supported from pip._internal.utils.hashes import Hashes + from tests.lib import CURRENT_PY_VERSION_INFO from tests.lib.index import make_mock_candidate diff --git a/tests/unit/test_models_wheel.py b/tests/unit/test_models_wheel.py index ee4d88c744a..e87b2c107a0 100644 --- a/tests/unit/test_models_wheel.py +++ b/tests/unit/test_models_wheel.py @@ -1,4 +1,5 @@ import pytest + from pip._vendor.packaging.tags import Tag from pip._internal.exceptions import InvalidWheelFilename @@ -148,6 +149,28 @@ def test_not_supported_multiarch_darwin(self) -> None: assert not w.supported(tags=intel) assert not w.supported(tags=universal) + def test_supported_ios_version(self) -> None: + """ + Wheels build for iOS 12.3 are supported on iOS 15.1 + """ + tags = compatibility_tags.get_supported( + "313", platforms=["ios_15_1_arm64_iphoneos"], impl="cp" + ) + w = Wheel("simple-0.1-cp313-none-ios_12_3_arm64_iphoneos.whl") + assert w.supported(tags=tags) + w = Wheel("simple-0.1-cp313-none-ios_15_1_arm64_iphoneos.whl") + assert w.supported(tags=tags) + + def test_not_supported_ios_version(self) -> None: + """ + Wheels built for macOS 15.1 are not supported on 12.3 + """ + tags = compatibility_tags.get_supported( + "313", platforms=["ios_12_3_arm64_iphoneos"], impl="cp" + ) + w = Wheel("simple-0.1-cp313-none-ios_15_1_arm64_iphoneos.whl") + assert not w.supported(tags=tags) + def test_support_index_min(self) -> None: """ Test results from `support_index_min` @@ -178,3 +201,10 @@ def test_version_underscore_conversion(self) -> None: with pytest.warns(deprecation.PipDeprecationWarning): w = Wheel("simple-0.1_1-py2-none-any.whl") assert w.version == "0.1-1" + + def test_invalid_wheel_warning(self) -> None: + """ + Test that wheel with invalid name produces warning + """ + with pytest.warns(deprecation.PipDeprecationWarning): + Wheel("six-1.16.0_build1-py3-none-any.whl") diff --git a/tests/unit/test_network_auth.py b/tests/unit/test_network_auth.py index 86f01e436c0..aec5e513ba5 100644 --- a/tests/unit/test_network_auth.py +++ b/tests/unit/test_network_auth.py @@ -8,6 +8,7 @@ import pip._internal.network.auth from pip._internal.network.auth import MultiDomainBasicAuth + from tests.lib.requests_mocks import MockConnection, MockRequest, MockResponse diff --git a/tests/unit/test_network_cache.py b/tests/unit/test_network_cache.py index b43b36cd897..6bba8fc670b 100644 --- a/tests/unit/test_network_cache.py +++ b/tests/unit/test_network_cache.py @@ -3,9 +3,11 @@ from unittest.mock import Mock import pytest + from pip._vendor.cachecontrol.caches import FileCache from pip._internal.network.cache import SafeFileCache + from tests.lib.filesystem import chmod diff --git a/tests/unit/test_network_download.py b/tests/unit/test_network_download.py index 53200f2e511..14998d229bf 100644 --- a/tests/unit/test_network_download.py +++ b/tests/unit/test_network_download.py @@ -10,6 +10,7 @@ parse_content_disposition, sanitize_content_filename, ) + from tests.lib.requests_mocks import MockResponse diff --git a/tests/unit/test_network_lazy_wheel.py b/tests/unit/test_network_lazy_wheel.py index 356387d2bba..5d97e9e3202 100644 --- a/tests/unit/test_network_lazy_wheel.py +++ b/tests/unit/test_network_lazy_wheel.py @@ -1,6 +1,7 @@ from typing import Iterator import pytest + from pip._vendor.packaging.version import Version from pip._internal.exceptions import InvalidWheel @@ -9,6 +10,7 @@ dist_from_wheel_url, ) from pip._internal.network.session import PipSession + from tests.lib import TestData from tests.lib.server import MockServer, file_response diff --git a/tests/unit/test_network_session.py b/tests/unit/test_network_session.py index 3f1a596ad8e..fd00d5c606c 100644 --- a/tests/unit/test_network_session.py +++ b/tests/unit/test_network_session.py @@ -6,6 +6,7 @@ from urllib.request import getproxies import pytest + from pip._vendor import requests from pip import __version__ diff --git a/tests/unit/test_network_utils.py b/tests/unit/test_network_utils.py index 1b198c166fc..5911583feec 100644 --- a/tests/unit/test_network_utils.py +++ b/tests/unit/test_network_utils.py @@ -2,6 +2,7 @@ from pip._internal.exceptions import NetworkConnectionError from pip._internal.network.utils import raise_for_status + from tests.lib.requests_mocks import MockResponse diff --git a/tests/unit/test_operations_prepare.py b/tests/unit/test_operations_prepare.py index d06733e8503..86e26c11801 100644 --- a/tests/unit/test_operations_prepare.py +++ b/tests/unit/test_operations_prepare.py @@ -14,6 +14,7 @@ from pip._internal.network.session import PipSession from pip._internal.operations.prepare import unpack_url from pip._internal.utils.hashes import Hashes + from tests.lib import TestData from tests.lib.requests_mocks import MockResponse diff --git a/tests/unit/test_options.py b/tests/unit/test_options.py index aee64ccc932..8f3cf7de6a6 100644 --- a/tests/unit/test_options.py +++ b/tests/unit/test_options.py @@ -11,6 +11,7 @@ from pip._internal.commands import create_command from pip._internal.commands.configuration import ConfigurationCommand from pip._internal.exceptions import PipError + from tests.lib.options_helpers import AddFakeCommandMixin diff --git a/tests/unit/test_packaging.py b/tests/unit/test_packaging.py index 88277448c2c..6b8c4cd37d8 100644 --- a/tests/unit/test_packaging.py +++ b/tests/unit/test_packaging.py @@ -1,6 +1,7 @@ from typing import Optional, Tuple import pytest + from pip._vendor.packaging import specifiers from pip._vendor.packaging.requirements import Requirement diff --git a/tests/unit/test_pep517.py b/tests/unit/test_pep517.py index b9fcd9d2137..4264bbdcac8 100644 --- a/tests/unit/test_pep517.py +++ b/tests/unit/test_pep517.py @@ -7,6 +7,7 @@ from pip._internal.exceptions import InstallationError, InvalidPyProjectBuildRequires from pip._internal.req import InstallRequirement + from tests.lib import TestData diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index 8a95c058706..e243a718725 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -10,6 +10,7 @@ from unittest import mock import pytest + from pip._vendor.packaging.markers import Marker from pip._vendor.packaging.requirements import Requirement @@ -46,6 +47,7 @@ handle_requirement_line, ) from pip._internal.resolution.legacy.resolver import Resolver + from tests.lib import TestData, make_test_finder, requirements_file, wheel diff --git a/tests/unit/test_req_file.py b/tests/unit/test_req_file.py index 1ddccdee58e..7593e55d679 100644 --- a/tests/unit/test_req_file.py +++ b/tests/unit/test_req_file.py @@ -28,6 +28,7 @@ preprocess, ) from pip._internal.req.req_install import InstallRequirement + from tests.lib import TestData, make_test_finder, requirements_file diff --git a/tests/unit/test_req_install.py b/tests/unit/test_req_install.py index 22b98f86da2..79828525da4 100644 --- a/tests/unit/test_req_install.py +++ b/tests/unit/test_req_install.py @@ -3,6 +3,7 @@ from pathlib import Path import pytest + from pip._vendor.packaging.requirements import Requirement from pip._internal.exceptions import InstallationError diff --git a/tests/unit/test_req_uninstall.py b/tests/unit/test_req_uninstall.py index 0523ffd7a07..0372eac9bd9 100644 --- a/tests/unit/test_req_uninstall.py +++ b/tests/unit/test_req_uninstall.py @@ -16,6 +16,7 @@ compress_for_rename, uninstallation_paths, ) + from tests.lib import create_file diff --git a/tests/unit/test_resolution_legacy_resolver.py b/tests/unit/test_resolution_legacy_resolver.py index b2f93b3d4f5..489f678c561 100644 --- a/tests/unit/test_resolution_legacy_resolver.py +++ b/tests/unit/test_resolution_legacy_resolver.py @@ -5,6 +5,7 @@ from unittest import mock import pytest + from pip._vendor.packaging.specifiers import SpecifierSet from pip._vendor.packaging.utils import NormalizedName @@ -21,6 +22,7 @@ Resolver, _check_dist_requires_python, ) + from tests.lib import TestData, make_test_finder from tests.lib.index import make_mock_candidate diff --git a/tests/unit/test_self_check_outdated.py b/tests/unit/test_self_check_outdated.py index 605d9182a09..38ce648a09d 100644 --- a/tests/unit/test_self_check_outdated.py +++ b/tests/unit/test_self_check_outdated.py @@ -10,6 +10,7 @@ import pytest from freezegun import freeze_time + from pip._vendor.packaging.version import Version from pip._internal import self_outdated_check diff --git a/tests/unit/test_target_python.py b/tests/unit/test_target_python.py index 31df5935ee3..63e77a3d8a9 100644 --- a/tests/unit/test_target_python.py +++ b/tests/unit/test_target_python.py @@ -2,9 +2,11 @@ from unittest import mock import pytest + from pip._vendor.packaging.tags import Tag from pip._internal.models.target_python import TargetPython + from tests.lib import CURRENT_PY_VERSION_INFO, pyversion diff --git a/tests/unit/test_urls.py b/tests/unit/test_urls.py index c4b8db681ff..539bf091fb2 100644 --- a/tests/unit/test_urls.py +++ b/tests/unit/test_urls.py @@ -5,6 +5,7 @@ import pytest from pip._internal.utils.urls import path_to_url, url_to_path + from tests.lib import ( skip_needs_new_urlun_behavior_win, skip_needs_old_urlun_behavior_win, diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index d1e64262de2..6627a89496d 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -15,6 +15,7 @@ from unittest.mock import Mock, patch import pytest + from pip._vendor.packaging.requirements import Requirement from pip._internal.exceptions import HashMismatch, HashMissing, InstallationError diff --git a/tests/unit/test_utils_unpacking.py b/tests/unit/test_utils_unpacking.py index e0db5c4ba4a..5f89751311a 100644 --- a/tests/unit/test_utils_unpacking.py +++ b/tests/unit/test_utils_unpacking.py @@ -14,6 +14,7 @@ from pip._internal.exceptions import InstallationError from pip._internal.utils.unpacking import is_within_directory, untar_file, unzip_file + from tests.lib import TestData diff --git a/tests/unit/test_utils_wheel.py b/tests/unit/test_utils_wheel.py index 4e8e72be64a..b31b51ccae0 100644 --- a/tests/unit/test_utils_wheel.py +++ b/tests/unit/test_utils_wheel.py @@ -10,6 +10,7 @@ from pip._internal.exceptions import UnsupportedWheel from pip._internal.utils import wheel + from tests.lib import TestData _ZipDir = Callable[[Path], ZipFile] diff --git a/tests/unit/test_vcs.py b/tests/unit/test_vcs.py index 13ef42fc43f..c9a026968f4 100644 --- a/tests/unit/test_vcs.py +++ b/tests/unit/test_vcs.py @@ -14,6 +14,7 @@ from pip._internal.vcs.mercurial import Mercurial from pip._internal.vcs.subversion import Subversion from pip._internal.vcs.versioncontrol import RevOptions, VersionControl + from tests.lib import is_svn_installed, need_svn diff --git a/tests/unit/test_vcs_mercurial.py b/tests/unit/test_vcs_mercurial.py index d8e8f6cad27..ef52795a513 100644 --- a/tests/unit/test_vcs_mercurial.py +++ b/tests/unit/test_vcs_mercurial.py @@ -8,6 +8,7 @@ from pip._internal.utils.misc import hide_url from pip._internal.vcs.mercurial import Mercurial + from tests.lib import need_mercurial diff --git a/tests/unit/test_wheel.py b/tests/unit/test_wheel.py index ed6f5821133..7b44a59e4a4 100644 --- a/tests/unit/test_wheel.py +++ b/tests/unit/test_wheel.py @@ -12,6 +12,7 @@ from unittest.mock import patch import pytest + from pip._vendor.packaging.requirements import Requirement from pip._internal.exceptions import InstallationError @@ -32,6 +33,7 @@ from pip._internal.utils.compat import WINDOWS from pip._internal.utils.misc import hash_file from pip._internal.utils.unpacking import unpack_file + from tests.lib import DATA_DIR, TestData, assert_paths_equal from tests.lib.wheel import make_wheel diff --git a/tests/unit/test_wheel_builder.py b/tests/unit/test_wheel_builder.py index d5f372dd5cd..a657e900b42 100644 --- a/tests/unit/test_wheel_builder.py +++ b/tests/unit/test_wheel_builder.py @@ -11,6 +11,7 @@ from pip._internal.operations.build.wheel_legacy import format_command_result from pip._internal.req.req_install import InstallRequirement from pip._internal.vcs.git import Git + from tests.lib import _create_test_package diff --git a/tools/vendoring/patches/distlib.patch b/tools/vendoring/patches/distlib.patch index de2834710a3..962eab1d74f 100644 --- a/tools/vendoring/patches/distlib.patch +++ b/tools/vendoring/patches/distlib.patch @@ -5,7 +5,7 @@ index cfa45d2af..e16292b83 100644 @@ -49,6 +49,24 @@ if __name__ == '__main__': sys.exit(%(func)s()) ''' - + +# Pre-fetch the contents of all executable wrapper stubs. +# This is to address https://github.com/pypa/pip/issues/12666. +# When updating pip, we rename the old pip in place before installing the @@ -24,9 +24,22 @@ index cfa45d2af..e16292b83 100644 + if r.name.endswith(".exe") +} + - + def enquote_executable(executable): if ' ' in executable: +@@ -164,6 +164,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 @@ -409,15 +427,11 @@ class ScriptMaker(object): bits = '32' platform_suffix = '-arm' if get_platform() == 'win-arm64' else '' diff --git a/tools/vendoring/patches/packaging.patch b/tools/vendoring/patches/packaging.patch new file mode 100644 index 00000000000..1d109e55f62 --- /dev/null +++ b/tools/vendoring/patches/packaging.patch @@ -0,0 +1,122 @@ +diff --git a/src/pip/_vendor/packaging/tags.py b/src/pip/_vendor/packaging/tags.py +index 6667d2990..cb11c60b8 100644 +--- a/src/pip/_vendor/packaging/tags.py ++++ b/src/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: