diff --git a/news/11547.bugfix.rst b/news/11547.bugfix.rst new file mode 100644 index 00000000000..29d566a23ff --- /dev/null +++ b/news/11547.bugfix.rst @@ -0,0 +1,3 @@ +Fix entry point generation of ``pip.X``, ``pipX.Y``, and ``easy_install-X.Y`` +to correctly account for multi-digit Python version segments (e.g. the "11" +part of 3.11). diff --git a/src/pip/_internal/operations/install/wheel.py b/src/pip/_internal/operations/install/wheel.py index 1650d59a374..c79941398a2 100644 --- a/src/pip/_internal/operations/install/wheel.py +++ b/src/pip/_internal/operations/install/wheel.py @@ -325,7 +325,7 @@ def get_console_script_specs(console: Dict[str, str]) -> List[str]: scripts_to_generate.append(f"pip{get_major_minor_version()} = {pip_script}") # Delete any other versioned pip entry points - pip_ep = [k for k in console if re.match(r"pip(\d(\.\d)?)?$", k)] + pip_ep = [k for k in console if re.match(r"pip(\d+(\.\d+)?)?$", k)] for k in pip_ep: del console[k] easy_install_script = console.pop("easy_install", None) @@ -340,7 +340,7 @@ def get_console_script_specs(console: Dict[str, str]) -> List[str]: ) # Delete any other versioned easy_install entry points easy_install_ep = [ - k for k in console if re.match(r"easy_install(-\d\.\d)?$", k) + k for k in console if re.match(r"easy_install(-\d+\.\d+)?$", k) ] for k in easy_install_ep: del console[k] diff --git a/tests/unit/test_wheel.py b/tests/unit/test_wheel.py index 6aec64702d2..c5a8f3be4f3 100644 --- a/tests/unit/test_wheel.py +++ b/tests/unit/test_wheel.py @@ -3,6 +3,7 @@ import logging import os import pathlib +import sys import textwrap from email import message_from_string from pathlib import Path @@ -22,7 +23,11 @@ from pip._internal.models.scheme import Scheme from pip._internal.operations.build.wheel_legacy import get_legacy_build_wheel_path from pip._internal.operations.install import wheel -from pip._internal.operations.install.wheel import InstalledCSVRow, RecordPath +from pip._internal.operations.install.wheel import ( + InstalledCSVRow, + RecordPath, + get_console_script_specs, +) from pip._internal.utils.compat import WINDOWS from pip._internal.utils.misc import hash_file from pip._internal.utils.unpacking import unpack_file @@ -681,3 +686,31 @@ def test_rehash(self, tmpdir: Path) -> None: h, length = wheel.rehash(os.fspath(self.test_file)) assert length == str(self.test_file_len) assert h == self.test_file_hash_encoded + + +def test_get_console_script_specs_replaces_python_version( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Fake Python version. + monkeypatch.setattr(sys, "version_info", (10, 11)) + + entry_points = { + "pip": "real_pip", + "pip99": "whatever", + "pip99.88": "whatever", + "easy_install": "real_easy_install", + "easy_install-99.88": "whatever", + # The following shouldn't be replaced. + "not_pip_or_easy_install-99": "whatever", + "not_pip_or_easy_install-99.88": "whatever", + } + specs = get_console_script_specs(entry_points) + assert specs == [ + "pip = real_pip", + "pip10 = real_pip", + "pip10.11 = real_pip", + "easy_install = real_easy_install", + "easy_install-10.11 = real_easy_install", + "not_pip_or_easy_install-99 = whatever", + "not_pip_or_easy_install-99.88 = whatever", + ]