Long story short: I’m finally starting to drop Python 2 (and a few slightly older Python 3s) from my projects, in a phased manner. Background and details follow.
A brief timeline
Writing this out made me feel
- 2004: I’m introduced to Python (2.2/2.3) at the end of my time serving a CS degree.
- 2008: My OSS career kicks into gear as I take over Fabric. Python 2.4 and
2.5 were stable, 2.6 comes out in the fall, and 3.0 in winter.
- 3.x has been around the entire time I’ve maintained Fabric!
- 2010: Python 2.7 is released. That’s 11 years ago!
- 2012: Python 3.3, considered the first “really usable” version (especially for 2+3 codebases), comes out.
- 2013-2014: Invoke and Fabric 2 start development, with Python 3 support right out the gate; Paramiko gains Python 3 support.
- 2016: Python 3.6 is is born, with f-strings and ordered dicts.
- 2018-2019: Every widespread Linux distribution switches to Python 3, if
they hadn’t already.
- The exception is RHEL/CentOS, which switches in 2020.
- Python 3.4 reaches EOL (End of Life) in mid 2019.
- Around this time (if not sooner) many Python 3-only packages declare Python 3.6 as their baseline supported version.
- Python 2, in its entirety, is EOL’d in January. This is an ex-interpreter!
- Python 3.5 reaches EOL.
- I admit burnout.
- Early 2021: Pip drops support for Python 2, as does Cryptography (a Paramiko dependency which is unsafe to pin for long).
And here we are.
The timeline is a bit implicit; let’s be explicit. Why am I doing this now?
- It’s past time. I’m quite conservative on the maintainer spectrum, but by now – with the interpreter, package installer, many/most packages, and most/all Linux distributions all leaving Python 2 behind – I’m in good company.
- It’s decreasingly likely that my software is the first thing pushing you to upgrade. If you’re still on Python 2 in 2021, you’re already committed to a lack of updates from all of the above sources. I’m just one more.
- The iron triangle has shifted. An old post is still relevant; ease of maintenance (because burnout) and speed (the current release cadence is unacceptable) are tipping the scales against stability (in the “things don’t change” sense).
- Most downloads have been Python 3 for years. Going by
PyPIStats, even the most conservative userbase I
answer to (surprisingly Fabric, not Paramiko) is only 33% Python 2.
- I don’t have a useful breakdown, but I’d also guess that 33% is heavily slated towards Fabric 1 users, who are already largely unsupported.
- Paramiko is down to <=20% Python 2.
- Invoke (and by extension, most users of Fabric 2) has always been <=10%
- Alabaster is at 10%; etc.
- Combining the above two: I’d prefer to think of this as improving quality and release cadence for a majority of users, instead of worrying about its impacts on a recalcitrant minority.
- Finally: nothing’s getting deleted. Same as any backwards incompatible release: existing Python 2-supporting releases remain on PyPI.
I am planning a phased removal of support for Pythons 2.7, 3.4 and 3.5, as follows:
- The first step will be to remove CI support for old Pythons.
- This will happen as I migrate to CircleCI from the now-defunct Travis-CI over the next few weeks/months.
- Doing it this way saves me from reproducing a lot of frustrating busywork in my scripting, and also slims the test matrix – which is important now that CI providers track how much CPU time we burn!
- But it means that there’s still a short grace period for users (see below), as my local env will still be doing basic Python 2 test runs.
- The next step, which may happen at the same time, is to update development dependencies to assume Python 3.6+.
- There will likely be 1-2 more release cycles which include Python 2
- This works because I still generate those artifacts locally and not from CI (yet).
- Included in this is Fabric 1’s still-planned Python 3 support merge, for a final release of that line. This provides users an upgrade path: Python 3, then later Fabric 2+.
- Finally, the last trio of changes will happen around the same time:
- Project tooling will drop old Python support, including build/publish tasks and packaging metadata.
- Python 2-related syntax will be removed from the code itself.
- Versions of most packages will bump their major qualifier to signify the
change (though it’s unlikely any other backwards incompatible changes will
- Invoke will go to 2.0
- Paramiko will go to 3.0
- Fabric will remain on 2.x because it’s got a more complicated history here
- thus, this will probably be Fabric 2.8 or 2.9, with 2.7 or 2.8 being the last Python 2-supporting release.