Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 838 – Adding python-version to pyvenv.cfg

PEP 838 – Adding python-version to pyvenv.cfg

Author:
Konstantin Schütze <konstin at mailbox.org>
Sponsor:
Alex Waygood <alex.waygood at gmail.com>
PEP-Delegate:
Paul Moore <p.f.moore at gmail.com>
Discussions-To:
Pending
Status:
Draft
Type:
Standards Track
Topic:
Packaging
Created:
15-Jul-2026
Python-Version:
3.16
Post-History:
Pending

Table of Contents

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 venv module adds a version field as '%d.%d.%d' % sys.version_info[:3] (CPython source). 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). 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). Example: version_info = 3.14.4.

This information is used by a variety of tools, see Appendix: Existing Tool Behavior. 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, 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 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), 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, including documentation for this field. The field is not user-facing.

Reference Implementation

Reference implementations will be provided for uv, virtualenv, and CPython.

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). 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). 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). Its uv-specific parser stores only version_info (Python Environment Tools uv source). 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, health-check source). This caused a failure where uv and pre-commit disagreed about virtual environment freshness checks.
  • Jute reads version_info (Jute source). Jute presents the full Python version to the user for identification.
  • MediaHarbor parses the first two components of version (MediaHarbor source).
  • Jac parses the first two components of version (Jac source).