Skip to content

Commit

Permalink
Add support for --pip-version 24.2. (#2481)
Browse files Browse the repository at this point in the history
The changelog is here: https://pip.pypa.io/en/stable/news/#v24-2

Closes #2471
  • Loading branch information
jsirois authored Jul 29, 2024
1 parent e0aac4f commit a5286b6
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 48 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ jobs:
- py311-pip20
- py311-pip22_3_1
- py311-pip23_1_2
- py312-pip24_1_2
- py313-pip24_1_2
- py312-pip24_2
- py313-pip24_2
- pypy310-pip20
- pypy310-pip22_3_1
- pypy310-pip23_1_2
Expand All @@ -87,8 +87,8 @@ jobs:
- py311-pip20-integration
- py311-pip22_3_1-integration
- py311-pip23_1_2-integration
- py312-pip24_1_2-integration
- py313-pip24_1_2-integration
- py312-pip24_2-integration
- py313-pip24_2-integration
- pypy310-pip20-integration
- pypy310-pip22_3_1-integration
- pypy310-pip23_1_2-integration
Expand Down Expand Up @@ -132,10 +132,10 @@ jobs:
matrix:
include:
- python-version: [ 3, 12 ]
tox-env: py312-pip24_1_2
tox-env: py312-pip24_2
tox-env-python: python3.11
- python-version: [ 3, 12 ]
tox-env: py312-pip24_1_2-integration
tox-env: py312-pip24_2-integration
tox-env-python: python3.11
steps:
- name: Calculate Pythons to Expose
Expand Down
6 changes: 6 additions & 0 deletions pex/pep_440.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ def __lt__(self, other):
return NotImplemented
return self.parsed_version < other.parsed_version

def __ge__(self, other):
# type: (Any) -> bool
if not isinstance(other, Version):
return NotImplemented
return self.parsed_version >= other.parsed_version

@property
def is_legacy(self):
# type: () -> bool
Expand Down
29 changes: 23 additions & 6 deletions pex/pip/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@
from pex.typing import TYPE_CHECKING, cast

if TYPE_CHECKING:
from typing import Iterable, Optional, Tuple, Union
from typing import Iterable, Iterator, Optional, Tuple, Union


@functools.total_ordering
class PipVersionValue(Enum.Value):
@classmethod
def _iter_values(cls):
# type: () -> Iterator[PipVersionValue]
return cast("Iterator[PipVersionValue]", super(PipVersionValue, cls)._iter_values())

@classmethod
def overridden(cls):
# type: () -> Optional[PipVersionValue]
Expand Down Expand Up @@ -94,9 +99,15 @@ def __lt__(self, other):
return NotImplemented
return self.version < other.version

def __ge__(self, other):
if not isinstance(other, PipVersionValue):
return NotImplemented
return self.version >= other.version


class LatestPipVersion(object):
def __get__(self, obj, objtype=None):
# type: (...) -> PipVersionValue
if not hasattr(self, "_latest"):
self._latest = max(
(version for version in PipVersionValue._iter_values() if not version.hidden),
Expand All @@ -111,17 +122,16 @@ def __init__(self, preferred):
self._preferred = preferred

def __get__(self, obj, objtype=None):
# type: (...) -> PipVersionValue
if not hasattr(self, "_default"):
self._default = None
current_version = Version(".".join(map(str, sys.version_info[:3])))
preferred_versions = (
[PipVersionValue.overridden()] if PipVersionValue.overridden() else self._preferred
)
overridden = PipVersionValue.overridden()
preferred_versions = [overridden] if overridden is not None else self._preferred
for preferred_version in preferred_versions:
if preferred_version.requires_python_applies(current_version):
self._default = preferred_version
break
if self._default is None:
if not hasattr(self, "_default"):
applicable_versions = tuple(
version
for version in PipVersionValue._iter_values()
Expand Down Expand Up @@ -285,6 +295,13 @@ def values(cls):
requires_python=">=3.8,<3.14",
)

v24_2 = PipVersionValue(
version="24.2",
setuptools_version="71.1.0",
wheel_version="0.43.0",
requires_python=">=3.8,<3.14",
)

VENDORED = v20_3_4_patched
LATEST = LatestPipVersion()
DEFAULT = DefaultPipVersion(preferred=(VENDORED, v23_2, v24_1))
17 changes: 8 additions & 9 deletions tests/integration/test_excludes.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,11 @@ def assert_certifi_is_excluded(pex):
)


@pytest.fixture(scope="module")
def requests_certifi_excluded_pex(tmpdir_factory):
def requests_certifi_excluded_pex(tmpdir):
# type: (Any) -> str

pex_root = str(tmpdir_factory.mktemp("pex_root"))
pex = str(tmpdir_factory.mktemp("pex"))
pex_root = os.path.join(str(tmpdir), "pex_root")
pex = os.path.join(str(tmpdir), "pex")
run_pex_command(
args=[
"--lock",
Expand Down Expand Up @@ -147,28 +146,28 @@ def assert_requests_certifi_excluded_pex(
@skip_unless_compatible_with_requests_lock
def test_exclude(
tmpdir, # type: Any
requests_certifi_excluded_pex, # type: str
certifi_venv, # type: Virtualenv
):
# type: (...) -> None

assert_requests_certifi_excluded_pex(requests_certifi_excluded_pex, certifi_venv)
pex = requests_certifi_excluded_pex(tmpdir)
assert_requests_certifi_excluded_pex(pex, certifi_venv)


@skip_unless_compatible_with_requests_lock
def test_requirements_pex_exclude(
tmpdir, # type: Any
requests_certifi_excluded_pex, # type: str
certifi_venv, # type: Virtualenv
):
# type: (...) -> None

pex_root = PexInfo.from_pex(requests_certifi_excluded_pex).pex_root
requirements_pex = requests_certifi_excluded_pex(tmpdir)
pex_root = PexInfo.from_pex(requirements_pex).pex_root
pex = os.path.join(str(tmpdir), "pex")
run_pex_command(
args=[
"--requirements-pex",
requests_certifi_excluded_pex,
requirements_pex,
"ansicolors==1.1.8",
"-o",
pex,
Expand Down
83 changes: 56 additions & 27 deletions tests/integration/test_issue_2017.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,54 +11,83 @@

import pytest

from pex.atomic_directory import atomic_directory
from pex.common import is_exe, safe_open
from pex.compatibility import urlparse
from pex.fetcher import URLFetcher
from pex.pep_440 import Version
from pex.pip.version import PipVersion
from pex.pip.version import PipVersion, PipVersionValue
from pex.typing import TYPE_CHECKING
from testing import IS_LINUX, run_pex_command

if TYPE_CHECKING:
from typing import Any
from typing import Any, Iterator


def musl_libc_capable_pip_versions():
# type: () -> Iterator[PipVersionValue]

for version in PipVersion.values():
if not version.requires_python_applies():
continue
if version is PipVersion.VENDORED or version >= PipVersion.v24_2:
yield version


MUSL_LIBC_CAPABLE_PIP_VERSIONS = tuple(musl_libc_capable_pip_versions())


@pytest.fixture
def statically_linked_musl_libc_cpython(shared_integration_test_tmpdir):
# type: (str) -> str
pbs_distribution_url = (
"https:/indygreg/python-build-standalone/releases/download/20221220/"
"cpython-3.10.9+20221220-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
)
tarball_name = os.path.basename(urlparse.urlparse(pbs_distribution_url).path)
pbs_distribution = os.path.join(shared_integration_test_tmpdir, "PBS-dists", tarball_name)
with atomic_directory(pbs_distribution) as chroot:
if not chroot.is_finalized():
tarball_dest = os.path.join(chroot.work_dir, tarball_name)
with URLFetcher().get_body_stream(pbs_distribution_url) as read_fp, open(
tarball_dest, "wb"
) as write_fp:
shutil.copyfileobj(read_fp, write_fp)
with tarfile.open(tarball_dest) as tf:
tf.extractall(chroot.work_dir)
statically_linked_musl_libc_cpython = os.path.join(
chroot.work_dir, "python", "bin", "python3"
)
assert is_exe(statically_linked_musl_libc_cpython)

return os.path.join(pbs_distribution, "python", "bin", "python3")


# TODO(John Sirois): Include a test of >= Pip 24.2 when Pex adds support for it.
# See: https:/pex-tool/pex/issues/2471
@pytest.mark.skipif(
PipVersion.DEFAULT > PipVersion.VENDORED and PipVersion.DEFAULT.version < Version("24.2"),
not MUSL_LIBC_CAPABLE_PIP_VERSIONS,
reason=(
"Although Pex's vendored Pip is patched to handle statically linked musl libc CPython, no "
"version of Pip Pex supports handles these Pythons until Pip 24.2"
"version of Pip Pex supports handles these Pythons until Pip 24.2 and none of these "
"versions are supported by the current interpreter."
),
)
@pytest.mark.skipif(
not IS_LINUX,
reason="This test tests statically linked musl libc CPython which is only available for Linux.",
)
def test_statically_linked_musl_libc_cpython_support(tmpdir):
# type: (Any) -> None

pbs_distribution_url = (
"https:/indygreg/python-build-standalone/releases/download/20221220/"
"cpython-3.10.9+20221220-x86_64_v3-unknown-linux-musl-install_only.tar.gz"
)
pbs_distribution = os.path.join(
str(tmpdir),
os.path.basename(urlparse.urlparse(pbs_distribution_url).path),
)
with URLFetcher().get_body_stream(pbs_distribution_url) as read_fp, open(
pbs_distribution, "wb"
) as write_fp:
shutil.copyfileobj(read_fp, write_fp)
with tarfile.open(pbs_distribution) as tf:
tf.extractall(str(tmpdir))
statically_linked_musl_libc_cpython = os.path.join(str(tmpdir), "python", "bin", "python3")
assert is_exe(statically_linked_musl_libc_cpython)
@pytest.mark.parametrize(
"pip_version",
[pytest.param(version, id=str(version)) for version in MUSL_LIBC_CAPABLE_PIP_VERSIONS],
)
def test_statically_linked_musl_libc_cpython_support(
tmpdir, # type: Any
pip_version, # type: PipVersionValue
statically_linked_musl_libc_cpython, # type: str
):
# type: (...) -> None

pex = os.path.join(str(tmpdir), "pex")
run_pex_command(
args=["fortune==1.1.1", "-c", "fortune", "-o", pex],
args=["fortune==1.1.1", "-c", "fortune", "--pip-version", str(pip_version), "-o", pex],
python=statically_linked_musl_libc_cpython,
).assert_success()

Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ setenv =
pip24_1: _PEX_PIP_VERSION=24.1
pip24_1_1: _PEX_PIP_VERSION=24.1.1
pip24_1_2: _PEX_PIP_VERSION=24.1.2
pip24_2: _PEX_PIP_VERSION=24.2

# Python 3 (until a fix here in 3.9: https://bugs.python.org/issue13601) switched from stderr
# being unbuffered to stderr being buffered by default. This can lead to tests checking stderr
Expand Down

0 comments on commit a5286b6

Please sign in to comment.