PEP 2026: Calendar versioning for Python

If you want to assign “breaking” semantics to our X.Y.Z numbering scheme:

  • X represents breaking syntax changes to the language (and implicitly, pure-Python code[1]), and anything downstream of that (i.e. native ABI)
  • Y represents breaking ABI changes to native extensions
  • Z represents no breaking changes

The deprecation/removal semantics, bugfix semantics, and feature addition semantics can be similarly tied to the parts of our version numbers. Most core developers have a good feel for what fits in each (and release managers should have a very good feel for it), even if it isn’t written down. Since these are largely treated as guidelines rather than rules, we like it that way, though as the number of rule-preferrers grows I imagine we’ll formalise them into rules at some point.[2]

So we do in fact do semantic versioning. We just don’t do SemVer™.


  1. Making async and await non-contextual without bumping the 3 was incorrect under this scheme. ↩︎

  2. Which, IMHO, will make development harder and cause more breakage than it solves. But I don’t suffer the angst around not having strict rules that affects some others. ↩︎

6 Likes

@Rosuav @hugovk @steve.dower Thanks for your thoughtful replies guys, especially since it was a slightly off-topic question.

One on-topic thought from me, considering @sorcio’s list:

If the PSF were a big tech giant then something Python might very well do would be to adopt the PEP’s 3.YY.micro versioning and then refer to an annual release officially and in marketing exclusively by the year number.

I.e. the first release following the PEP in 2026 would be 3.26 but referred to as Python 26, a la C, C++, Fortran etc. That would cement the calendar versioning in people’s heads without having made a drastic change to the version numbers themselves.

1 Like

To me, Python 26 already means Python 2.6.

4 Likes

Dual versioning schemes like this are utterly confusing to me, and I suspect I’m not the only one.

15 Likes

To be clear, this is not what I suggested should be considered. IMO having a dual versioning scheme is only likely to add to the confusion.

I’d prefer explicit communication on the lifetime of any release, regardless of versioning scheme (whether it stays the same, or someone decides to adopt a new one). I’m personally skeptical that the versioning change would improve communication, so I’m asking why it’s being suggested and which alternatives have been considered.

Marginally, please let’s not conflate this with the Rust “editions” scheme, which is not about versioning in the same way we are talking about here, and is not applicable. Rust editions follow a year numbering because they are supposed to be rare enough, and are not regularly released. But each current Rust compiler release has its own version number, it’s released on a six-week cycle, and must support all “editions” back to the first one.

2 Likes

No, indeed, especially when there’s a mismatch between the official number and version number like Windows 11 being version 10.whatever. I’m not necessarily saying the example of Microsoft and co is a good one to follow, I just thought I’d mention it since it’s a possibility and one that’s commonly seen elsewhere. :slight_smile:

to me, the informational value of 3.26 would basically be the same as 3.15.2026_10 (or similar). I.e. an indicator of the release date. Replacing the monotonic patch portion of the number would be the least disruptive (in that it wouldn’t disrupt or confuse really anything imo), and would have the “same” benefits as the PEP, in my mind.

I perused the comments and mostly saw that people didn’t like mixed-semantic numbers for some reason, but it’s not exactly obvious to me why it’d be a bad idea, particularly if it’s just on the patch version.

With that said, the status quo seems fine to me.

6 Likes

Thanks everyone for this discussion! Also based on many discussions at EuroPython, I’m going to stick with 3.YY (for example, 3.26) rather than 3.YYYY (3.2026).

A few people in this thread said they didn’t realise pip used CalVer because it has a two-digit YY.x and not YYYY.x. Maybe so, however I think once you do know and you run pip --version on a system and see something like 21.0, well, now you know it’s about time to upgrade :slight_smile: Similarly, if I get an installation bug report for a package and see an old pip version, I’ll first ask them to upgrade.

3.YYYY seems relatively safe, but changes to adapt PY_VERSION_HEX in patchlevel.h could cause some issues. YY.x and YYYY.x are much bigger changes. Therefore let’s try 3.YY.

