PEP 2026: Calendar versioning for Python

That’s fair. I do feel like it would be slightly easier to explain it to users — “it’s not SemVer, it’s CalVer; here are the details […]” feels less complicated than “It’s not SemVer, it’s this bespoke versioning scheme that’s sorta like SemVer but subtly different; here are the details […]”.

3 Likes

While we’ve had people get confused because they assume SemVer, I don’t think anyone has had any particular issue once it’s been explained.

And to be honest, I think that a lot of the reason we get people assuming semver is just because semver fans seem to assume everything is semver, not because our version scheme is unusually difficult to understand.

Just because a project uses an X.Y.Z version structure shouldn’t automatically mean they follow the rules of SemVer. And we shouldn’t have to change our versioning just because some fans of SemVer think otherwise…

21 Likes

I touched upon it but could more explicitly reject a four-(or more)-part version in the PEP. The proposal is to retain the familiar three-part 3.x.y shape for backwards compatibility:

And to minimise ecosystem changes:

Addressed under non-goals: I propose 3.YY.micro where YY is the year of initial release, and micro is incremented for bugfix/security releases.

For example, 3.26.0 is the initial release in October 2026, 3.26.2 is the second bugfix release in February 2027. We retain the 3.YY for each feature release based on initial release; remember we support five feature releases at a time.

This is similar to Ubuntu’s micro: 22.04.0 was the initial release in 2022, 22.04.2 was a bugfix release in 2023.

Sure, but we’re not designing from scratch. Why not those? To avoid breaking code that expects a three-part, two-dot version starting with 3 and followed by two parts of 1-2 digits; and:


However we’d be able to point to a clear statement saying “the major is always 3, minor is the year”, which I feel is much better than the ambiguous and confusing “major is bumped for really major changes in the language, minor for less earth-shattering changes”.


But when will we bump the major version? There is confusion around this. What exceptional, earth-shattering changes warrant a bump to 4? It comes up from time to time, but there’s little appetite for it and we don’t want to repeat 2-to-3. From the summit discussion:

“Python 3 is a brand at this point, and we should stick to it” said Guido van Rossum after sharing concerns that changes to the major version would break the ecosystem more than changes to the minor version. Others voiced concerns about changing the major version “3” including in the “python3” binary and for packaging such as “abi3” tag.

The proposal makes clear the major is always 3; there’ll be no Python 4.

Indeed, but this isn’t the only reason. We bump the minor every year without fail. We’re unlikely to bump the major. I propose we do something useful with the minor.

2 Likes

How?

This needs elaboration in the PEP as to how multiple releases per year would work and the ecosystem consequences of such a change in version numbering. The patch number would no longer be the patch number if we followed what others have done for this.

I don’t want us to be unable to adopt a more frequent release cycle because of a version numbering declaration. Thoughts as to whether we ever would aren’t important.

8 Likes

I’m personally a CalVer fan when deprecations and other notice periods are involved, so +1 on a 2026 3.26.0 release from me (and I agree with the PEP’s reasoning for choosing that approach as the least disruptive way of getting a calendar reference into the version number).

While the PEP specifically mentions making EOL dates easier to calculate (once you’re aware of the scheme, you’ll know that 3.26 will go EOL in 2031), using CalVer makes everything easier to translate into calendar time rather than counting versions and looking up when they will be (or were) released.

  • setting your minimum compatible Python version to 3.12 in 2024 is actually making an aggressive assumption regarding version adoption and support. The less-than-12-months-old age of the release will be more obvious to folks considering making 3.26 their baseline in 2027. (Not a hypothetical example, I actually made a mistake along those lines when setting up a work project a couple of months ago and only corrected it last week when a new feature brought in a new dependency that didn’t fully support Python 3.12 yet)
  • warnings for hard deprecations specify a future release when the deprecated feature will go away entirely. When the warning says This will go away in 3.15, it isn’t immediately obvious how long you have to do something about it. When the warning instead says This will go away in 3.26 (and you’re aware the versioning is CalVer based), you know you’ve got at least a year to do something about it, but will need to make changes after that.

(Tangent: while I don’t think it should be part of this PEP, there may even come a time when the text represention of the version number is sometimes written like “Python3 26.0” rather than always being written as “Python 3.26.0”. Something to consider for folks that find the fixed 3. prefix before the year a bit odd to look at)

