[Python-Dev] Python version numbers

On 04/03/2018 12:36 PM, Brett Cannon wrote:
> On Tue, 3 Apr 2018 at 07:39 Paul G <paul at ganssle.io> wrote:
> Paul's point is that he knows e.g. code working in 3.6.0 will work when he
> upgrades to 3.6.5, and if his code is warning-free and works with all
> __future__ statements in 3.6 that it will work fine in 3.7. With CalVer you
> could make a similar promise if you keep the major version the year of
> release and then keep our feature/bugfix number promise like we already
> have, but at that point who cares about the year?
I think it is reasonable to use a scheme like this:
YY.MM.patch
The canonical release is numbered by Year-Month, and patches intended to add new features and break nothing get a patch release, no matter when they are released. That allows for simple pinning.
> While we have an 18 month schedule for releases, we also can't guarantee we
> will hit our release window in a specific year, e.g. 3.6 was first released
> in December but we could have slipped into January. That makes promises for
> a specific version tied to a year number problematic.
I think no promises for a specific version number need to be made until *after* a release is made. Using calendar-based versioning facilitates using a calendar-based deprecation schedule, irrespective of how many releases have occurred between the deprecation and the removal. If the promise is "we will support this feature for 5 years", then you know ahead of time the minimum version number in which that feature will be removed.
So say you have a function foo() called in your library that is deprecated in the 20.05.0 feature release. You know at that point that any release *after* 25.05.0 will drop support for foo, so on your next release that uses foo(), you set the upper bound on your `requires_python` to `<25.05.0`. It doesn't matter if that release happens in 2025-08 or 2027-01.
Similarly if you are developing some cutting edge library that is using features from the "feature release" branch, you can set `requires_python` to some value with a month greater than the current calendar version.
> If we chose to switch to semantic versioning, we would probably make it so
> that any version that makes a __future__ statement the new default is a
> major version bump. But then the issue becomes the stdlib. Do we drop
> everything that was previously deprecated in the stdlib for every major
> version bump? That might be a bit drastic when e.g. all you did was make
> old code that used `await` as a variable name raise a SyntaxError. And
> saying "deprecated for two versions" then becomes messy because you have no
> idea what that second version will be. And what if you **really** want to
> get rid of something in the next release? Can a single module dropping a
> function force a version bump for Python itself?
This is why I suggested a calendar-version based approach, along with a pre-commitment that the "rolling backwards compatibility window" would be a specific amount of *time*, not a specific number of versions. It makes it very easy to make predicitions about when specific features are falling in and out of that window, because each deprecation warning can come *pre-populated* with the length of the deprecation period and, as a result, the maximum version that will support that feature. If that were done, you could even concievably write a "compatibility checker" tool that can be run against a repo to calculate the `requires_python` upper bound and to order deprecation warnings by urgency.
> I have not read the other thread, but knowing it's from Lukasz makes me
> guess he wants to move up the minor number to become the major one in terms
> of our current semantics so we have a rolling window of support. That would
> mean that as long as you are warnings-free and run fine with all __future__
> statements turned on for version N then N+1 should work for you without
> modification (sans relying on buggy semantics). That approach would deal
> with the above issues cleanly while dropping what our current major number
> semantics which some people view as a fallacy and are getting upset over
> (I'm personally +0 on this last idea as it's easy to explain to folks and I
> have been doing Python version explanations a lot over the last several
> months).
>
Lukasz did not propose any changes to the version number semantics, just the deprecation schedule. I was suggesting that if this happens, it's probably a good idea to "drop" the major version number - either by incrementing it with each release that breaks backwards compat (which, for a sufficiently continuous influx of rolling deprecations should be basically every feature release), or by switching to a calendar-based system. From above, I think a calendar-based system has the best features for end users.