As Petr said, 3.YY is not a big change, and I agree it’s nevertheless a worthwhile one. Not much changes, and we get to do something more useful with the version number.

As requested by Greg and others, I’ve updated the PEP to add a number of options of how we could deal multiple releases in a year, and for releasing less often than a year, or even ditching CalVer altogether in the future. Adopting CalVer now does not preclude moving away CalVer in the future.

I’ve also added some more benefits, in part based on Alyssa’s feedback. This is not just about EOLs, but “using CalVer makes everything easier to translate into calendar time rather than counting versions and looking up when they will be (or were) released.”

I plan to submit the PEP to the SC soon.

5 Likes

Speaking as a pip maintainer, I will say that I read that statement, even in the context given here, and it still took me a moment to think “what’s so old about pip 21?” Yes, we use calver. And yes, the logic is easy to remember/work out. But it still isn’t intuitive.

It’s not a big deal, and I really don’t want to make a debate out of it - I remain -1 on this proposal for other reasons - but I do think you overestimate the obviousness of YY date values.

19 Likes

As I said, once you do know.

I picked pip 21 out of the air, but as a topical example, it’s too old to install packages with C extensions in the free-threaded 3.13 build.

Opting into experimental features requires choosing experimental packages, so I don’t think the front of the version number is a guide here anyway.

But there will be other examples that do justify “oh, this is 2-3 years old, no wonder it’s not working” as a legitimate reaction.

2 Likes

Yep, something like pip 19.2 was needed to install wheels on Windows with Python 3.8 (released in 2019).

That wasn’t my point. What I was trying to get at was that even though I know pip uses calver I still didn’t immediately realise that pip 21 was released in 2021.

Ironically, it’s semvar (and specifically the fact that some projects see semver as a reason to escalate version numbers rather than reduce the number of breaking changes) that has normalised projects with major version numbers in the 20+ range, which in turn has made YY-based calver less obvious…

18 Likes

I’m not taking a stance on the PEP, but that statement doesn’t make sense to me. IMO either one knows that pip uses CalVer (and then 21 ↔ 2021 is obvious), or one doesn’t. I can’t understand how one can simultaneously know of that relation, yet fail to apply it in the one place where it matters. :person_shrugging:

1 Like

It’s called forgetting :sweat_smile: one can know something intellectually and not immediately think of it in the moment.

9 Likes

Added in python/peps#3995 and PEP submitted to the SC in python/steering-council#255.

Thanks all!

5 Likes

Even if you know AND remember that pip uses calver, it still tells you nothing beyond “it’s 2-3 years old”. It tells you nothing about whether it’s current, nothing about whether it lacks important and meaningful features. Unless code begins to rust, mere age alone isn’t all that useful an indication.

How many patch notes do I have to read in order to know how much pip has changed (potentially backward incompatibly) since version 21?

3 Likes

Only the latest version of pip is ever supported. So if you have a pip < 23 you know you probably should update. In practical terms it means that if you encounter an issue with pip, the pip team will likely first ask you to reproduce the issue with the latest pip version and if it is not reproducible with latest pip then the issue will likely be closed as “won’t fix”.

To summarize the pip version string gives you a very good approximation of whether or not this version is supported.

https://pip.pypa.io/en/stable/development/release-process/#supported-versions

That is true for pip, but this thread is about applying the same to Python, for which that policy does not apply.

I’m not in general in favor of calendar versioning and nothing in this thread has made me feel like changing that view. I tend to subscribe to the old-school versioning philosophy that versions should be based on functionality and not time, i.e., you release a new version when you have something that is enough of an improvement on the old one to make a new release worthwhile and meaningful to users, and you support old versions as long as reasonably possible (or longer :slight_smile: ) to avoid disruption to users.

Thanks for your suggestion but this is very off-topic, please open a new thread in Ideas if you wish to propose dropping annual releases for an “enough new stuff” policy, and the 5 year support window for “as long as reasonably possible”.