7 Likes

Related to this, I’m a little surprised that “Python 3 is the brand” is so widely agreed on. I think of Python as the brand–I can assume the “3” unless I’m doing archaeology. I wouldn’t be mad at installing Python 30.0 in 2030[1].

I didn’t think the 3 in abi3 was strictly tied to the major version–I know there was discussion of abi4 as part of PEP 703, and there might be other reasons to bump that version. It seems like breaking that correspondence might be healthier for communication, documentation, etc, because it’s easy to assume python3 == abi3 forever, right now.


  1. but I recognize that the transition would still be painful, which is why I moved it 4 years past this PEP ↩︎

9 Likes

To combine “multiple feature releases per year” with “multiple maintenance releases for each feature release” in a 3-field CalVer based version number, it’s hard to avoid moving the “year” to the first field (leaving the second field free for either a month entry, or a feature release serial within the year, and then keeping the third field as a patch release serial).

I don’t think that’s a strong argument against the CalVer variant in the PEP, though - it just means that any hypothetical future proposal to switch to multiple releases per year would also need to tackle the challenge of moving the 3. prefix out of the runtime version number (e.g. making it an implied language version prefix rather than a runtime one). In the grand scheme of hurdles that a multiple-feature-releases-per-year proposal would have to overcome, that seems like a pretty minor one :slight_smile:

2 Likes

Having maintained the Python 3 Q&A for several years, letting people make that assumption and having it be mostly correct for the immediate future is a good thing (I was delighted when the decision to create 3.10 rather than 4.0 was made).

While we have muttered at various times about changes that might be both significant and invasive enough to want to declare abi4 (e.g. free threading, fixing up various performance limiting problems in the C API design), folks have so far been able to come up with ways to make steady progress on those topics by using the regular deprecation management process to address individual problematic interfaces, without needing to ask for the kind of wholesale compatibility break that occurred in the Python 2->3 transition.

It’s also worth keeping in mind that core dev support for Python 2.7 ended less than 5 years ago, and commercial support is still available (e.g. ActiveState just published their Python 2.7.18.8 build, and while RHEL 7’s Python 2.7 support hits its regular EOL at the end of this month, Red Hat’s Extended Update Support offering can push that deadline out another 4 years).

So even though, by the time we hit the 2026 release date, the Python 3 series will be nearly as old as the age of the first public Python release back when 3.0 was first released[1], it’s still worth being respectful of the concerns of the folks that found the Python 2->3 transition to be a disruptive annoyance.


  1. February 1991 → December 2008 ~= 17 years, 11 months; December 2008 → October 2026 ~= 17 years, 10 months ↩︎

4 Likes

While no one has trouble understanding it, I’ve seen some people almost getting upset that Pytho would use a versioning scheme so similar to SemVer. But that’s an attitude problem rather than a technical one.

I like the proposal in this PEP and it would make a bit more sense than the current scheme. But I’m also not sure there’s enough benefit to switch.

4 Likes

It’s also worth noting that SemVer.org demands more than what people think of when they talk about three-part version numbers. For example, my interactive Python is currently 3.14.0a0 which violates the ninth point on that web site. So when people say “SemVer”, do they actually mean a completely strict reading of that specific web site, or do they really mean “it has three part versions and an X.Y release ought to be backward compatible”? And frankly, I don’t think there are very many large-scale projects out there that are completely backward compatible in their minor releases - every change breaks someone’s workflow.

Python’s policy has always been “practicality beats purity”. The version numbering system closely approximates to people’s expectations of backward compatibility. I don’t, for example, lock my scripts to Python version 3.11; I expect that any newer version of Python will usually work. And that’s mostly true. How will CalVer change this? What will I learn by it? Nothing. It tells me no more or less than the current version numbering system does. Compare:

  • Deprecation warning says “will break in 3.14”. Deprecation warning says “will break in 3.31”. Neither of these tells me when a particular version will start to be used, so it’s still just a version number.
  • There’s no warning, but stuff might happen to break. I originally installed something when Python 3.11 was current; will it run on 3.12? I originally installed something in 2030 when 3.28 was current; will it run on 3.29? In both cases: “Probably”.
  • I’m looking at a cool new feature. It says in the docs “Added in 3.11”. It says in the docs “Added in 3.28”. Can I use that on Debian Stable? The version number doesn’t tell me, I have to go and check packages.debian.org.

