-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
PEP 838: Adding python-version to pyvenv.cfg
#5040
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
Open
konsti-openai
wants to merge
1
commit into
python:main
Choose a base branch
from
konsti-openai:konsti/pyvenv-cfg-python-version
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+175
−0
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| PEP: 838 | ||
| Title: Adding python-version to pyvenv.cfg | ||
| Author: Konstantin Schütze <konstin@mailbox.org> | ||
| Sponsor: Alex Waygood <alex.waygood@gmail.com> | ||
| PEP-Delegate: Paul Moore <p.f.moore@gmail.com> | ||
| Discussions-To: Pending | ||
| Status: Draft | ||
| Type: Standards Track | ||
| Topic: Packaging | ||
| Created: 15-Jul-2026 | ||
| Python-Version: 3.16 | ||
| Post-History: Pending | ||
|
|
||
|
|
||
| Abstract | ||
| ======== | ||
|
|
||
| This PEP proposes adding a ``python-version`` field to ``pyvenv.cfg`` | ||
| which records the Python interpreter used by a virtual environment. | ||
| It records only the major and minor version to be resilient to patch | ||
| version updates. | ||
|
|
||
|
|
||
| Motivation | ||
| ========== | ||
|
|
||
| ``pyvenv.cfg``, as defined by :pep:`405`, only specifies the ``home`` | ||
| and ``include-system-site-packages`` keys. Different tools record different | ||
| information about the Python version of a virtual environment. For a virtual | ||
| environment created with Python 3.14.4 final: | ||
|
|
||
| - CPython's :mod:`venv` module adds a ``version`` field as | ||
| ``'%d.%d.%d' % sys.version_info[:3]`` | ||
| (`CPython source <https://github.com/python/cpython/blob/bc235304dfe5f018a87e1d73ca1ad2912f4ab999/Lib/venv/__init__.py#L234>`__). | ||
| Example: ``version = 3.14.4``. | ||
| - The ``virtualenv`` package adds ``version_info`` and ``version`` fields as | ||
| ``".".join(str(i) for i in sys.version_info)`` and | ||
| ``".".join(str(i) for i in sys.version_info[:3])`` | ||
| (`virtualenv source <https://github.com/pypa/virtualenv/blob/21.5.1/src/virtualenv/create/creator.py#L222-L227>`__). | ||
| Example: ``version_info = 3.14.4.final.0`` and ``version = 3.14.4``. | ||
| - uv adds a ``version_info`` field based on | ||
| ``platform.python_version()`` | ||
| (`uv source <https://github.com/astral-sh/uv/blob/7bbc01af54e8fd1d3c61d05b65f233574f7466da/crates/uv-virtualenv/src/virtualenv.rs#L531>`__). | ||
| Example: ``version_info = 3.14.4``. | ||
|
|
||
| This information is used by a variety of tools, see :ref:`appendix`. Some of | ||
| them want to present the full Python version to the user for identification, | ||
| while others only need the major and minor version of Python. | ||
|
|
||
| One problem is the different definitions of ``version`` and | ||
| ``version_info``, and the lack of guarantees for downstream tools. There is | ||
| no guarantee that either field is present, nor is either field's granularity | ||
| defined. | ||
|
|
||
| Another problem is that the Python interpreter underneath the virtual | ||
| environment may change. Linux distributions routinely update CPython patch | ||
| versions as part of regular updates within a single distribution version. uv | ||
| supports `upgrading existing Python installations <https://docs.astral.sh/uv/guides/install-python/#upgrading-python-versions>`__, | ||
| upgrading virtual environments using the interpreter in the process. A | ||
| ``version_info`` key in ``pyvenv.cfg`` with a patch version and a potential | ||
| prerelease component goes stale this way. | ||
|
|
||
| Tools interacting with virtual environments can `fail after a Python | ||
| patch-version upgrade <https://github.com/astral-sh/uv/issues/19920>`__ when | ||
| their assumptions about version granularity are violated. A standardized field | ||
| with only major and minor version avoids this problem. | ||
|
|
||
|
|
||
| Specification | ||
| ============= | ||
|
|
||
| A new ``python-version`` field is added to ``pyvenv.cfg``. It contains a | ||
| string value with the major and minor version of the Python interpreter, such | ||
| as ``3.16``. The value can be obtained with | ||
| ``f"{sys.version_info[0]}.{sys.version_info[1]}"``. Tools creating virtual | ||
| environments MUST write ``python-version`` to ``pyvenv.cfg``. Reading | ||
| ``version`` or ``version_info`` is discouraged. | ||
|
|
||
| A Python interpreter MAY refuse to run from a virtual environment with a | ||
| mismatching ``python-version``. | ||
|
|
||
|
|
||
| Rationale | ||
| ========= | ||
|
|
||
| The ``python-version`` key is not yet used by any known tool (`GitHub code | ||
| search <https://github.com/search?q=path%3A**%2Fpyvenv.cfg%20python-version&type=code>`__), | ||
| avoiding breakage in tools that read any of the existing keys. By | ||
| specifying only the major and minor version, the value remains fresh even if | ||
| the underlying Python interpreter is updated from one patch release to | ||
| another. | ||
|
|
||
| This PEP does not handle the case of ``python-version`` going stale due to | ||
| the underlying Python interpreter being updated to another minor version. | ||
| This may happen when upgrading from one Linux distribution version to another. | ||
| Such an update breaks any packages using CPython's unstable C API and cannot | ||
| be fixed through a different way of recording values in ``pyvenv.cfg``; it can | ||
| only be fixed by regenerating the virtual environment, resolving with the new | ||
| Python version and installing the appropriate packages. By performing a check | ||
| during interpreter startup, we avoid inscrutable errors at import time or at | ||
| runtime, and can inform the user about the problem. | ||
|
|
||
| To show accurate Python version information to the user, tools can present the | ||
| value of ``python-version``, or if they need the full Python version, they can | ||
| query the interpreter for ``sys.version_info``, invalidating this information | ||
| when the virtual environment interpreter or the underlying base executable | ||
| change. This PEP does not require any specific tool behavior, nor does it | ||
| disallow existing patterns. Its goal is to provide the required information | ||
| for correct, resilient implementations. | ||
|
|
||
|
|
||
| Backwards Compatibility | ||
| ======================= | ||
|
|
||
| If ``python-version`` is not available, tools can fall back to the | ||
| existing unspecified fields or inspect the Python interpreter. There is no | ||
| known existing usage of ``python-version`` in ``pyvenv.cfg``. | ||
|
|
||
|
|
||
| How to Teach This | ||
| ================= | ||
|
|
||
| A new specification page for ``pyvenv.cfg`` will be added to the `Python | ||
| Packaging User Guide <https://packaging.python.org/>`__, including | ||
| documentation for this field. The field is not user-facing. | ||
|
|
||
|
|
||
| Reference Implementation | ||
| ======================== | ||
|
|
||
| Reference implementations will be provided for uv, virtualenv, and CPython. | ||
|
|
||
|
|
||
| .. _appendix: | ||
|
|
||
| Appendix: Existing Tool Behavior | ||
| ================================ | ||
|
|
||
| A non-exhaustive list of how tools parse version values: | ||
|
|
||
| - **ty** splits the dotted value and parses only the major and minor | ||
| components, ignoring any remaining components | ||
| (`ty source <https://github.com/astral-sh/ruff/blob/1b011de418f1007a37fbe33f989a47bf99e2aa9f/crates/ty_site_packages/src/lib.rs#L789-L803>`__). | ||
| Ty only needs the major and minor version of Python. | ||
| - The **VS Code Python extension** parses both fields and | ||
| separately handles virtualenv-style values such as ``3.9.0.final.0``. | ||
| When both fields are present, it selects the most specific version | ||
| (`VS Code source <https://github.com/microsoft/vscode-python/blob/34348154b5eac877eef60b5b838699c6cbaf58b6/src/client/pythonEnvironments/common/environmentManagers/simplevirtualenvs.ts#L123-L211>`__). | ||
| VS Code presents the full Python version to the user for identification. | ||
| - **Microsoft Python Environment Tools** requires at least three numeric | ||
| components for both fields, then parses the first two components | ||
| (`Python Environment Tools source <https://github.com/microsoft/python-environment-tools/blob/89bf1c02290e09413e745cbbb0194bc50491bf0d/crates/pet-core/src/pyvenv_cfg.rs#L10-L162>`__). | ||
| Its uv-specific parser stores only ``version_info`` | ||
| (`Python Environment Tools uv source <https://github.com/microsoft/python-environment-tools/blob/89bf1c02290e09413e745cbbb0194bc50491bf0d/crates/pet-uv/src/lib.rs#L27-L60>`__). | ||
| VS Code presents the full Python version to the user for identification. | ||
| - **pre-commit** compares ``version_info`` with the ``sys.version_info`` | ||
| components joined by dots. | ||
| (`pre-commit source <https://github.com/pre-commit/pre-commit/blob/1553b465fd7ea42321ae0d04d1b41e706b89ae45/pre_commit/languages/python.py#L27-L33>`__, | ||
| `health-check source <https://github.com/pre-commit/pre-commit/blob/1553b465fd7ea42321ae0d04d1b41e706b89ae45/pre_commit/languages/python.py#L175-L211>`__). | ||
| `This caused a failure <https://github.com/astral-sh/uv/issues/19920>`__ where uv and pre-commit disagreed about virtual environment freshness checks. | ||
| - **Jute** reads ``version_info`` | ||
| (`Jute source <https://github.com/ekzhang/jute/blob/18723a036b843d9efc1d07b326bda5614b2020e7/src-tauri/src/commands/venv.rs#L125-L165>`__). | ||
| Jute presents the full Python version to the user for identification. | ||
| - **MediaHarbor** parses the first two components of ``version`` | ||
| (`MediaHarbor source <https://github.com/MediaHarbor/mediaharbor/blob/0fe6810d3a348e238e7d5ed87f6c2a9b16510b85/src/core/src/venv_manager.rs#L174-L184>`__). | ||
| - **Jac** parses the first two components of ``version`` | ||
| (`Jac source <https://github.com/jaseci-labs/jaseci/blob/e7afd1d8253a940bca989b946a1569970f99f719/jac/jaclang/project/impl/dependencies.impl.jac#L437-L453>`__). | ||
|
|
||
|
|
||
| Copyright | ||
| ========= | ||
|
|
||
| This document is placed in the public domain or under the | ||
| CC0-1.0-Universal license, whichever is more permissive. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pfmoore I put you up as default choice for packaging PEPs, but I'm with any other delegate too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm OK with this, but it's borderline whether this should be a packaging or a core PEP (the
pyvenv.cfgfile is maintained by the stdlibvenvmodule and machinery, not by packaging tools).