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

Python version ending with plus sign not compatible with PEP 508 python_full_version marker #99968

Open
radoering opened this issue Dec 3, 2022 · 3 comments
Labels
build The build process and cross-build type-bug An unexpected behavior, bug, or error

Comments

@radoering
Copy link

Bug report

When building an untagged version of CPython, the resulting version ends with a plus sign, e.g. 3.11.0+. This version doesn't comply with PEP 440. As mentioned in #88166 (comment) PEP 440 does only apply to Python packages but not to CPython itself. However, a CPython version that doesn't comply with PEP 440 leads to unwanted side effects considering the python_full_version environment marker from PEP 508.

According to PEP 508 python_full_version is equal to platform.python_version() which is 3.11.0+ in my example.
Further, PEP 508 says:

The <version_cmp> operators use the PEP 440 version comparison rules when those are defined (that is when both sides have a valid version specifier). If there is no defined PEP 440 behaviour and the operator exists in Python, then the operator falls back to the Python behaviour.

That means an environment marker like python_full_version >= "3.9.0" is fulfilled for Python 3.11.0 because a PEP 440 version comparison is performed. However, it is not fulfilled for Python 3.11.0+ because 3.11.0+ is not a valid version and thus a string comparison is performed.

This has also practical implications. When trying to pip install a requirement with such a marker, pip says markers 'python_full_version >= "3.9.0"' don't match your environment. And if I understand correctly, it's right about that. However, that can't be intentional, can it? Wouldn't it be better to make sure that CPython versions always comply with PEP 440?

Your environment

@hugovk
Copy link
Member

hugovk commented Feb 19, 2023

Thanks for opening the issue, see also pypa/packaging#678 (comment) for further discussion.

@iritkatriel iritkatriel added the build The build process and cross-build label Nov 28, 2023
@konstin
Copy link

konstin commented Feb 20, 2024

This causes problems in uv because it breaks PEP 508 compliant marker implementations (astral-sh/uv#1357)

BurntSushi added a commit to astral-sh/uv that referenced this issue Feb 20, 2024
(This PR message is mostly copied from the comment in the code.)

For local builds of Python, at time of writing, the version numbers end with
a `+`. This makes the version non-PEP-440 compatible since a `+` indicates
the start of a local segment which must be non-empty. Thus, `uv` chokes on it
and [spits out an error][1] when trying to create a venv using a "local" build
of Python. Arguably, the right fix for this is for [CPython to use a PEP-440
compatible version number][2].

However, as a work-around for now, [as suggested by pradyunsg][3] as one
possible direction forward, we strip the `+`.

This fix does unfortunately mean that one [cannot specify a Python version
constraint that specifically selects a local version][4]. But at the time of
writing, it seems reasonable to block such functionality on this being fixed
upstream (in some way).

Another alternative would be to treat such invalid versions as strings (which
is what PEP-508 suggests), but this leads to undesirable behavior in this
case. For example, let's say you have a Python constraint of `>=3.9.1` and
a local build of Python with a version `3.11.1+`. Using string comparisons
would mean the constraint wouldn't be satisfied:

    >>> "3.9.1" < "3.11.1+"
    False

So in the end, we just strip the trailing `+`, as was done in the days of old
for [legacy version numbers][5].

I tested this fix by manually confirming that

    uv venv --python local/python

failed before it and succeeded after it.

Fixes #1357

[1]: #1357
[2]: python/cpython#99968
[3]: pypa/packaging#678 (comment)
[4]: #1357 (comment)
[5]: https://github.com/pypa/packaging/blob/085ff41692b687ae5b0772a55615b69a5b677be9/packaging/version.py#L168-L193
BurntSushi added a commit to astral-sh/uv that referenced this issue Feb 20, 2024
(This PR message is mostly copied from the comment in the code.)

For local builds of Python, at time of writing, the version numbers end
with
a `+`. This makes the version non-PEP-440 compatible since a `+`
indicates
the start of a local segment which must be non-empty. Thus, `uv` chokes
on it
and [spits out an error][1] when trying to create a venv using a "local"
build
of Python. Arguably, the right fix for this is for [CPython to use a
PEP-440
compatible version number][2].

However, as a work-around for now, [as suggested by pradyunsg][3] as one
possible direction forward, we strip the `+`.

This fix does unfortunately mean that one [cannot specify a Python
version
constraint that specifically selects a local version][4]. But at the
time of
writing, it seems reasonable to block such functionality on this being
fixed
upstream (in some way).

Another alternative would be to treat such invalid versions as strings
(which
is what PEP-508 suggests), but this leads to undesirable behavior in
this
case. For example, let's say you have a Python constraint of `>=3.9.1`
and
a local build of Python with a version `3.11.1+`. Using string
comparisons
would mean the constraint wouldn't be satisfied:

    >>> "3.9.1" < "3.11.1+"
    False

So in the end, we just strip the trailing `+`, as was done in the days
of old
for [legacy version numbers][5].

I tested this fix by manually confirming that

    uv venv --python local/python

failed before it and succeeded after it.

Fixes #1357

[1]: #1357
[2]: python/cpython#99968
[3]:
pypa/packaging#678 (comment)
[4]: #1357 (comment)
[5]:
https://github.com/pypa/packaging/blob/085ff41692b687ae5b0772a55615b69a5b677be9/packaging/version.py#L168-L193
radoering added a commit to radoering/poetry that referenced this issue Mar 23, 2024
neersighted pushed a commit to radoering/poetry that referenced this issue Mar 23, 2024
neersighted pushed a commit to python-poetry/poetry that referenced this issue Mar 23, 2024
neersighted pushed a commit to neersighted/poetry that referenced this issue Mar 24, 2024
…rsion() ends with a "+"

works around python/cpython#99968

(cherry picked from commit 8e1e87c)
abn pushed a commit to neersighted/poetry that referenced this issue Mar 24, 2024
…rsion() ends with a "+"

works around python/cpython#99968

(cherry picked from commit 8e1e87c)
abn pushed a commit to python-poetry/poetry that referenced this issue Mar 24, 2024
…rsion() ends with a "+"

works around python/cpython#99968

(cherry picked from commit 8e1e87c)
@jawhien
Copy link

jawhien commented Jun 22, 2024

Tell me how to build from the source code so that the version does not have this sign (+)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
build The build process and cross-build type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

5 participants