The release year gives you a bit of an idea of how old the release is, but (a) that only works if you know for sure that Python uses that scheme (less obvious with “3.31” than with, say, “2012f”), and (b) that’s really not all that useful as information goes.

And it won’t stop people from complaining that it’s similar to SemVer without actually being it. People will still make that complaint even if the versions are 3.31 instead of 3.14.

12 Likes

Personally I would like this change. I’m fine with the existing scheme and I don’t see a huge benefit with changing this:

  1. While people might confuse the current versioning scheme for SemVer, the suggested scheme doesn’t really solve the issue. You still keep the 3.XX structure that might be confused for SemVer.

  2. The new scheme can help calculating EOL. But only for people who are already familiar enough with the current schedule, and only if there will be no changes to the expected amount of support.

What if the total amount of expected support will need to change? It would still be confusing. Sure, we may not see any expected changes in the near future. But considering we’ve made changes to the release schedule as recently as Python 3.13 (though not any that affect the total amount of support time), I wouldn’t be relying on the stability of the current schedule.

1 Like

I am entirely unconvinced by the need or benefit of this proposal. I’ve never come across anyone who has a problem figuring out when EOL is (“we just look it up”), but I regularly come across people who assume that 3.(n+1) is a compatible update to 3.n. As this proposal doesn’t fix that, I fail to see how it improves any situation enough to be worth the churn.

Surely it would be easier to put the EOL date into the sys.version string or a sys.version_info field if people are regularly trying to guess the date from the version number?

21 Likes

And as a practical matter, the official EOL date is not that important or relevant to many users of Python, particularly if they are using Pythons from the many downstream distributors who provide extended support for EOL versions. So I don’t think making the CPython project EOL date easier to discover should be a major motivation for making a change like this.

16 Likes

I think the November release and its resultant off by almost one error is already enough nuance that I’d send people the Python release schedule page URL (or tell them to run norwegianblue python) instead of trying to explain it.

In my experience, 100% of the people who’ve asked me anything to do with this (usually what versions they should aim to support) weren’t expecting there to be an official scheduled support model at all. Calender versioning isn’t going to fix that.

4 Likes

tl;dr: that colour sounds great.

Beat me to it! But in truth it would be nice if there were one obvious way to do it. Your suggestion echoes the position in car models, where the 27 “model year” starts in '26; so the leading wave who actually exercise each production release in anger will be able to feel they are using “next year’s Python.”

Some will argue this is marketing. My response? “So what? Aren’t we (PSF members) supposed to ‘promote the Python programming language’?”

And clearly whichever is chosen it will cause no actual breakage.

How would this affect sys.version_info? Would it also jump from (3, 14, ...) to (3, 26, ...)?

Yes, it would continue to report the version:

>>> sys.version_info
sys.version_info(major=3, minor=26, micro=0, ...)
>>> sys.version
'3.26.0 (v3.26.0:..., Oct 1 2026, 12:50:24) [...]'
>>> platform.python_version()
'3.26.0'
>>> platform.python_version_tuple()
('3', '26', '0')

Nitpick: October release, but I get your point, and thanks for the norwegianblue plug :wink:

I will add that there are many alphas, betas, and release candidates during the release year, at least 10. We very much want people to be aware the release is coming, to get involved and start testing and reporting bugs before the big October release so we can fix them.

For example, during the beta phase, third-party library maintainers are strongly encouraged to test, and it’s extremely important to get as much exposure as possible.

Yes, this is an excellent point. :+1:

1 Like

I really like this change and the PEP is well written, thanks @hugovk! I support this PEP :+1:

5 Likes

Sorry if this has already been mentioned… I was talking about this proposal with two friends who oversee Python upgrades for a large open source project. They didn’t realize that Python has regular yearly releases each October. Changing to calver helps underscore this fact and educates people about the release process in general. The releases are calendar-based, the version number should be as well.

I’m in favor of this proposal.

8 Likes

Would “3.23” have helped this, though? Presumably “3.2023” would have, but “.23” is surely just a viable version increment and not obviously a year.

We’d still have to educate people about what changes they can expect year-to-year, which is vastly more important to them (whether they realise or not) than the frequency or date of the release.

6 Likes