Here’s my PEP for Python to adopt calendar versioning, based on my talk at the Language Summit at PyCon US. I’m proposing the preferred option of summit attendees (3.YY) which I feel has a good cost/benefit balance compared to the other suggestions (YY.0 and YY.MM).
Abstract
This PEP proposes updating the versioning scheme for Python to include the calendar year. This aims to make the support lifecycle clear by making it easy to see when a version was first released, and easier to work out when it will reach end of life (EOL).
Starting with what would have been Python 3.15, the version is 3.YY.micro where YY is the year of initial release:
Python 3.26 will be released in 2026 instead of Python 3.15. EOL is five years after initial release, therefore Python 3.26 will reach EOL in 2031.
I like the goal of making the EOL calculation easier. Would it be worth adjusting the release month to be January instead of October? (I see it’s marked as a non-goal.) “Released in 2026” or “EOL in 2031” actually mean “October 2026” or “nearer to the end of 2026”. But I think it’s more common to think of the beginning/full span of the year when shown only a year number. Moving to January might avoid a sort of “off by one” error.
Not a core dev, but I know a lot of core devs come from Western civilizations, and December is a particularly busy month with Western holidays and the like. October is a pretty reasonable release month.
Changing the release month is out of scope for this PEP.
PEP 602 (“Annual Release Cycle for Python”) set it in October with good reasons:
creates a predictable calendar for releases where the final release is always in October (so after the annual core sprint), and the beta phase starts in late May (so after PyCon US sprints), which is especially important for core developers who need to plan to include Python involvement in their calendar;
…
allows for synchronizing the schedule of Python release management with external distributors like Fedora who’ve been historically very helpful in finding regressions early not only in core Python but also in third-party libraries, helping moving the community forward to support the latest version of Python from Day 1;
It’s worth repeating: Fedora do a huge amount of testing of pre-releases with third-party packages, including creating fixes and contributing them upstream to packages. They find and report a good number of CPython bug too. This is extremely valuable to both CPython and the ecosystem as a whole.
My personal preference would have been for YY.MM (26.10), making the month explicit, but the ecosystem cost is likely too large (compatibility tags, python3 command, version assumptions, etc.) and 3.YY (3.26) is a much safer choice.
<bikeshedding>
Maybe the version released in October 2026[1] should be 3.27? That way 3.27 is the latest version in (nearly all of) 2027.
</bikeshedding>
Or, if you prefer, somewhere around January -92nd, 2027 ↩︎
The PEP describes the proposal well but I don’t think we should make this change.
The motivation of the change is really just this section: PEP 2026 – Calendar versioning for Python | peps.python.org. It becomes clearer that Python version 3.xy is the version released in 20xy. But it’s not very clear: it’s not obvious to people who aren’t intimately familiar with CPython that 3.26 has something to do with 2026, and to know when a version reaches EOL, you still have to know about the arbitrary 5-year lifetime.
The PEP’s proposal has a few minor disadvantages:
User confusion when the change is actually made (we’ll surely have many people wondering what happened to Python 3.15 through 3.25)
Less flexibility in the future if we want to change to a different release cycle (either less than once a year or multiple times per year).
With the arguments both for and against change relatively weak, I’d prefer to make no change and stick with the current model.
The scheme standardized by Semantic Versioning was already a common (but far from universal) practice long before it was ever put into a “standard”. The best example is .so naming, which is essentially identical with SemVer and has been around since at least the 90s.
Edit: What Semantic Versioning did was formalizing the existing practice (which is largely irrelevant as no one follows the standard exactly) and give it a name (which is the real achievement of SemVer).
I want to add to this that I think the PEP overstates people knowing the EOL as an advantage. I consider myself a pretty enthusiastic Python user. I know 3.12 was released in October 2023, but I still don’t remember when the EOL is. Usually, when I care about EOL, I just check this: Status of Python versions. This is a good enough way for me.
I don’t think it’s 100% fair to say that the section you link to there is the only motivation given for the change. A significant other motivation given in the PEP is the argument that current users often assume that Python uses SemVer, and therefore assume that Python guarantees backwards compatibility between “minor” releases (it does not). Several examples of users exhibiting confusion about this are linked to inline in the earlier section of the PEP, “Python predates SemVer”: PEP 2026 – Calendar versioning for Python | peps.python.org.
There are lots of good reasons for an annual release cycle, as detailed in PEP 602 (for example, predictable release cycle, syncing with redistributors) and I doubt we’ll move away from it any time soon, if at all.
But if we went to fewer than one release per year, the proposed CalVer scheme still works just fine (for example, 3.26 in 2026, 3.28 in 2028) and I’d argue it even helps people know in which year to expect the release.
I think switching to more than one release per year is even less likely, but CalVer could still be adapted in some way. For example, Ubuntu, Black, pip and PyCharm all have multiple releases per year.
Yeah, I expect there are other forms of (lowercase) semantic versioning that also predate SemVer, but I think SemVer really popularised it.
Anyway, my main point is that people often expect Python to follow SemVer, but it doesn’t, and SemVer would be a poor fit for Python. I believe CalVer is more useful.
The year-based version string is the display version of Windows, which is used as a friendly name for the purposes of API documentation and branding (e.g. “22H2”)[1]. The version value that’s used programmatically is still the major.minor.build version at runtime (e.g. 10.0.22621), or an NTDDI value at compile time (e.g. NTDDI_WIN10_NI). I wouldn’t want Python to start using a complicated combination of display, runtime, and compile-time version values like Windows. It’s tedious and confusing. A switch to calendar-based versioning should be across the board.
It’s stored as the “DisplayVersion” value in the registry key “HKLM\Software\Microsoft\Windows NT\CurrentVersion”. The deprecated YYMM formatted value (e.g. “2009”, for September 2020) is the “ReleaseId” value in the same key. ↩︎
Going to throw out there that while YY.00 and YY.MM were explored, 3.YY.MM was not explored (so I guess 3.YY.MM.0, 3.YY.MM.1…).
Perhaps the triple-dot is already sufficient enough to reject the idea outright. 3.YY.MM0,3.YY.MM1, etc might be a bit odd too. But I personally like having the month in releases for the same reason having the year is good: our main question with all of this for me is usually “how far away is this release from another release in human time”.
It is for me. I don’t think there’d be much to gain by it, other than retaining some level of commonality with the existing 3.x version numbers. We wouldn’t be any better off, for example, if Firefox were numbered 2.115.whatever instead of just 115.whatever; it gives no additional information, and there would be no logical point to bump it to 4.YY.MM or 5.YY.MM.
Very few programs require four-part version numbers.
I feel like “3 is the brand” is non-negotiable at this at this point. Easy for me to say because I think it’s too divisive to fight about and not useful. I wanted to mention 3.YY.MM mainly because it captures “3 is the brand” and “capture years and months” like Ubuntu or Black.
“There’s nothing to gain from the 3” feels like a real point, but if you think about it nothing about version numbers in calver matters anyways! Why not 3.YYMM? Why not YYMM01, YYMM02, etc? The dots location in the string is information-less, yet we put it in because aesthetically it’s nice!
I’m saying this but don’t have strong opinions about anything. Ultimately this falls into the “either basically everyone is happy with the conclusion or it shouldn’t be done” category. There’s probably not a conflict cost low enough to be worth paying for this kind of change.
(EDIT: also to your point: 3 dots making the version number be non-ingestible is a legit point though. No point in breaking people’s software for fun)
I don’t think that the proposed versioning format would help with the confusion. “3.26.5” very much looks like a SemVer version, the fact it uses some kind of CalVer is quite obscure.