-
Notifications
You must be signed in to change notification settings - Fork 251
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
Non-tagged Python builds use non-PEP 440 versions #678
Comments
Looking at the implementation of You can probably replicate the issue by installing packaging, then running:
I'm unsure if Python should use PEP 440 version numbers or if packaging should be updated to honor Python versions that aren't PEP 440 compliant, but this issue only happens to be loosely affiliated with this issue, which is about package versions. |
Python has never formally followed PEP 440 (although most of the version numbers it used are compatible). Even if we start mandating PEP 440 for it, there are still much too many problematic version strings to deal with (considering redistributors probably have their own scheme). A separate parser for Python versions is probably more viable; IIRC Python has documentation on the rules somewhere, but we can ask the core devs for a concrete ruling if not. |
pypa/packaging#678 Nightly builds were failing because newer setuptools didn't like the Python version number: ``` % .tox/anypy/bin/python -c "import pkg_resources as p; p.load_entry_point('coverage', 'console_scripts', 'coverage')()" Traceback (most recent call last): File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2711, in _dep_map return self.__dep_map ^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2826, in __getattr__ raise AttributeError(attr) AttributeError: _Distribution__dep_map During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<string>", line 1, in <module> File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 522, in load_entry_point return get_distribution(dist).load_entry_point(group, name) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2855, in load_entry_point return ep.load() ^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2467, in load self.require(*args, **kwargs) File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2489, in require reqs = self.dist.requires(self.extras) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2746, in requires dm = self._dep_map ^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2713, in _dep_map self.__dep_map = self._filter_extras(self._build_dep_map()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2728, in _filter_extras invalid_marker(marker) or not evaluate_marker(marker) ^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 1415, in invalid_marker evaluate_marker(text) File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 1433, in evaluate_marker return marker.evaluate() ^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/_vendor/packaging/markers.py", line 245, in evaluate return _evaluate_markers(self._markers, current_environment) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/_vendor/packaging/markers.py", line 151, in _evaluate_markers groups[-1].append(_eval_op(lhs_value, op, rhs_value)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/_vendor/packaging/markers.py", line 109, in _eval_op return spec.contains(lhs, prereleases=True) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/_vendor/packaging/specifiers.py", line 565, in contains normalized_item = _coerce_version(item) ^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/_vendor/packaging/specifiers.py", line 36, in _coerce_version version = Version(version) ^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/_vendor/packaging/version.py", line 197, in __init__ raise InvalidVersion(f"Invalid version: '{version}'") pkg_resources.extern.packaging.version.InvalidVersion: Invalid version: '3.12.0a5+' ```
pypa/packaging#678 Nightly builds were failing because newer setuptools didn't like the Python version number: ``` % .tox/anypy/bin/python -c "import pkg_resources as p; p.load_entry_point('coverage', 'console_scripts', 'coverage')()" Traceback (most recent call last): File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2711, in _dep_map return self.__dep_map ^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2826, in __getattr__ raise AttributeError(attr) AttributeError: _Distribution__dep_map During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<string>", line 1, in <module> File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 522, in load_entry_point return get_distribution(dist).load_entry_point(group, name) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2855, in load_entry_point return ep.load() ^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2467, in load self.require(*args, **kwargs) File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2489, in require reqs = self.dist.requires(self.extras) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2746, in requires dm = self._dep_map ^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2713, in _dep_map self.__dep_map = self._filter_extras(self._build_dep_map()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 2728, in _filter_extras invalid_marker(marker) or not evaluate_marker(marker) ^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 1415, in invalid_marker evaluate_marker(text) File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/__init__.py", line 1433, in evaluate_marker return marker.evaluate() ^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/_vendor/packaging/markers.py", line 245, in evaluate return _evaluate_markers(self._markers, current_environment) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/_vendor/packaging/markers.py", line 151, in _evaluate_markers groups[-1].append(_eval_op(lhs_value, op, rhs_value)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/_vendor/packaging/markers.py", line 109, in _eval_op return spec.contains(lhs, prereleases=True) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/_vendor/packaging/specifiers.py", line 565, in contains normalized_item = _coerce_version(item) ^^^^^^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/_vendor/packaging/specifiers.py", line 36, in _coerce_version version = Version(version) ^^^^^^^^^^^^^^^^ File "/Users/nedbatchelder/coverage/trunk/.tox/anypy/lib/python3.12/site-packages/pkg_resources/_vendor/packaging/version.py", line 197, in __init__ raise InvalidVersion(f"Invalid version: '{version}'") pkg_resources.extern.packaging.version.InvalidVersion: Invalid version: '3.12.0a5+' ``` https://nedbat.github.io/coverage-reports/reports/20230214_7887212bda/htmlcov 7887212bda: master
This was flagged to me on a private Discord today, and jotting down a summary/my takeaways from that discussion. There's three directions we can take here:
Broadly though, the underlying reason of why this was surfaced is the same as all other PEP 440 issues -- #530 For the first bullet: I don't think this deviates much from PEP 440 TBH, and it's not clear that it's worth a compete new concept/mental model. Plus, it only affect development builds and patched copies of CPython. It's unclear that there's much value to changing that. For the second bullet: platform.python_version is documented as:
I think the expectation with PEP 508 is that all segments in the documentation would be numbers. We could just strip the trailing For the third bullet: There's also valid concern that people might be splitting the Python version on '.', so using a Adding cross-references mentioned by @hugovk and @Yhg1s:
|
Not to bikeshed too early, but I would suggest something other than |
(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
(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
I propose a fix in #802 |
I ran into this issue again today. It seems it's not fixed: I'm using
When I dive into the debugger, I see
It seems |
I see now the fix in #802 specifically retained the "InvalidVersion" behavior for user-provided environments. Does that mean that this issue needs to be addressed by pipx and every other upstream caller that's passing in an environment? That seems rather unsustainable. |
I think it was just an oversight in the PR and not intentional. |
Sorry if this should be a new issue. I have a problem where the version of Python itself is causing an Invalid Version error. I install Python from the tip of 3.12, then:
Why is setuptools trying to parse the Python version?
There's a corresponding coverage.py issue about this.
Originally posted by @nedbat in pypa/setuptools#3772 (comment)
The text was updated successfully, but these errors were encountered: