From 0edb859bde3a93e437d5b8d051d79e941b3315ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Sat, 12 Sep 2026 16:00:49 +0200 Subject: [PATCH] dev-python/pip: Bump to 26.2.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Górny --- dev-python/pip/Manifest | 1 + .../pip/files/pip-26.2.1-unbundle.patch | 258 ++++++++++++++++++ dev-python/pip/pip-26.2.1.ebuild | 196 +++++++++++++ 3 files changed, 455 insertions(+) create mode 100644 dev-python/pip/files/pip-26.2.1-unbundle.patch create mode 100644 dev-python/pip/pip-26.2.1.ebuild diff --git a/dev-python/pip/Manifest b/dev-python/pip/Manifest index cc088c7b0cc9c..6a96866423bb3 100644 --- a/dev-python/pip/Manifest +++ b/dev-python/pip/Manifest @@ -1,2 +1,3 @@ DIST flit_core-3.12.0-py3-none-any.whl 45594 BLAKE2B 7c6cb6eb03d45bbba27f27b3728881b57fe82dd38e03f884d3b7c46116eb2b9dd76f92bdaf7f594ef8ccbe12ec8f9a56424ff9e9fc7a839c4818a113fdf0c3d3 SHA512 790c12b1f43201e365fb3f8f2f0a54e1a578876799dfdf8bfeea679a25ea096bf62946d006618c1458ae6e37ce6d00998f37e9aba426d5ab80d32ef2d75da4e0 DIST pip-26.1.2.gh.tar.gz 9268753 BLAKE2B 8cbf0ecf25a2bdd148506ca0e2e778b9053759cf5fed3914b915454bd8810b1d7a27e3b2efb5fd29c4e6b189c7e8050f0da15ae6c259712446b5a35f44018ee0 SHA512 e29c98a7da5e329183b7eef86a66f9d6c3473051f64aa6e762714306148547eb0de4220824484071822a9a62bd01a62a09ab16bba4c26e4b847bfc2609728608 +DIST pip-26.2.1.gh.tar.gz 9301563 BLAKE2B eb7b929de0e99c84c9b1257f1bf737f524eb6de01075d40b36519b082d8a49e107dbd0eded9a8bf737ce8f7d452c5e5cffb853b000d6ac2936b5b84dd607c770 SHA512 03a00bdc4387a4e7e4e54672e9198893500d279912ece4cd144f015c568c974ecc2c3c7bd6abf108df852302ddd49468ef0bc514ca4323ee037d754e2fbfaee0 diff --git a/dev-python/pip/files/pip-26.2.1-unbundle.patch b/dev-python/pip/files/pip-26.2.1-unbundle.patch new file mode 100644 index 0000000000000..daf4b91332e99 --- /dev/null +++ b/dev-python/pip/files/pip-26.2.1-unbundle.patch @@ -0,0 +1,258 @@ +diff --git a/src/pip/_internal/cli/main_parser.py b/src/pip/_internal/cli/main_parser.py +index 903c89112..558a0d5a0 100644 +--- a/src/pip/_internal/cli/main_parser.py ++++ b/src/pip/_internal/cli/main_parser.py +@@ -81,6 +81,11 @@ def parse_command(args: list[str]) -> tuple[str, list[str]]: + + # --python + if general_options.python and "_PIP_RUNNING_IN_SUBPROCESS" not in os.environ: ++ raise CommandError( ++ "--python option is not supported on Gentoo, as it requires bundled " ++ "dependencies that have been removed to improve security" ++ ) ++ + # Re-invoke pip using the specified Python interpreter + interpreter = identify_python_interpreter(general_options.python) + if interpreter is None: +diff --git a/src/pip/_internal/commands/debug.py b/src/pip/_internal/commands/debug.py +index 4e8178d0a..b42a12064 100644 +--- a/src/pip/_internal/commands/debug.py ++++ b/src/pip/_internal/commands/debug.py +@@ -7,7 +7,6 @@ from optparse import Values + from types import ModuleType + from typing import Any + +-import pip._vendor + from pip._vendor.certifi import where + from pip._vendor.packaging.version import parse as parse_version + +@@ -186,9 +185,7 @@ class DebugCommand(Command): + show_value("REQUESTS_CA_BUNDLE", os.environ.get("REQUESTS_CA_BUNDLE")) + show_value("CURL_CA_BUNDLE", os.environ.get("CURL_CA_BUNDLE")) + show_value("pip._vendor.certifi.where()", where()) +- show_value("pip._vendor.DEBUNDLED", pip._vendor.DEBUNDLED) +- +- show_vendor_versions() ++ show_value("pip._vendor.DEBUNDLED", True) + + show_tags(options) + +diff --git a/src/pip/_internal/commands/install.py b/src/pip/_internal/commands/install.py +index e1482b9cd..cc5758c1f 100644 +--- a/src/pip/_internal/commands/install.py ++++ b/src/pip/_internal/commands/install.py +@@ -546,13 +546,6 @@ class InstallCommand(RequirementCommand): + if options.target_dir or options.prefix_path: + warn_script_location = False + +- # Warn on late imports so we don't silently pick up a module +- # from a distribution pip is about to install. +- try: +- _eagerly_import_modules() +- finally: +- _prevent_further_imports() +- + installed = install_given_reqs( + to_install, + root=options.root_path, +diff --git a/tests/conftest.py b/tests/conftest.py +index c1a3d60ce..0b2b5fd98 100644 +--- a/tests/conftest.py ++++ b/tests/conftest.py +@@ -532,9 +532,6 @@ def virtualenv_template( + tmpdir_factory: pytest.TempPathFactory, + pip_src: Path, + pip_editable_parts: tuple[Path, ...], +- setuptools_install: Path, +- coverage_install: Path, +- socket_install: Path, + ) -> VirtualEnvironment: + venv_type: VirtualEnvironmentType + if request.config.getoption("--use-venv"): +@@ -546,13 +543,6 @@ def virtualenv_template( + tmpdir = tmpdir_factory.mktemp("virtualenv") + venv = VirtualEnvironment(tmpdir.joinpath("venv_orig"), venv_type=venv_type) + +- # Install setuptools, pytest-subket, and pip. +- install_pth_link(venv, "setuptools", setuptools_install) +- install_pth_link(venv, "pytest_subket", socket_install) +- # Also copy pytest-subket's .pth file so it can intercept socket calls. +- with open(venv.site / "pytest_socket.pth", "w") as f: +- f.write(socket_install.joinpath("pytest_socket.pth").read_text()) +- + pth, dist_info = pip_editable_parts + + shutil.copy(pth, venv.site) +@@ -564,14 +554,6 @@ def virtualenv_template( + # detects changed files. + venv.site.joinpath("easy-install.pth").touch() + +- if request.config.getoption("--cov"): +- # Install coverage and pth file for executing it in any spawned processes +- # in this virtual environment. +- install_pth_link(venv, "coverage", coverage_install) +- # zz prefix ensures the file is after easy-install.pth. +- with open(venv.site / "zz-coverage-helper.pth", "a") as f: +- f.write("import coverage; coverage.process_startup()") +- + # Drop (non-relocatable) launchers. + for exe in os.listdir(venv.bin): + if not exe.startswith(("python", "libpy")): # Don't remove libpypy-c.so... +diff --git a/tests/functional/test_check.py b/tests/functional/test_check.py +index acf99bc13..5425002e7 100644 +--- a/tests/functional/test_check.py ++++ b/tests/functional/test_check.py +@@ -10,10 +10,8 @@ from tests.lib import ( + def matches_expected_lines(string: str, expected_lines: Collection[str]) -> bool: + # Ignore empty lines + output_lines = list(filter(None, string.splitlines())) +- # We'll match the last n lines, given n lines to match. +- last_few_output_lines = output_lines[-len(expected_lines) :] + # And order does not matter +- return set(last_few_output_lines) == set(expected_lines) ++ return set(expected_lines).issubset(set(output_lines)) + + + def test_basic_check_clean(script: PipTestEnvironment) -> None: +diff --git a/tests/functional/test_freeze.py b/tests/functional/test_freeze.py +index 92e55aca6..e6d5f6d51 100644 +--- a/tests/functional/test_freeze.py ++++ b/tests/functional/test_freeze.py +@@ -75,8 +75,8 @@ def test_basic_freeze(script: PipTestEnvironment) -> None: + ) + result = script.pip("freeze", expect_stderr=True) + expected = textwrap.dedent("""\ +- ...simple==2.0 +- simple2==3.0... ++ ...simple==2.0... ++ ...simple2==3.0... + """) + _check_output(result.stdout, expected) + +@@ -881,7 +881,7 @@ def test_freeze_skip_work_dir_pkg(script: PipTestEnvironment) -> None: + + # Freeze should not include package simple when run from package directory + result = script.pip("freeze", cwd=pkg_path) +- assert "simple" not in result.stdout ++ assert "\nsimple==" not in result.stdout + + + def test_freeze_include_work_dir_pkg(script: PipTestEnvironment) -> None: +diff --git a/tests/functional/test_install_check.py b/tests/functional/test_install_check.py +index cb8312b53..174bb8f66 100644 +--- a/tests/functional/test_install_check.py ++++ b/tests/functional/test_install_check.py +@@ -61,6 +61,7 @@ def test_check_install_canonicalization(script: PipTestEnvironment) -> None: + ) + assert "requires" not in result.stderr + assert result.returncode == 0 ++ return + + # Double check that all errors are resolved in the end + result = script.pip("check") +diff --git a/tests/functional/test_list.py b/tests/functional/test_list.py +index 1acc28254..c10dd70ed 100644 +--- a/tests/functional/test_list.py ++++ b/tests/functional/test_list.py +@@ -1,5 +1,6 @@ + import json + import os ++import re + from pathlib import Path + + import pytest +@@ -43,8 +44,8 @@ def test_basic_list(simple_script: PipTestEnvironment) -> None: + + """ + result = simple_script.pip("list") +- assert "simple 1.0" in result.stdout, str(result) +- assert "simple2 3.0" in result.stdout, str(result) ++ assert re.search(r"simple\s+1\.0", result.stdout), str(result) ++ assert re.search(r"simple2\s+3\.0", result.stdout), str(result) + + + def test_verbose_flag(simple_script: PipTestEnvironment) -> None: +@@ -56,8 +57,8 @@ def test_verbose_flag(simple_script: PipTestEnvironment) -> None: + assert "Version" in result.stdout, str(result) + assert "Location" in result.stdout, str(result) + assert "Installer" in result.stdout, str(result) +- assert "simple 1.0" in result.stdout, str(result) +- assert "simple2 3.0" in result.stdout, str(result) ++ assert re.search(r"simple\s+1\.0", result.stdout), str(result) ++ assert re.search(r"simple2\s+3\.0", result.stdout), str(result) + + + def test_columns_flag(simple_script: PipTestEnvironment) -> None: +@@ -68,8 +69,8 @@ def test_columns_flag(simple_script: PipTestEnvironment) -> None: + assert "Package" in result.stdout, str(result) + assert "Version" in result.stdout, str(result) + assert "simple (1.0)" not in result.stdout, str(result) +- assert "simple 1.0" in result.stdout, str(result) +- assert "simple2 3.0" in result.stdout, str(result) ++ assert re.search(r"simple\s+1\.0", result.stdout), str(result) ++ assert re.search(r"simple2\s+3\.0", result.stdout), str(result) + + + def test_format_priority(simple_script: PipTestEnvironment) -> None: +@@ -81,16 +82,16 @@ def test_format_priority(simple_script: PipTestEnvironment) -> None: + ) + assert "simple==1.0" in result.stdout, str(result) + assert "simple2==3.0" in result.stdout, str(result) +- assert "simple 1.0" not in result.stdout, str(result) +- assert "simple2 3.0" not in result.stdout, str(result) ++ assert not re.search(r"simple\s+1\.0", result.stdout), str(result) ++ assert not re.search(r"simple2\s+3\.0", result.stdout), str(result) + + result = simple_script.pip("list", "--format=freeze", "--format=columns") + assert "Package" in result.stdout, str(result) + assert "Version" in result.stdout, str(result) + assert "simple==1.0" not in result.stdout, str(result) + assert "simple2==3.0" not in result.stdout, str(result) +- assert "simple 1.0" in result.stdout, str(result) +- assert "simple2 3.0" in result.stdout, str(result) ++ assert re.search(r"simple\s+1\.0", result.stdout), str(result) ++ assert re.search(r"simple2\s+3\.0", result.stdout), str(result) + + + def test_local_flag(simple_script: PipTestEnvironment) -> None: +@@ -126,8 +127,8 @@ def test_multiple_exclude_and_normalization( + assert "Normalizable_Name" in result.stdout + assert "pip" in result.stdout + result = script.pip("list", "--exclude", "normalizablE-namE", "--exclude", "pIp") +- assert "Normalizable_Name" not in result.stdout +- assert "pip" not in result.stdout ++ assert "Normalizable_Name " not in result.stdout ++ assert "pip " not in result.stdout + + + @pytest.mark.usefixtures("enable_user_site") +diff --git a/tests/lib/venv.py b/tests/lib/venv.py +index a5d8704b2..81438f12e 100644 +--- a/tests/lib/venv.py ++++ b/tests/lib/venv.py +@@ -9,6 +9,7 @@ import venv as _venv + from pathlib import Path + from typing import Literal + ++import pytest + import virtualenv as _virtualenv + + VirtualEnvironmentType = Literal["virtualenv", "venv"] +@@ -35,7 +36,7 @@ class VirtualEnvironment: + self._venv_type = venv_type + else: + self._venv_type = "virtualenv" +- self._user_site_packages = False ++ self._user_site_packages = True + self._template = template + self._sitecustomize: str | None = None + self._update_paths() +@@ -155,6 +156,8 @@ class VirtualEnvironment: + + @user_site_packages.setter + def user_site_packages(self, value: bool) -> None: ++ if not value: ++ pytest.skip("Gentoo: skipping due to lack of system site-packages") + self._user_site_packages = value + self._rewrite_pyvenv_cfg( + {"include-system-site-packages": str(bool(value)).lower()} diff --git a/dev-python/pip/pip-26.2.1.ebuild b/dev-python/pip/pip-26.2.1.ebuild new file mode 100644 index 0000000000000..5202b87527dc3 --- /dev/null +++ b/dev-python/pip/pip-26.2.1.ebuild @@ -0,0 +1,196 @@ +# Copyright 1999-2026 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +# please bump dev-python/ensurepip-pip along with this package! + +DISTUTILS_USE_PEP517=flit-core +PYTHON_TESTED=( python3_{12..15} ) +PYTHON_COMPAT=( "${PYTHON_TESTED[@]}" ) +PYTHON_REQ_USE="ssl(+),threads(+)" + +inherit distutils-r1 pypi shell-completion +FLIT_CORE_PV=3.12.0 + +DESCRIPTION="The PyPA recommended tool for installing Python packages" +HOMEPAGE=" + https://pip.pypa.io/en/stable/ + https://pypi.org/project/pip/ + https://github.com/pypa/pip/ +" +SRC_URI=" + https://github.com/pypa/pip/archive/${PV}.tar.gz -> ${P}.gh.tar.gz + test? ( + $(pypi_wheel_url flit-core "${FLIT_CORE_PV}") + ) +" + +LICENSE="MIT" +SLOT="0" +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~loong ~m68k ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86" +IUSE="test test-rust" +RESTRICT="!test? ( test )" + +# see src/pip/_vendor/vendor.txt +RDEPEND=" + >=dev-python/cachecontrol-0.14.3[${PYTHON_USEDEP}] + >=dev-python/dependency-groups-1.3.0[${PYTHON_USEDEP}] + >=dev-python/distlib-0.4.0[${PYTHON_USEDEP}] + >=dev-python/distro-1.9.0[${PYTHON_USEDEP}] + >=dev-python/msgpack-1.1.1[${PYTHON_USEDEP}] + >=dev-python/packaging-26.2[${PYTHON_USEDEP}] + >=dev-python/platformdirs-4.3.8[${PYTHON_USEDEP}] + >=dev-python/pyproject-hooks-1.2.0[${PYTHON_USEDEP}] + >=dev-python/requests-2.33.1[${PYTHON_USEDEP}] + >=dev-python/rich-14.1.0[${PYTHON_USEDEP}] + >=dev-python/resolvelib-1.2.0[${PYTHON_USEDEP}] + >=dev-python/setuptools-70.3.0[${PYTHON_USEDEP}] + >=dev-python/tomli-w-1.2.0[${PYTHON_USEDEP}] + >=dev-python/truststore-0.10.1[${PYTHON_USEDEP}] + >=dev-python/typing-extensions-4.13.2[${PYTHON_USEDEP}] +" +BDEPEND=" + ${RDEPEND} + test? ( + $(python_gen_cond_dep ' + dev-python/ensurepip-setuptools + dev-python/freezegun[${PYTHON_USEDEP}] + dev-python/pretend[${PYTHON_USEDEP}] + dev-python/pytest[${PYTHON_USEDEP}] + dev-python/pytest-rerunfailures[${PYTHON_USEDEP}] + dev-python/pytest-xdist[${PYTHON_USEDEP}] + dev-python/scripttest[${PYTHON_USEDEP}] + completion.bash || die + "${EPYTHON}" -c "${pipcmd}" completion --zsh > completion.zsh || die +} + +python_test() { + if ! has "${EPYTHON}" "${PYTHON_TESTED[@]/_/.}"; then + einfo "Skipping tests on ${EPYTHON}" + return 0 + fi + + local EPYTEST_DESELECT=( + tests/functional/test_inspect.py::test_inspect_basic + # Internet + tests/functional/test_config_settings.py::test_backend_sees_config_via_sdist + tests/functional/test_install.py::test_double_install_fail + tests/functional/test_install.py::test_install_sdist_links + tests/functional/test_install_config.py::test_prompt_for_keyring_if_needed + tests/functional/test_lock.py::test_lock_archive + tests/functional/test_lock.py::test_lock_vcs + # broken by system site-packages use + tests/functional/test_freeze.py::test_freeze_with_setuptools + tests/functional/test_install.py::test_install_subprocess_output_handling + tests/functional/test_pip_runner_script.py::test_runner_work_in_environments_with_no_pip + tests/functional/test_uninstall.py::test_basic_uninstall_distutils + tests/unit/test_base_command.py::test_base_command_global_tempdir_cleanup + tests/unit/test_base_command.py::test_base_command_local_tempdir_cleanup + tests/unit/test_base_command.py::test_base_command_provides_tempdir_helpers + # broken by unbundling + "tests/functional/test_debug.py::test_debug[vendored library versions:]" + tests/functional/test_debug.py::test_debug__library_versions + tests/functional/test_freeze.py::test_freeze_multiple_exclude_with_all + tests/functional/test_install.py::test_install_package_with_same_name_in_curdir + tests/functional/test_pep517.py::test_nested_builds + tests/functional/test_python_option.py::test_python_interpreter + tests/functional/test_uninstall.py::test_basic_uninstall + tests/functional/test_uninstall.py::test_uninstall_non_local_distutils + tests/functional/test_install.py::test_install_warns_on_unexpected_post_install_import + # TODO + tests/functional/test_build_env.py::test_build_env_can_still_access_python_tools_on_system_path + tests/functional/test_build_env.py::test_build_env_console_scripts_use_venv_python[subprocess] + tests/functional/test_build_env.py::test_build_env_isolation[venv-inprocess] + tests/functional/test_build_env.py::test_build_env_isolation[venv-subprocess] + tests/functional/test_build_env.py::test_build_env_requirements_check[venv] + tests/functional/test_self_update.py::test_self_update_editable + ) + local EPYTEST_IGNORE=( + # from upstream options + tests/tests_cache + # requires proxy.py + tests/functional/test_proxy.py + ) + + if ! has_version "dev-python/cryptography[${PYTHON_USEDEP}]"; then + EPYTEST_DESELECT+=( + tests/functional/test_install.py::test_install_sends_client_cert + tests/functional/test_install_config.py::test_do_not_prompt_for_authentication + tests/functional/test_install_config.py::test_prompt_for_authentication + tests/functional/test_install_config.py::test_prompt_for_keyring_if_needed + ) + fi + + local -x PIP_DISABLE_PIP_VERSION_CHECK=1 + local EPYTEST_PLUGINS=() + # rerunfailures because test suite breaks if packages are installed + # to system site-packages while it's running + local EPYTEST_RERUNS=5 + local EPYTEST_XDIST=1 + epytest -m "not network" -o addopts= -o tmp_path_retention_policy=all \ + --use-venv +} + +python_install_all() { + local DOCS=( AUTHORS.txt docs/html/**/*.rst ) + distutils-r1_python_install_all + + newbashcomp completion.bash pip + newzshcomp completion.zsh _pip +}