Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for --pip-version 24.2. #2481

Merged
merged 2 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately this __ge__ and the one below in PipVersionValue are needed to satisfy MyPy despite using @total_ordering in both cases.

# 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))
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://github.com/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://github.com/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://github.com/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
Loading