Compare commits

..

3 commits

Author SHA1 Message Date
Miro Hrončok
274c7d860e Security fix for the bundled urllib3 for CVE-2025-50181 2025-09-11 08:29:55 +02:00
Charalampos Stratakis
282d8747ee Fix CI tests to account for normalization of dist-info dirs (PEP 491)
setuptools now normalizes the dist-info directory names to lowercase
according to PEP 491

Also egg-info directories are not created anymore

[skip changelog]

(cherry picked from commit 97a9e3e215)
2025-09-11 08:29:55 +02:00
Charalampos Stratakis
29f78324d1 Remove testing of retired python3.8 from the CI
See https://fedoraproject.org/wiki/Changes/RetirePython3.8

[skip changelog]

(cherry picked from commit d681b5b429)
2025-09-11 08:29:55 +02:00
14 changed files with 328 additions and 569 deletions

View file

@ -1 +0,0 @@
1

2
.gitignore vendored
View file

@ -4,4 +4,4 @@
/pip/
/results_python-pip/
*.rpm
*.whl

View file

@ -1,54 +0,0 @@
From 35378ae02912d704d466e4809070e17a8d13ad0a Mon Sep 17 00:00:00 2001
From: Karolina Surma <ksurma@redhat.com>
Date: Thu, 7 Aug 2025 15:05:34 +0200
Subject: [PATCH] Downstream-Only: Remove pytest-subket from tests
---
tests/conftest.py | 17 -----------------
1 file changed, 17 deletions(-)
diff --git a/tests/conftest.py b/tests/conftest.py
index c98b871..ada7a7e 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -451,18 +451,6 @@ def coverage_install(
return _common_wheel_editable_install(tmpdir_factory, common_wheels, "coverage")
-@pytest.fixture(scope="session")
-def socket_install(tmpdir_factory: pytest.TempPathFactory, common_wheels: Path) -> Path:
- lib_dir = _common_wheel_editable_install(
- tmpdir_factory, common_wheels, "pytest_subket"
- )
- # pytest-subket is only included so it can intercept and block unexpected
- # network requests. It should NOT be visible to the pip under test.
- dist_info = next(lib_dir.glob("*.dist-info"))
- shutil.rmtree(dist_info)
- return lib_dir
-
-
def install_pth_link(
venv: VirtualEnvironment, project_name: str, lib_dir: Path
) -> None:
@@ -480,7 +468,6 @@ def virtualenv_template(
setuptools_install: Path,
wheel_install: Path,
coverage_install: Path,
- socket_install: Path,
) -> VirtualEnvironment:
venv_type: VirtualEnvironmentType
if request.config.getoption("--use-venv"):
@@ -495,10 +482,6 @@ def virtualenv_template(
# Install setuptools, wheel, pytest-subket, and pip.
install_pth_link(venv, "setuptools", setuptools_install)
install_pth_link(venv, "wheel", wheel_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
--
2.50.1

View file

@ -1,17 +1,17 @@
From 7b5fbac83944e3a0dd975ff17b69358791b68721 Mon Sep 17 00:00:00 2001
From 0741e5a665308184ddbd20900f92e4417204092f Mon Sep 17 00:00:00 2001
From: Karolina Surma <ksurma@redhat.com>
Date: Thu, 27 Jun 2024 10:38:53 +0200
Subject: [PATCH] Dummy certifi patch
---
src/pip/_vendor/certifi/core.py | 80 +++------------------------------
1 file changed, 6 insertions(+), 74 deletions(-)
src/pip/_vendor/certifi/core.py | 110 ++------------------------------
1 file changed, 6 insertions(+), 104 deletions(-)
diff --git a/src/pip/_vendor/certifi/core.py b/src/pip/_vendor/certifi/core.py
index 2f2f7e0..bec6595 100644
index 70e0c3b..eaf4210 100644
--- a/src/pip/_vendor/certifi/core.py
+++ b/src/pip/_vendor/certifi/core.py
@@ -4,80 +4,12 @@ certifi.py
@@ -4,111 +4,13 @@ certifi.py
This module returns the installation location of cacert.pem or its contents.
"""
@ -20,13 +20,13 @@ index 2f2f7e0..bec6595 100644
-def exit_cacert_ctx() -> None:
- _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr]
+# The RPM-packaged certifi always uses the system certificates
+def where() -> str:
+ return '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem'
+ return '/etc/pki/tls/certs/ca-bundle.crt'
-if sys.version_info >= (3, 11):
-
- from importlib.resources import as_file, files
-
- _CACERT_CTX = None
@ -60,7 +60,7 @@ index 2f2f7e0..bec6595 100644
- def contents() -> str:
- return files("pip._vendor.certifi").joinpath("cacert.pem").read_text(encoding="ascii")
-
-else:
-elif sys.version_info >= (3, 7):
-
- from importlib.resources import path as get_path, read_text
-
@ -95,9 +95,40 @@ index 2f2f7e0..bec6595 100644
-
- def contents() -> str:
- return read_text("pip._vendor.certifi", "cacert.pem", encoding="ascii")
-
-else:
- import os
- import types
- from typing import Union
-
- Package = Union[types.ModuleType, str]
- Resource = Union[str, "os.PathLike"]
-
- # This fallback will work for Python versions prior to 3.7 that lack the
- # importlib.resources module but relies on the existing `where` function
- # so won't address issues with environments like PyOxidizer that don't set
- # __file__ on modules.
- def read_text(
- package: Package,
- resource: Resource,
- encoding: str = 'utf-8',
- errors: str = 'strict'
- ) -> str:
- with open(where(), encoding=encoding) as data:
- return data.read()
-
- # If we don't have importlib.resources, then we will just do the old logic
- # of assuming we're on the filesystem and munge the path directly.
- def where() -> str:
- f = os.path.dirname(__file__)
-
- return os.path.join(f, "cacert.pem")
-
- def contents() -> str:
- return read_text("pip._vendor.certifi", "cacert.pem", encoding="ascii")
+def contents() -> str:
+ with open(where(), encoding='utf=8') as data:
+ return data.read()
--
2.50.1
2.45.1

View file

@ -0,0 +1,79 @@
From 9d1e0a0e91cad143702b3a2d8c54bd765a5d9eb2 Mon Sep 17 00:00:00 2001
From: Karolina Surma <ksurma@redhat.com>
Date: Thu, 27 Jun 2024 10:48:03 +0200
Subject: [PATCH] Don't warn the user about pip._internal.main() entrypoint
In Fedora, we use that in ensurepip and users cannot do anything about it,
this warning is juts moot. Also, the warning breaks CPython test suite.
Co-Authored-By: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
---
src/pip/_internal/__init__.py | 2 +-
src/pip/_internal/utils/entrypoints.py | 19 ++++++++++---------
tests/functional/test_cli.py | 3 ++-
3 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/src/pip/_internal/__init__.py b/src/pip/_internal/__init__.py
index 1a5b7f8..682b9e4 100755
--- a/src/pip/_internal/__init__.py
+++ b/src/pip/_internal/__init__.py
@@ -15,4 +15,4 @@ def main(args: Optional[List[str]] = None) -> int:
"""
from pip._internal.utils.entrypoints import _wrapper
- return _wrapper(args)
+ return _wrapper(args, _nowarn=True)
diff --git a/src/pip/_internal/utils/entrypoints.py b/src/pip/_internal/utils/entrypoints.py
index 1501369..70034eb 100644
--- a/src/pip/_internal/utils/entrypoints.py
+++ b/src/pip/_internal/utils/entrypoints.py
@@ -20,7 +20,7 @@ if WINDOWS:
]
-def _wrapper(args: Optional[List[str]] = None) -> int:
+def _wrapper(args: Optional[List[str]] = None, _nowarn: bool = False) -> int:
"""Central wrapper for all old entrypoints.
Historically pip has had several entrypoints defined. Because of issues
@@ -32,14 +32,15 @@ def _wrapper(args: Optional[List[str]] = None) -> int:
directing them to an appropriate place for help, we now define all of
our old entrypoints as wrappers for the current one.
"""
- sys.stderr.write(
- "WARNING: pip is being invoked by an old script wrapper. This will "
- "fail in a future version of pip.\n"
- "Please see https://github.com/pypa/pip/issues/5599 for advice on "
- "fixing the underlying issue.\n"
- "To avoid this problem you can invoke Python with '-m pip' instead of "
- "running pip directly.\n"
- )
+ if not _nowarn:
+ sys.stderr.write(
+ "WARNING: pip is being invoked by an old script wrapper. This will "
+ "fail in a future version of pip.\n"
+ "Please see https://github.com/pypa/pip/issues/5599 for advice on "
+ "fixing the underlying issue.\n"
+ "To avoid this problem you can invoke Python with '-m pip' instead of "
+ "running pip directly.\n"
+ )
return main(args)
diff --git a/tests/functional/test_cli.py b/tests/functional/test_cli.py
index e1ccf04..30b8f74 100644
--- a/tests/functional/test_cli.py
+++ b/tests/functional/test_cli.py
@@ -49,7 +49,8 @@ def test_entrypoints_work(entrypoint: str, script: PipTestEnvironment) -> None:
result = script.pip("-V")
result2 = script.run("fake_pip", "-V", allow_stderr_warning=True)
assert result.stdout == result2.stdout
- assert "old script wrapper" in result2.stderr
+ if entrypoint[0] != "fake_pip = pip._internal:main":
+ assert "old script wrapper" in result2.stderr
@pytest.mark.parametrize(
--
2.45.1

111
plan.fmf
View file

@ -1,111 +0,0 @@
execute:
how: tmt
discover:
- name: tests_python
how: shell
url: https://src.fedoraproject.org/tests/python.git
tests:
- name: smoke36
path: /smoke
test: VERSION=3.6 TOX=false ./venv.sh
- name: smoke39
path: /smoke
test: VERSION=3.9 ./venv.sh
- name: smoke310
path: /smoke
test: VERSION=3.10 ./venv.sh
- name: smoke311
path: /smoke
test: VERSION=3.11 ./venv.sh
- name: smoke312
path: /smoke
test: VERSION=3.12 ./venv.sh
- name: smoke313
path: /smoke
test: VERSION=3.13 ./venv.sh
- name: smoke314
path: /smoke
test: VERSION=3.14 ./venv.sh
- name: smoke315
path: /smoke
test: VERSION=3.15 ./venv.sh
- name: smoke39_virtualenv
path: /smoke
test: VERSION=3.9 METHOD=virtualenv ./venv.sh
- name: smoke310_virtualenv
path: /smoke
test: VERSION=3.10 METHOD=virtualenv ./venv.sh
- name: smoke311_virtualenv
path: /smoke
test: VERSION=3.11 METHOD=virtualenv ./venv.sh
- name: smoke312_virtualenv
path: /smoke
test: VERSION=3.12 METHOD=virtualenv ./venv.sh
- name: smoke313_virtualenv
path: /smoke
test: VERSION=3.13 METHOD=virtualenv ./venv.sh
- name: smoke314_virtualenv
path: /smoke
test: VERSION=3.14 METHOD=virtualenv ./venv.sh
- name: smoke315_virtualenv
path: /smoke
test: VERSION=3.15 METHOD=virtualenv ./venv.sh
- name: rpms_pyproject-rpm-macros
how: shell
url: https://src.fedoraproject.org/rpms/pyproject-rpm-macros.git
tests:
- name: pyproject_pytest
path: /tests
test: ./mocktest.sh python-pytest
- name: pyproject_entrypoints
path: /tests
test: ./mocktest.sh python-entrypoints
- name: pyproject_pluggy
path: /tests
test: ./mocktest.sh python-pluggy
- name: pyproject_clikit
path: /tests
test: ./mocktest.sh python-clikit
- name: same_repo
how: shell
dist-git-source: true
dist-git-download-only: true
tests:
- name: mock_bootstrap_build
test: |
cd $TMT_SOURCE_DIR &&
$TMT_TREE/../discover/rpms_pyproject-rpm-macros/tests/tests/mocktest.sh python-pip --without tests --without man
- name: pip_install_upgrade
path: /tests/pip_install_upgrade/
test: ./runtest.sh
- name: bash_completion
path: /tests/bash_completion
test: ./pip_completion_full_test.sh
prepare:
- name: Install dependencies
how: install
package:
- gcc
- virtualenv
- python3.6-devel
- python3.9-devel
- python3.10-devel
- python3.11-devel
- python3.12-devel
- python3.13-devel
- python3.14-devel
- python3.15-devel
- python3-devel
- python3-tox
- mock
- rpmdevtools
- rpm-build
- grep
- util-linux
- shadow-utils
- expect
- dnf
- name: Update packages
how: shell
script: dnf upgrade -y

View file

@ -7,3 +7,6 @@ addFilter(r'non-executable-script .+/pip/_vendor/distro/distro.py\b')
# We ship README with the main package but not with the wheel
addFilter(r'python-pip-wheel.noarch: W: no-documentation')
# Spelling errors
addFilter(r"E: spelling-error .+'venv'")

View file

@ -1,12 +1,12 @@
# The original RHEL N+1 content set is defined by (build)dependencies
# of the packages in Fedora ELN. Hence we disable tests here
# of the packages in Fedora ELN. Hence we disable tests and documentation here
# to prevent pulling many unwanted packages in.
%bcond tests %{defined fedora}
# Whether to build the manual pages (useful for bootstrapping Sphinx)
%bcond man 1
# We intentionally keep this enabled on EPEL.
%bcond tests %[%{defined fedora} || %{defined epel}]
%bcond doc %[%{defined fedora} || %{defined epel}]
%global srcname pip
%global base_version 25.3
%global base_version 24.3.1
%global upstream_version %{base_version}%{?prerel}
%global python_wheel_name %{srcname}-%{upstream_version}-py3-none-any.whl
@ -20,7 +20,6 @@ Summary: A tool for installing and managing Python packages
# certifi: MPL-2.0
# CacheControl: Apache-2.0
# dependency-groups: MIT
# distlib: Python-2.0.1
# distro: Apache-2.0
# idna: BSD-3-Clause
@ -35,39 +34,13 @@ Summary: A tool for installing and managing Python packages
# setuptools: MIT
# truststore: MIT
# tomli: MIT
# tomli-w: MIT
# typing-extensions: Python-2.0.1
# urllib3: MIT
License: MIT AND Python-2.0.1 AND Apache-2.0 AND BSD-2-Clause AND BSD-3-Clause AND ISC AND MPL-2.0 AND (Apache-2.0 OR BSD-2-Clause)
URL: https://pip.pypa.io/
Source0: https://github.com/pypa/pip/archive/%{upstream_version}/%{srcname}-%{upstream_version}.tar.gz
# The following sources are wheels used only for tests.
# They are not bundled in the built package and do not contribute to the overall license.
# They are pre-built but only contain text files, rebuilding them in %%build has very little benefit.
# setuptools.whl
# We cannot use RPM-packaged python-setuptools-wheel because upstream pins to <80.
# See https://github.com/pypa/pip/pull/13357 for rationale.
Source1: https://files.pythonhosted.org/packages/0d/6d/b4752b044bf94cb802d88a888dc7d288baaf77d7910b7dedda74b5ceea0c/setuptools-79.0.1-py3-none-any.whl
# wheel.whl
# We cannot use RPM-packaged python-wheel-wheel because we intent to drop that package in wheel 0.46+.
# That version of wheel has runtime dependencies and is generally useless as a standalone wheel.
# See https://github.com/pypa/pip/pull/13382 as an attempt to drop the requirement from pip tests.
Source2: https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl
# flit_core.whl
# This is not built as RPM-packaged wheel in Fedora at all.
Source3: https://files.pythonhosted.org/packages/f2/65/b6ba90634c984a4fcc02c7e3afe523fef500c4980fec67cc27536ee50acf/flit_core-3.12.0-py3-none-any.whl
# coverage.whl
# There is no RPM-packaged python-coverage-wheel, the package is archful.
# Upstream uses this to measure coverage, which we don't.
# This is a dummy placeholder package that only contains empty coverage.process_startup().
# That way, we don't need to patch the usage out of conftest.py.
Source4: coverage-0-py3-none-any.whl
BuildArch: noarch
%if %{with tests}
@ -75,15 +48,8 @@ BuildRequires: /usr/bin/git
BuildRequires: /usr/bin/hg
BuildRequires: /usr/bin/bzr
BuildRequires: /usr/bin/svn
BuildRequires: python%{python3_pkgversion}-pytest-xdist
%endif
%if %{with man}
# docs/requirements.txt contains many sphinx extensions
# however, we only build the manual pages thanks to
# https://github.com/pypa/pip/pull/13168
# We also always use the "main" Sphinx, not python%%{python3_pkgversion}-sphinx
BuildRequires: python3-sphinx
BuildRequires: python-setuptools-wheel
BuildRequires: python-wheel-wheel
%endif
# Prevent removing of the system packages installed under /usr/lib
@ -97,10 +63,10 @@ Patch: remove-existing-dist-only-if-path-conflicts.patch
# The same patch is a part of the RPM-packaged python-certifi
Patch: dummy-certifi.patch
# pytest-subket has been introduced to intercept network calls
# https://github.com/pypa/pip/commit/a4b40f62332ccb3228b12cc5ae1493c75177247a
# We don't need a layer to check that, as we're by default in an offline environment
Patch: downstream-remove-pytest-subket.patch
# Don't warn the user about pip._internal.main() entrypoint
# In Fedora, we use that in ensurepip and users cannot do anything about it,
# this warning is juts moot. Also, the warning breaks CPython test suite.
Patch: nowarn-pip._internal.main.patch
# Patch for the bundled urllib3 for CVE-2025-50181
# Redirects are not disabled when retries are disabled on PoolManager instantiation
@ -123,24 +89,23 @@ Packages" or "Pip Installs Python".
# You can generate it with:
# %%{_rpmconfigdir}/pythonbundles.py --namespace 'python%%{1}dist' src/pip/_vendor/vendor.txt
%global bundled() %{expand:
Provides: bundled(python%{1}dist(cachecontrol)) = 0.14.3
Provides: bundled(python%{1}dist(certifi)) = 2025.10.5
Provides: bundled(python%{1}dist(dependency-groups)) = 1.3.1
Provides: bundled(python%{1}dist(distlib)) = 0.4
Provides: bundled(python%{1}dist(cachecontrol)) = 0.14
Provides: bundled(python%{1}dist(certifi)) = 2024.8.30
Provides: bundled(python%{1}dist(distlib)) = 0.3.9
Provides: bundled(python%{1}dist(distro)) = 1.9
Provides: bundled(python%{1}dist(idna)) = 3.10
Provides: bundled(python%{1}dist(msgpack)) = 1.1.2
Provides: bundled(python%{1}dist(packaging)) = 25
Provides: bundled(python%{1}dist(platformdirs)) = 4.5
Provides: bundled(python%{1}dist(pygments)) = 2.19.2
Provides: bundled(python%{1}dist(pyproject-hooks)) = 1.2
Provides: bundled(python%{1}dist(requests)) = 2.32.5
Provides: bundled(python%{1}dist(resolvelib)) = 1.2.1
Provides: bundled(python%{1}dist(rich)) = 14.2
Provides: bundled(python%{1}dist(idna)) = 3.7
Provides: bundled(python%{1}dist(msgpack)) = 1.0.8
Provides: bundled(python%{1}dist(packaging)) = 24.1
Provides: bundled(python%{1}dist(platformdirs)) = 4.2.2
Provides: bundled(python%{1}dist(pygments)) = 2.18
Provides: bundled(python%{1}dist(pyproject-hooks)) = 1
Provides: bundled(python%{1}dist(requests)) = 2.32.3
Provides: bundled(python%{1}dist(resolvelib)) = 1.0.1
Provides: bundled(python%{1}dist(rich)) = 13.7.1
Provides: bundled(python%{1}dist(setuptools)) = 70.3
Provides: bundled(python%{1}dist(tomli)) = 2.3
Provides: bundled(python%{1}dist(tomli-w)) = 1.2
Provides: bundled(python%{1}dist(truststore)) = 0.10.4
Provides: bundled(python%{1}dist(tomli)) = 2.0.1
Provides: bundled(python%{1}dist(truststore)) = 0.10
Provides: bundled(python%{1}dist(typing-extensions)) = 4.12.2
Provides: bundled(python%{1}dist(urllib3)) = 1.26.20
}
@ -175,15 +140,17 @@ BuildRequires: python%{python3_pkgversion}-devel
# The minimal version is for bundled provides verification script
BuildRequires: python3-rpm-generators >= 11-8
BuildRequires: pyproject-rpm-macros
BuildRequires: python%{python3_pkgversion}-flit-core
BuildRequires: python%{python3_pkgversion}-setuptools
BuildRequires: python%{python3_pkgversion}-wheel
BuildRequires: bash-completion
BuildRequires: ca-certificates
Requires: ca-certificates
# Virtual provides for the packages bundled by pip:
%{bundled %{python3_pkgversion}}
%{bundled 3}
Provides: pip = %{version}-%{release}
Conflicts: python-pip < %{version}-%{release}
%description -n python%{python3_pkgversion}-%{srcname}
pip is a package management system used to install and manage software packages
@ -191,13 +158,26 @@ written in Python. Many packages can be found in the Python Package Index
(PyPI). pip is a recursive acronym that can stand for either "Pip Installs
Packages" or "Pip Installs Python".
%if %{with doc}
%package doc
Summary: A documentation for a tool for installing and managing Python packages
BuildRequires: python%{python3_pkgversion}-sphinx
BuildRequires: python%{python3_pkgversion}-sphinx-inline-tabs
BuildRequires: python%{python3_pkgversion}-sphinx-copybutton
BuildRequires: python%{python3_pkgversion}-myst-parser
%description doc
A documentation for a tool for installing and managing Python packages
%endif
%package -n %{python_wheel_pkg_prefix}-%{srcname}-wheel
Summary: The pip wheel
Requires: ca-certificates
# Virtual provides for the packages bundled by pip:
%{bundled %{python3_pkgversion}}
%{bundled 3}
# This is only relevant for Pythons that are older than 3.12 and don't use their own bundled wheels
# It is also only relevant when this wheel is shared across multiple Pythons
@ -205,6 +185,8 @@ Requires: ca-certificates
%{crypt_compat_recommends 3.11}
%{crypt_compat_recommends 3.10}
%{crypt_compat_recommends 3.9}
%{crypt_compat_recommends 3.8}
%{crypt_compat_recommends 3.7}
%endif
%description -n %{python_wheel_pkg_prefix}-%{srcname}-wheel
@ -216,28 +198,33 @@ A Python wheel of pip to use with venv.
# this goes together with patch4
rm src/pip/_vendor/certifi/*.pem
# Do not use furo as HTML theme in docs
# furo is not available in Fedora
sed -i '/html_theme = "furo"/d' docs/html/conf.py
# towncrier extension for Sphinx is not yet available in Fedora
sed -i '/"sphinxcontrib.towncrier",/d' docs/html/conf.py
# tests expect wheels in here
ln -s %{python_wheel_dir} tests/data/common_wheels
# Remove windows executable binaries
rm -v src/pip/_vendor/distlib/*.exe
sed -i '/\.exe/d' pyproject.toml
# Remove RIGHT-TO-LEFT OVERRIDE from AUTHORS.txt
# https://github.com/pypa/pip/pull/12046
%{python3} -c 'from pathlib import Path; p = Path("AUTHORS.txt"); p.write_text("".join(c for c in p.read_text() if c != "\u202e"))'
# Remove unused test requirements
sed -Ei '/(pytest-(cov|xdist|rerunfailures|subket)|proxy\.py)/d' pyproject.toml
# Remove unused pytest-subket options
sed -Ei '/(--disable-socket|--allow-unix-socket|--allow-hosts=localhost)/d' pyproject.toml
%if %{with tests}
# tests expect wheels in here
mkdir tests/data/common_wheels
cp -a %{SOURCE1} %{SOURCE2} %{SOURCE3} %{SOURCE4} tests/data/common_wheels
%endif
sed -Ei '/(pytest-(cov|xdist|rerunfailures)|proxy\.py)/d' tests/requirements.txt
%if %{with tests}
%generate_buildrequires
# we only use this to generate test requires
# the "pyproject" part is explicitly disabled as it generates a requirement on pip
%pyproject_buildrequires -N -g test
%pyproject_buildrequires -N tests/requirements.txt
%endif
@ -245,8 +232,11 @@ cp -a %{SOURCE1} %{SOURCE2} %{SOURCE3} %{SOURCE4} tests/data/common_wheels
export PYTHONPATH=./src/
%pyproject_wheel
%if %{with man}
sphinx-build -t man -b man -d docs/build/doctrees/man -c docs/html docs/man docs/build/man
%if %{with doc}
# from tox.ini
sphinx-build-3 -b html docs/html docs/build/html
sphinx-build-3 -b man docs/man docs/build/man -c docs/html
rm -rf docs/build/html/{.doctrees,.buildinfo}
%endif
@ -255,28 +245,13 @@ export PYTHONPATH=./src/
%pyproject_install
%pyproject_save_files -l pip
# We'll install pip as pip3.X
# Later we'll provide symbolic links, manpage links and bashcompletion fixes for alternative names
%if "%{python3_pkgversion}" == "3"
%global alternate_names pip-%{python3_version} pip-3 pip3 pip
%else
%global alternate_names pip-%{python3_version}
%endif
# Provide symlinks to executables
mv %{buildroot}%{_bindir}/pip %{buildroot}%{_bindir}/pip%{python3_version}
rm %{buildroot}%{_bindir}/pip3
for pip in %{alternate_names}; do
ln -s ./pip%{python3_version} %{buildroot}%{_bindir}/$pip
done
%if %{with man}
%if %{with doc}
pushd docs/build/man
install -d %{buildroot}%{_mandir}/man1
for MAN in *1; do
install -pm0644 $MAN %{buildroot}%{_mandir}/man1/${MAN/pip/pip%{python3_version}}
for pip in %{alternate_names}; do
echo ".so ${MAN/pip/pip%{python3_version}}" > %{buildroot}%{_mandir}/man1/${MAN/pip/$pip}
install -pm0644 $MAN %{buildroot}%{_mandir}/man1/$MAN
for pip in "pip3" "pip-3" "pip%{python3_version}" "pip-%{python3_version}"; do
echo ".so $MAN" > %{buildroot}%{_mandir}/man1/${MAN/pip/$pip}
done
done
popd
@ -284,18 +259,22 @@ popd
mkdir -p %{buildroot}%{bash_completions_dir}
PYTHONPATH=%{buildroot}%{python3_sitelib} \
%{buildroot}%{_bindir}/pip%{python3_version} completion --bash \
> %{buildroot}%{bash_completions_dir}/pip%{python3_version}
%{buildroot}%{_bindir}/pip completion --bash \
> %{buildroot}%{bash_completions_dir}/pip3
# Make bash completion apply to all the 5 symlinks we install
sed -i -e "s/^\\(complete.*\\) pip\$/\\1 pip pip{,-}{3,%{python3_version}}/" \
-e s/_pip_completion/_pip3_completion/ \
%{buildroot}%{bash_completions_dir}/pip3
# Provide symlinks to executables to comply with Fedora guidelines for Python
ln -s ./pip%{python3_version} %{buildroot}%{_bindir}/pip-%{python3_version}
ln -s ./pip-%{python3_version} %{buildroot}%{_bindir}/pip-3
# Make bash completion apply to all alternate names symlinks we install
sed -i -e "s/^\\(complete.*\\) pip%{python3_version}\$/\\1 pip%{python3_version} %{alternate_names}/" \
-e s/_pip_completion/_pip%{python3_version_nodots}_completion/ \
%{buildroot}%{bash_completions_dir}/pip%{python3_version}
# Install the built wheel and inject SBOM into it (if the macro is available)
mkdir -p %{buildroot}%{python_wheel_dir}
install -p %{_pyproject_wheeldir}/%{python_wheel_name} -t %{buildroot}%{python_wheel_dir}
%{?python_wheel_inject_sbom:%python_wheel_inject_sbom %{buildroot}%{python_wheel_dir}/%{python_wheel_name}}
%check
@ -307,51 +286,48 @@ grep "exe$" %{pyproject_files} && exit 1 || true
grep "pem$" %{pyproject_files} && exit 1 || true
# Verify we can at least run basic commands without crashing
%{py3_test_envvars} %{buildroot}%{_bindir}/pip%{python3_version} --help
%{py3_test_envvars} %{buildroot}%{_bindir}/pip%{python3_version} list
%{py3_test_envvars} %{buildroot}%{_bindir}/pip%{python3_version} show pip
%{py3_test_envvars} %{buildroot}%{_bindir}/pip --help
%{py3_test_envvars} %{buildroot}%{_bindir}/pip list
%{py3_test_envvars} %{buildroot}%{_bindir}/pip show pip
%if %{with tests}
# Upstream tests
# bash completion tests only work from installed package
pytest_k='not completion'
# this clashes with our PYTHONPATH
pytest_k="$pytest_k and not environments_with_no_pip"
# this seems to require internet (despite no network marker)
# added in https://github.com/pypa/pip/pull/13378 TODO drop this in the next release
pytest_k="$pytest_k and not test_prompt_for_keyring_if_needed and not test_double_install_fail and not test_install_sdist_links and not test_lock_vcs and not test_lock_archive and not test_backend_sees_config_via_sdist"
# this cannot import breezy, TODO investigate
pytest_k="$pytest_k and not (functional and bazaar)"
# failures to investigate
pytest_k="$pytest_k and not test_all_fields and not test_report_mixed_not_found and not test_basic_show" # "Editable project location" missing
pytest_k="$pytest_k and not test_basic_install_from_wheel"
pytest_k="$pytest_k and not test_check_unsupported"
%pytest -n auto -m 'not network' -k "$(echo $pytest_k)" \
--ignore tests/functional/test_proxy.py # no proxy.py in Fedora
# --ignore'd tests are not compatible with the latest virtualenv
# These files contain almost 500 tests so we should enable them back
# as soon as pip will be compatible upstream
# https://github.com/pypa/pip/pull/8441
# among them, tests/functional/test_proxy.py needs proxy.py which is not
# yet packaged in Fedora
%pytest -m 'not network' -k "$(echo $pytest_k)" \
--ignore tests/functional --ignore tests/lib/test_lib.py
%endif
%files -n python%{python3_pkgversion}-%{srcname} -f %{pyproject_files}
%doc README.rst
%if %{with man}
%if "%{python3_pkgversion}" == "3"
%{_mandir}/man1/pip{,3,-3}.1.*
%{_mandir}/man1/pip{,3,-3}-[^3]*.1.*
%if %{with doc}
%{_mandir}/man1/pip.*
%{_mandir}/man1/pip-*.*
%{_mandir}/man1/pip3.*
%{_mandir}/man1/pip3-*.*
%endif
%{_mandir}/man1/pip{,-}%{python3_version}.1.*
%{_mandir}/man1/pip{,-}%{python3_version}-*.1.*
%endif
%if "%{python3_pkgversion}" == "3"
%{_bindir}/pip
%{_bindir}/pip3
%{_bindir}/pip-3
%endif
%{_bindir}/pip%{python3_version}
%{_bindir}/pip-%{python3_version}
%dir %{bash_completions_dir}
%{bash_completions_dir}/pip%{python3_version}
%{bash_completions_dir}/pip3
%if %{with doc}
%files doc
%license LICENSE.txt
%doc README.rst
%doc docs/build/html
%endif
%files -n %{python_wheel_pkg_prefix}-%{srcname}-wheel
%license LICENSE.txt

View file

@ -1,11 +1,8 @@
From d5cb806a14bb50a96484bca6536e81f2ac316b9d Mon Sep 17 00:00:00 2001
From 9020f56e88a7dbaef688c147c281909f95b4e1d1 Mon Sep 17 00:00:00 2001
From: Karolina Surma <ksurma@redhat.com>
Date: Wed, 16 Feb 2022 08:36:21 +0100
Subject: [PATCH] Prevent removing of the system packages installed under
/usr/lib when pip install --upgrade is executed.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Resolves: rhbz#1550368
@ -15,6 +12,7 @@ Co-Authored-By: Petr Viktorin <pviktori@redhat.com>
Co-Authored-By: Lumir Balhar <lbalhar@redhat.com>
Co-Authored-By: Miro Hrončok <miro@hroncok.cz>
Co-Authored-By: Karolina Surma <ksurma@redhat.com>
---
src/pip/_internal/metadata/base.py | 12 +++++++++++-
src/pip/_internal/req/req_install.py | 2 +-
@ -23,10 +21,10 @@ Co-Authored-By: Karolina Surma <ksurma@redhat.com>
4 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/src/pip/_internal/metadata/base.py b/src/pip/_internal/metadata/base.py
index 230e114..8bd5d31 100644
index 9eabcdb..9816691 100644
--- a/src/pip/_internal/metadata/base.py
+++ b/src/pip/_internal/metadata/base.py
@@ -23,7 +23,7 @@ from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
@@ -28,7 +28,7 @@ from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
from pip._vendor.packaging.version import Version
from pip._internal.exceptions import NoneMetadataError
@ -35,7 +33,7 @@ index 230e114..8bd5d31 100644
from pip._internal.models.direct_url import (
DIRECT_URL_METADATA_NAME,
DirectUrl,
@@ -575,6 +575,16 @@ class BaseDistribution(Protocol):
@@ -578,6 +578,16 @@ class BaseDistribution(Protocol):
for extra in self._iter_egg_info_extras():
metadata["Provides-Extra"] = extra
@ -53,10 +51,10 @@ index 230e114..8bd5d31 100644
class BaseEnvironment:
"""An environment containing distributions to introspect."""
diff --git a/src/pip/_internal/req/req_install.py b/src/pip/_internal/req/req_install.py
index c9f6bff..c101826 100644
index 2132785..0340890 100644
--- a/src/pip/_internal/req/req_install.py
+++ b/src/pip/_internal/req/req_install.py
@@ -453,7 +453,7 @@ class InstallRequirement:
@@ -449,7 +449,7 @@ class InstallRequirement:
f"lack sys.path precedence to {existing_dist.raw_name} "
f"in {existing_dist.location}"
)
@ -66,10 +64,10 @@ index c9f6bff..c101826 100644
else:
if self.editable:
diff --git a/src/pip/_internal/resolution/legacy/resolver.py b/src/pip/_internal/resolution/legacy/resolver.py
index 33a4fdc..1fe886e 100644
index 1dd0d70..414bdbe 100644
--- a/src/pip/_internal/resolution/legacy/resolver.py
+++ b/src/pip/_internal/resolution/legacy/resolver.py
@@ -322,7 +322,9 @@ class Resolver(BaseResolver):
@@ -319,7 +319,9 @@ class Resolver(BaseResolver):
# Don't uninstall the conflict if doing a user install and the
# conflict is not a user install.
assert req.satisfied_by is not None
@ -81,19 +79,19 @@ index 33a4fdc..1fe886e 100644
req.satisfied_by = None
diff --git a/src/pip/_internal/resolution/resolvelib/factory.py b/src/pip/_internal/resolution/resolvelib/factory.py
index f23e4cd..1bada79 100644
index 1f31d83..3804774 100644
--- a/src/pip/_internal/resolution/resolvelib/factory.py
+++ b/src/pip/_internal/resolution/resolvelib/factory.py
@@ -3,6 +3,8 @@ from __future__ import annotations
@@ -1,6 +1,8 @@
import contextlib
import functools
import logging
+import sys
+import sysconfig
from collections.abc import Iterable, Iterator, Mapping, Sequence
from typing import (
TYPE_CHECKING,
@@ -615,6 +617,16 @@ class Factory:
Callable,
@@ -617,6 +619,16 @@ class Factory:
if dist is None: # Not installed, no uninstallation required.
return None
@ -111,5 +109,5 @@ index f23e4cd..1bada79 100644
# be uninstalled, no matter it's in global or user site, because the
# user site installation has precedence over global.
--
2.50.1
2.45.1

View file

@ -1,5 +1 @@
SHA512 (pip-25.3.tar.gz) = f50db092213ec3bb819d3da5669f73d119b5ec7f7ac5e8a587a17c27eafa32bc17a057df09389c526a3769ef3577f5553187d54ceffa89aed63f4b4498ff044e
SHA512 (setuptools-79.0.1-py3-none-any.whl) = fef6cfc6f95a5bb7320f1680e1c665cb8d9a4e4227cde4d8aab8a50bed4bcf04320085b9d7d5343359f887008db5c5a861e57f3d08b7b0b2311a28adaeee6b4a
SHA512 (wheel-0.45.1-py3-none-any.whl) = 86c16248ec804ee0ac95d43b03d47351dceb534d0cdc4025ca1eb073e39e539de44c870b9261f0373144e1537f0e42675a759a318a8d5d346bbd9efcb704061d
SHA512 (flit_core-3.12.0-py3-none-any.whl) = 790c12b1f43201e365fb3f8f2f0a54e1a578876799dfdf8bfeea679a25ea096bf62946d006618c1458ae6e37ce6d00998f37e9aba426d5ab80d32ef2d75da4e0
SHA512 (coverage-0-py3-none-any.whl) = e734192565347010efe68f8ba600254259c9b647f3c553fd4e5d87b1d7f955cb15d6f7d807716f4a6415d239beed945fbec7210feaf502e9cc849c332845926e
SHA512 (pip-24.3.1.tar.gz) = 9cf5f18eefd559cf27bc026e5206b0028ea77fd904a61fea9a6682b519305c962dd19170b841581bd05ff72192a9c458ec0eba173fa66db0438b046111ff5856

View file

@ -1,35 +0,0 @@
summary: PIP bash completion functionality smoke test
description: |
Comprehensive test for pip bash completion functionality on Fedora/RHEL systems.
The test performs the following steps:
1. Finds the bash completion script in the given (e.g. python3-pip) RPM package
2. Discovers all pip executables in the package (e.g. /usr/bin/pip and /usr/bin/pip3.14)
3. Sources the completion script and verifies completion for all executables is registered
4. Runs functional TAB completion tests using expect (for regular and POSIX mode of Bash)
5. Validates that completion works for basic pip commands
This is a smoke test to ensure pip bash completion is properly
installed and functional after package installation.
component:
- python3-pip
test: ./pip_completion_full_test.sh
framework: shell
duration: 5m
tier: 1
require:
- python3-pip
- bash-completion
- expect
- rpm
- bash
environment:
PACKAGE: python3-pip

View file

@ -1,88 +0,0 @@
#!/bin/bash
# Comprehensive PIP bash completion test for RHEL
# Finds completion scripts from RPM, tests all pip binaries, and runs functional tests
PACKAGE="${PACKAGE:-python3-pip}"
# Step 1: Find bash completion scripts in python3-pip RPM package
echo "Step 1: Finding bash completion scripts in $PACKAGE RPM package..."
COMPLETION_FILE=$(rpm -ql $PACKAGE 2>/dev/null | grep -E "/usr/share/bash-completion/completions/" || true)
if [[ -z "$COMPLETION_FILE" ]]; then
echo "✗ No bash completion files found in $PACKAGE package"
exit 1
fi
# Check if there's exactly one completion file
COMPLETION_FILE_COUNT=$(echo "$COMPLETION_FILE" | wc -l)
if [[ $COMPLETION_FILE_COUNT -gt 1 ]]; then
echo "✗ Multiple bash completion files found in $PACKAGE package:"
echo "$COMPLETION_FILE" | sed 's/^/ - /'
echo "Expected exactly one completion file, found $COMPLETION_FILE_COUNT"
exit 1
fi
echo "✓ Found completion file from $PACKAGE package:"
echo "$COMPLETION_FILE" | sed 's/^/ - /'
# Step 2: Find all pip binaries
echo
echo "Step 2: Finding all pip binaries..."
PIP_BINARIES=()
PIP_FILES=$(rpm -ql $PACKAGE | grep /bin/p)
for pip_file in $PIP_FILES; do
if [[ -x "$pip_file" ]]; then
pip_cmd=$(basename "$pip_file")
PIP_BINARIES+=("$pip_cmd")
echo "✓ Found: $pip_cmd -> $pip_file"
fi
done
if [[ ${#PIP_BINARIES[@]} -eq 0 ]]; then
echo "✗ No pip binaries found"
exit 1
fi
echo "Total pip binaries found: ${#PIP_BINARIES[@]}"
# Step 3: Source completion scripts and test each binary
echo
echo "Step 3: Testing completion for each pip binary..."
for AS_POSIX in 0 1; do
if [[ $AS_POSIX -eq 1 ]]; then
echo "Testing in POSIX mode"
POSIX="--posix"
else
echo "Testing in non-POSIX mode"
POSIX=""
fi
echo "Sourcing: $COMPLETION_FILE"
if bash --norc $POSIX -c "source $COMPLETION_FILE" ; then
echo "✓ Successfully sourced $COMPLETION_FILE"
else
echo "! Warning: Failed to source $COMPLETION_FILE"
exit 1
fi
export AS_POSIX
for pip_exec in "${PIP_BINARIES[@]}"; do
echo "Running expect test with $COMPLETION_FILE and $pip_exec..."
if ./test_pip_completion.exp "$COMPLETION_FILE" "$pip_exec"; then
echo "✓ Functional test passed"
else
echo "✗ Functional test failed"
exit 1
fi
done
done
echo "✓ All tests completed successfully!"

View file

@ -1,117 +0,0 @@
#!/usr/bin/expect -f
# PIP bash completion smoke test using expect
# Tests actual TAB completion functionality
# Usage: test_pip_completion.exp [completion_file] [pip_binary]
set timeout 5
set completion_file [lindex $argv 0]
set pip_exec [lindex $argv 1]
puts "=== PIP Bash Completion Test (using expect) ==="
puts "Testing completion file: $completion_file"
puts "Testing pip binary: $pip_exec"
# Check if completion file exists first
if {![file exists $completion_file]} {
puts "✗ Completion file not found: $completion_file"
exit 1
}
puts "✓ Completion file found: $completion_file"
# Start bash shell
if {[info exists env(AS_POSIX)] && $env(AS_POSIX) == "1"} {
spawn bash --norc --posix
} else {
spawn bash --norc
}
expect "$ "
# Source the completion file
send "source $completion_file\r"
expect "$ "
puts "Attempted to source completion file"
# Test 1: Basic pip command completion
puts "\nTest 1: Testing '$pip_exec ' + TAB completion..."
send "$pip_exec "
sleep 0.1
# Send TAB TAB using hex codes
send "\x09\x09"
expect {
-re "(install|uninstall|list|show)" {
puts "✓ Basic pip commands found in completion"
expect "$ "
}
-re "Display all" {
puts "✓ Completion showing options menu"
send "n\r"
expect "$ "
}
timeout {
puts "✗ Timeout waiting for completion - test failed"
exit 1
}
}
# Clear the line and ensure clean prompt
send "\x03"
expect "$ "
send "\r"
expect "$ "
# Test 2: Test partial command completion (simpler test)
puts "\nTest 2: Testing '$pip_exec insta' + TAB completion..."
send "$pip_exec insta"
sleep 0.1
# Single TAB for completion
send "\x09"
expect {
-re "install" {
puts "✓ Partial command completion works (insta -> install)"
expect "$ "
}
timeout {
puts "✗ Timeout on partial completion test - test failed"
exit 1
}
}
# Clear the line and ensure clean prompt
send "\x03"
expect "$ "
send "\r"
expect "$ "
# Test 3: Test help completion
puts "\nTest 3: Testing '$pip_exec --' + TAB completion..."
send "$pip_exec --"
sleep 0.1
send "\x09\x09"
expect {
-re "(--help|--version)" {
puts "✓ Command options found in completion"
expect "$ "
}
timeout {
puts "✗ Timeout on options completion test - test failed"
exit 1
}
}
# Final cleanup - make sure we're at clean prompt
send "\x03"
expect "$ "
send "\r"
expect "$ "
# Exit bash cleanly
send "exit\r"
expect eof
puts "\n=== Completion Test Complete ==="
puts "PIP bash completion functionality tested!"

82
tests/tests.yml Normal file
View file

@ -0,0 +1,82 @@
---
- hosts: localhost
roles:
- role: standard-test-basic
tags:
- classic
repositories:
- repo: "https://src.fedoraproject.org/tests/python.git"
dest: "python"
- repo: "https://src.fedoraproject.org/rpms/pyproject-rpm-macros.git"
dest: "pyproject-rpm-macros"
tests:
- smoke36:
dir: python/smoke
run: VERSION=3.6 TOX=false ./venv.sh
- smoke39:
dir: python/smoke
run: VERSION=3.9 ./venv.sh
- smoke310:
dir: python/smoke
run: VERSION=3.10 ./venv.sh
- smoke311:
dir: python/smoke
run: VERSION=3.11 ./venv.sh
- smoke312:
dir: python/smoke
run: VERSION=3.12 ./venv.sh
- smoke313:
dir: python/smoke
run: VERSION=3.13 ./venv.sh
- smoke314:
dir: python/smoke
run: VERSION=3.14 ./venv.sh
- smoke39_virtualenv:
dir: python/smoke
run: VERSION=3.9 METHOD=virtualenv ./venv.sh
- smoke310_virtualenv:
dir: python/smoke
run: VERSION=3.10 METHOD=virtualenv ./venv.sh
- smoke311_virtualenv:
dir: python/smoke
run: VERSION=3.11 METHOD=virtualenv ./venv.sh
- smoke312_virtualenv:
dir: python/smoke
run: VERSION=3.12 METHOD=virtualenv ./venv.sh
- smoke313_virtualenv:
dir: python/smoke
run: VERSION=3.13 METHOD=virtualenv ./venv.sh
- smoke314_virtualenv:
dir: python/smoke
run: VERSION=3.14 METHOD=virtualenv ./venv.sh
- pyproject_pytest:
dir: pyproject-rpm-macros/tests
run: ./mocktest.sh python-pytest
- pyproject_entrypoints:
dir: pyproject-rpm-macros/tests
run: ./mocktest.sh python-entrypoints
- pyproject_pluggy:
dir: pyproject-rpm-macros/tests
run: ./mocktest.sh python-pluggy
- pyproject_clikit:
dir: pyproject-rpm-macros/tests
run: ./mocktest.sh python-clikit
- pip_install_upgrade
required_packages:
- gcc
- virtualenv
- python3.6
- python3.9
- python3.10-devel
- python3.11-devel
- python3.12-devel
- python3.13-devel
- python3.14-devel
- python3-devel
- python3-tox
- mock
- rpmdevtools
- rpm-build
- grep
- util-linux
- shadow-utils