diff --git a/CHANGES.md b/CHANGES.md index c5498696b..a16384b85 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,16 @@ # Release Notes +## 2.32.1 + +This release fixes a long-standing bug handling development versions of +CPython (any non-tagged release of the interpreter). These interpreters +report a full version of `X.Y.Z+` and the trailing `+` leads to a non +PEP-440 compliant version number. This, in turn, causes issues with the +`packaging` library leading to failures to evaluate markers for these +interpreters which surface as inscrutable Pex errors. + +* Fix support for CPython development releases. (#2655) + ## 2.32.0 This release adds support for Pip 25.0. diff --git a/pex/pep_508.py b/pex/pep_508.py index 153aba2ee..065985478 100644 --- a/pex/pep_508.py +++ b/pex/pep_508.py @@ -15,6 +15,24 @@ from pex.third_party import attr +def _convert_non_pep_440_dev_versions(python_full_version): + # type: (Optional[str]) -> Optional[str] + + # This applies the same workaround that exists in packaging as of its 24.1 release. + # See: + # + https://github.com/pypa/packaging/pull/802 + # + https://github.com/pypa/packaging/pull/825 + # + # N.B.: We can't simply upgrade to packaging >= 24.1 since those changes unconditionally access + # the `python_full_version` marker and our `AbbreviatedPlatform` can lead to marker environments + # without that marker filled in. Even if we could upgrade packaging though, that would only help + # Pex users on Python >= 3.8 whereas this fix applies to all Pex users. + if python_full_version and python_full_version.endswith("+"): + return python_full_version + "local" + + return python_full_version + + @attr.s(frozen=True) class MarkerEnvironment(object): """A PEP-508 marker environment. @@ -125,7 +143,9 @@ def from_platform(cls, platform): platform_release = attr.ib(default=None) # type: Optional[str] platform_system = attr.ib(default=None) # type: Optional[str] platform_version = attr.ib(default=None) # type: Optional[str] - python_full_version = attr.ib(default=None) # type: Optional[str] + python_full_version = attr.ib( + default=None, converter=_convert_non_pep_440_dev_versions + ) # type: Optional[str] python_version = attr.ib(default=None) # type: Optional[str] sys_platform = attr.ib(default=None) # type: Optional[str] diff --git a/pex/version.py b/pex/version.py index fd005f3da..636ab797f 100644 --- a/pex/version.py +++ b/pex/version.py @@ -1,4 +1,4 @@ # Copyright 2015 Pex project contributors. # Licensed under the Apache License, Version 2.0 (see LICENSE). -__version__ = "2.32.0" +__version__ = "2.32.1" diff --git a/tests/test_pep_508.py b/tests/test_pep_508.py index de9f285bf..842343905 100644 --- a/tests/test_pep_508.py +++ b/tests/test_pep_508.py @@ -99,3 +99,11 @@ def assert_platform_machine( assert_platform_machine("x86_64", "macosx-10.15-x86_64-cp-38-m") assert_platform_machine("arm64", "macosx-11.0-arm64-cp-39-cp39") + + +def test_cpython_dev_release(): + env = MarkerEnvironment(python_full_version="3.10.16+").as_dict() + assert evaluate_marker("python_full_version >= '3.10.16'", env) + assert evaluate_marker("python_full_version <= '3.10.17'", env) + assert evaluate_marker("python_full_version == '3.10.16'", env) + assert not evaluate_marker("python_full_version === '3.10.16'", env)