python2.7 will be removed from the images on June 12, 2023
mikhailkoliada opened this issue · 28 comments
Breaking changes
Python 2.7 will be removed from the images' tool cache.
Target date
The image rollout will start on June 12, 2023 and take 3-4 days.
The motivation for the changes
Python2.7 is not supported since January 1, 2020.
Possible impact
If your builds depend on python2.7 they will be broken.
Platforms affected
- Azure DevOps
- GitHub Actions
Runner images affected
- Ubuntu 20.04
- Ubuntu 22.04
- macOS 11
- macOS 12
- Windows Server 2019
- Windows Server 2022
Mitigation ways
No specific steps should be taken.
Python2.7 is not supported since January 1, 2022.
Correction: it's 2020, not 2022. The linked documents don't even mention 2022.
@vitalkanev true that! Fixed, thanks :)
Can I ask for clarification of the exact implications of this - is this just being removed from the runners tool cache, but would still be installable using the @setup-python
action, or does this change have implications for the correct operation of @setup-python
action as well?
Bumping the question above, as the implications of this still aren't entirely clear.
This rollout seems to have affected some builds with Wine: #4589
Is it possible to request the old image version as part of a build?
Any more information here? I had assumed as the date had passed this was not going to cause us any issues, but on checking back I see the rollout has been delayed. Could we get clarity before this is rolled out?
I still have to support users on 2.7 python, so having a test environment that supports 2.7 is important.
So to bump the requests above, will I have to use an 18.04 image to test on 2.7 or find another test service like travis?
For anyone interested in building and publishing Python 2 Only packages I've created an action listed in the Marketplace: python2-pypi-upload
@rtibbles @rouilj Hello! Python2.7 is planned to be removed from the setup-python as well.
@dmitry-shibanov can comment on this more.
The setup-python announcement: actions/setup-python#672
There is not even an announcement on https://github.blog/?s=python, hence I see no official stamp for that.
hugovk wrote on https://mastodon.social/@hugovk/110235359333000764:
- February 2020: GitHub said they'd remove 2.7 from Actions. https://github.blog/changelog/2020-02-27-github-actions-breaking-change-python-2-being-removed-from-all-virtual-environments/
- March 2020: GitHub said they'd exceptionally keep 2.7 longer. https://github.com/actions>/setup-python/issues/63#issuecomment-596450646
- November 2022: GitHub removed 2.7 from Actions.
- December 2022: GitHub added 2.7 back to Actions.
- April 2023: GitHub announced they'll be removing 2.7 in May 2023.
It has already been delayed.
@konradpabjan I hope this can be cancelled like the previous times. I think there will be customer backslash again which would not be justified.
There is no point in removing it.
Linux Distros like Ubuntu 20.04 which contain Python2.7 support Python 2.7 for many many years to come. Canonical will maintain it until April 2025, and it will have emergency security updates in 20.04 until April 2030. Similar for Red Hat and SUSE.
You omitted some important bits from my Mastodon post, I re-add with emphasis here:
Python was originally planned to be EOL in 2015.
2014: they moved it 5 years to Jan 2020. https://peps.python.org/pep-0373/
February 2020: GitHub said they'd remove 2.7 from Actions. https://github.blog/changelog/2020-02-27-github-actions-breaking-change-python-2-being-removed-from-all-virtual-environments/
March 2020: GitHub said they'd exceptionally keep 2.7 longer. actions/setup-python#63 (comment)
November 2022: GitHub removed 2.7 from Actions.
December 2022: GitHub added 2.7 back to Actions.
April 2023: GitHub announced they'll be removing 2.7 in May 2023.
How much more time do you need?
If you really need to use Python 2.7, you may be able to use PyPy instead, which does not plan to drop support for Python 2.7.
How long will PyPy support Python2?¶
Since RPython is built on top of Python2 and that is extremely unlikely to change, the Python2 version of PyPy will be around “forever”, i.e. as long as PyPy itself is around.
Is PyPy a drop in replacement for CPython?¶
Almost!
[...]
There don't seem to be any plans to drop PyPy 2.7 from GitHub Actions as far as I can tell.
Both responses fail to provide any justification why to remove Python2:
- Just because it's old doesn't mean it that it has no users relying on it.
- Just because there is pypy doesn't mean that pypy is a replacement for Python2:
pypy -m pip install pyliblzma
DEPRECATION: pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
Defaulting to user installation because normal site-packages is not writeable
Collecting pyliblzma
Using cached pyliblzma-0.5.3.tar.bz2 (43 kB)
Using legacy 'setup.py install' for pyliblzma, since package 'wheel' is not installed.
Installing collected packages: pyliblzma
Running setup.py install for pyliblzma ... error
ERROR: Command errored out with exit status 1:
command: /usr/bin/pypy -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-jq8Zxd/pyliblzma/setup.py'"'"'; __file__='"'"'/tmp/pip-install-jq8Zxd/pyliblzma/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-6Wi7Iu/install-record.txt --single-version-externally-managed --user --prefix= --compile --install-headers /home/bkaindl/.local/include/python2.7/pyliblzma
cwd: /tmp/pip-install-jq8Zxd/pyliblzma/
Complete output (88 lines):
running install
running build
running build_py
creating build
creating build/lib.linux-x86_64-2.7
copying liblzma.py -> build/lib.linux-x86_64-2.7
running build_ext
building 'lzma' extension
creating build/temp.linux-x86_64-2.7
creating build/temp.linux-x86_64-2.7/src
cc -pthread -DNDEBUG -O2 -fPIC -DVERSION="0.5.3" -I/usr/lib64/pypy-7.3/include -c src/liblzma.c -o build/temp.linux-x86_64-2.7/src/liblzma.o -Wall -Wextra -pedantic -Wswitch-enum -Wswitch-default -std=gnu99
src/liblzma.c:234:22: warning: cast between incompatible function types from ‘PyObject * (*)(PyObject *, PyObject *, PyObject *)’ {aka ‘struct _object * (*)(struct _object *, struct _object *, struct _object *)’} to ‘PyObject * (*)(PyObject *, PyObject *)’ {aka ‘struct _object * (*)(struct _object *, struct _object *)’} [-Wcast-function-type]
234 | {"compress", (PyCFunction)LZMA_compress,
| ^
src/liblzma.c:240:24: warning: cast between incompatible function types from ‘PyObject * (*)(PyObject *, PyObject *, PyObject *)’ {aka ‘struct _object * (*)(struct _object *, struct _object *, struct _object *)’} to ‘PyObject * (*)(PyObject *, PyObject *)’ {aka ‘struct _object * (*)(struct _object *, struct _object *)’} [-Wcast-function-type]
240 | {"decompress", (PyCFunction)LZMA_decompress,
| ^
In file included from /usr/lib64/pypy-7.3/include/Python.h:79,
from src/liblzma.h:8,
from src/liblzma.c:1:
src/liblzma.c: In function ‘initlzma’:
/usr/lib64/pypy-7.3/include/object.h:65:35: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
65 | #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
| ~^~~~~~~~~~~~~~~~
src/liblzma.c:259:9: note: in expansion of macro ‘Py_TYPE’
259 | Py_TYPE(&LZMAComp_Type) = &PyType_Type;
| ^~~~~~~
/usr/lib64/pypy-7.3/include/object.h:65:35: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
65 | #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
| ~^~~~~~~~~~~~~~~~
src/liblzma.c:260:9: note: in expansion of macro ‘Py_TYPE’
260 | Py_TYPE(&LZMADecomp_Type) = &PyType_Type;
| ^~~~~~~
/usr/lib64/pypy-7.3/include/object.h:65:35: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
65 | #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
| ~^~~~~~~~~~~~~~~~
src/liblzma.c:261:9: note: in expansion of macro ‘Py_TYPE’
261 | Py_TYPE(&LZMAFile_Type) = &PyType_Type;
| ^~~~~~~
/usr/lib64/pypy-7.3/include/object.h:37:27: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
37 | #define Py_INCREF(ob) (((PyObject *)(ob))->ob_refcnt++)
| ~^~~~~~~~~~~~~~~~~
src/liblzma.c:279:9: note: in expansion of macro ‘Py_INCREF’
279 | Py_INCREF(&LZMAOptions_Type);
| ^~~~~~~~~
/usr/lib64/pypy-7.3/include/object.h:37:27: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
37 | #define Py_INCREF(ob) (((PyObject *)(ob))->ob_refcnt++)
| ~^~~~~~~~~~~~~~~~~
src/liblzma.c:282:9: note: in expansion of macro ‘Py_INCREF’
282 | Py_INCREF(&LZMAComp_Type);
| ^~~~~~~~~
/usr/lib64/pypy-7.3/include/object.h:37:27: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
37 | #define Py_INCREF(ob) (((PyObject *)(ob))->ob_refcnt++)
| ~^~~~~~~~~~~~~~~~~
src/liblzma.c:285:9: note: in expansion of macro ‘Py_INCREF’
285 | Py_INCREF(&LZMADecomp_Type);
| ^~~~~~~~~
/usr/lib64/pypy-7.3/include/object.h:37:27: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
37 | #define Py_INCREF(ob) (((PyObject *)(ob))->ob_refcnt++)
| ~^~~~~~~~~~~~~~~~~
src/liblzma.c:288:9: note: in expansion of macro ‘Py_INCREF’
288 | Py_INCREF(&LZMAFile_Type);
| ^~~~~~~~~
cc -pthread -DNDEBUG -O2 -fPIC -DVERSION="0.5.3" -I/usr/lib64/pypy-7.3/include -c src/liblzma_compressobj.c -o build/temp.linux-x86_64-2.7/src/liblzma_compressobj.o -Wall -Wextra -pedantic -Wswitch-enum -Wswitch-default -std=gnu99
src/liblzma_compressobj.c: In function ‘LZMAComp_flush’:
src/liblzma_compressobj.c:108:9: warning: enumeration value ‘LZMA_FULL_BARRIER’ not handled in switch [-Wswitch-enum]
108 | switch(flushmode){
| ^~~~~~
src/liblzma_compressobj.c: At top level:
src/liblzma_compressobj.c:228:19: warning: cast between incompatible function types from ‘PyObject * (*)(LZMACompObject *, PyObject *, PyObject *)’ {aka ‘struct _object * (*)(LZMACompObject *, struct _object *, struct _object *)’} to ‘PyObject * (*)(PyObject *, PyObject *)’ {aka ‘struct _object * (*)(struct _object *, struct _object *)’} [-Wcast-function-type]
228 | {"reset", (PyCFunction)LZMAComp_reset, METH_VARARGS | METH_KEYWORDS,
| ^
src/liblzma_compressobj.c:359:9: error: ‘_PyObject_Del’ undeclared here (not in a function); did you mean ‘PyObject_Del’?
359 | _PyObject_Del, /*tp_free*/
| ^~~~~~~~~~~~~
| PyObject_Del
src/liblzma_compressobj.c:368:1: warning: missing initializer for field ‘tp_pypy_flags’ of ‘PyTypeObject’ {aka ‘struct _typeobject’} [-Wmissing-field-initializers]
368 | };
| ^
In file included from /usr/lib64/pypy-7.3/include/object.h:10,
from /usr/lib64/pypy-7.3/include/Python.h:79,
from src/liblzma.h:8,
from src/liblzma_compressobj.h:4,
from src/liblzma_compressobj.c:1:
/usr/lib64/pypy-7.3/include/cpyext_object.h:310:10: note: ‘tp_pypy_flags’ declared here
310 | long tp_pypy_flags;
| ^~~~~~~~~~~~~
error: command 'cc' failed with exit status 1
----------------------------------------
ERROR: Command errored out with exit status 1: /usr/bin/pypy -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-jq8Zxd/pyliblzma/setup.py'"'"'; __file__='"'"'/tmp/pip-install-jq8Zxd/pyliblzma/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-6Wi7Iu/install-record.txt --single-version-externally-managed --user --prefix= --compile --install-headers /home/bkaindl/.local/include/python2.7/pyliblzma Check the logs for full command output.
=
Instead of moving off Python2 simpler (which I agree is the goal), you are making migrating off it harder for the migration time where a large code base has to work for both Python2 and Python3 until all code is fully migrated and tested for production on Python3.
Justification: everything has a maintenance cost, especially EOL things. This may have a large running cost too.
Alternative: You can use Docker on GitHub Actions (and I expect Azure Pipelines) to test whatever version you need and maintain it yourself.
Putting the original 2015 EOL to one side, there was six years' notice for the 2020 EOL.
There has now been an extra 3.5 years grace period since it went EOL.
Serious question: how much more time do you need?
Alternative: You can use Docker on GitHub Actions (and I expect Azure Pipelines) to test whatever version you need and maintain it yourself.
I have just successfully tested this option using coatldev/six:3.10.11a9 which comes with Python 3.10.11 and 2.7.18. See: thecesrom/incendium/pull/153.
And I expect that to work on Azure Pipelines (ref: jobs.job.container definition | Microsoft Learn).
I'll soon post my Dockerfile to a repo under the coatl-dev org, so stay tuned.
Justification: everything has a maintenance cost, especially EOL things. This may have a large running cost too.
That is rather short and leaves a lot to imagination and does not quantify anything.
I'd think it should have little overhead since it should only be activated when used.
As 2.7 is EOL, it doesn't get any updates or fixes, so the maintenance burden should be low.
Serious question: how much more time do you need?
Serious answer: Until November. We are in the progress, but in no way we can be finished by June 19.
A little more time would be good, a couple more months should not make the big difference?
Dockerfile: good work!
Just five more months, when we've already had an extra ~42 months. Does someone else need just a couple extra months until January 2024? November 2024? 2025?
If the maintenance burden should be low, the good news is you can soon use the Dockerfile until November and beyond :) The Docker support is very good, we use it for testing a lot of different varieties of Linux.
I just ran into this problem with the windows-2019 image. Our use of Linux and macOS was entirely unaffected since we only test python2 on Linux and Windows, and the Linux tests use generic distro docker containers with apt/rpm installed dependencies.
Our use case is a bit different than the norm, though, since we're an open-source build system which is unashamedly written in python3, but does support detecting a python2 in order to build python2 modules. There is... honestly, no intention to ever drop that support. It's cleanly factored out and incurs no real maintenance cost. It also allows verifying important qualities, such as the ability to build modules for multiple interpreters as part of the same build, including that we correctly handle major version numbers (relevant in the event of a python 4.0). Finally, while I agree that maintained software should be upgraded to modern pythons, I think there's a pretty good argument for keeping support in build systems indefinitely, for the same general reason that projects like Software Heritage or the Heirloom Toolchest exist.
That being said, I suppose it is not a huge deal to download and install the .msi for python 2.7.18 in our workflow steps... it's just a bit more time, the Windows runners are used to running long after the others finished...
I did spend a bit of time very confused though, because the failures were not at all reproducible. It seems like some images have python2 installed, and some do not, and it's a bit random whether you'll have it available. It's thus also not something I can mark as an expected skip.
Alternative: You can use Docker on GitHub Actions (and I expect Azure Pipelines) to test whatever version you need and maintain it yourself.
[...]
I'll soon post my Dockerfile to a repo under the coatl-dev org, so stay tuned.
@thecesrom thanks for dong this. Do you use any external services in your testing? My github CI action deploys and does custom configuration for postgresql, mysql, and redis to be able to test the Python application.
I guess I am going to have to:
- figure out how to make my app running in your container talk to these services running outside the container
- or build customized docker containers for all these services and spin all of them up and down for every test.
Sadly it's many hours of non-productive work either way.
Serious question: how much more time do you need?
To give some perspective on this - we have continued to support Python 2.7 with https://github.com/learningequality/kolibri based on our telemetry data which suggests that we still have a small but significant (roughly 2%) of active installed devices that are using Python 2.7. In addition, as our primary target is offline usage, there is the potential for a considerably larger number of offline users who are less able to run up to date Python versions.
We are in the process of deprecating Python 2.7 now that we have got down to only ~2% of recorded pingbacks, but we are also highly conscious of wanting to support the widest range of hardware and software we can.
This doesn't mean that you need to change course here - we can work around it until we are ready, but just wanted to give some additional perspective on why we are still actively using Python 2.7.
The software I support has per site programming in Python. Business logic is written in Python and needs to be upgraded/rewritten/tested under python 3 for each tracker deployment.
Deprecation for Python 2 started with the first release that supported Python 3 in 2020.
My original plan was to support python 2 until the 2020 long term support (LTS) distros went out of support. That is in 2025 for Ubuntu and similarly for Debian 9. RedHat support was expected to end after full support ended again in 5 years. Less than a year ago I had somebody upgrade to python 3 because they went to a new platform that dropped support for python 2. I expected similar platform upgrades to drive movement to Python 3.
Obviously I'll have to make a decision about the 2024 and 2025 version support for python 2.
Removed from the image.
As 2.7 is EOL, it doesn't get any updates or fixes, so the maintenance burden should be low.
I second that. The work involved on your side to "keep it working" might be a little higher now that it actually was removed, but I still don't understand why you have decided to replace an "it's there, it still works, no changes" maintenance burden with a "please switch to an entirely different setup and bring that to work" for all of your users that still need it. That seems a very costly step overall.
Serious question: how much more time do you need?
It seems like another year would have helped. Many projects have been removing Py2 support gradually only during the last year, and it's still going up the dependency chains. Removing support now will probably accelerate that ("sorry, we can't test it any more, and don't have the time to add back the support"), but it's also a hard blow.
IMHO, the removal now is still too early. Reading the discussion above, the deadline seems entirely arbitrary. So why not move it by another year again?
My solution for Windows was to simply download https://www.python.org/ftp/python/2.7.18/python-2.7.18.amd64.msi and run msiexec.exe
on it. I do not think any maintenance burden is involved here. Probably, the VM image is slightly smaller without this...
For Linux there might be a slightly higher maintenance burden on the runner-images although I would have assumed the only real, meaningful difference is a version number on the list of source tarballs that are looped over, downloaded, and ./configure && make && make install
ed.
For anyone who still needs to run Python 2.7 on Windows in GitHub actions, here's an Actions step I came up with after a lot of trial and error:
- name: Install Python 2.7.18
shell: cmd
run: |
choco install wget --no-progress
wget -nv "https://www.python.org/ftp/python/2.7.18/python-2.7.18.amd64.msi"
start /wait msiexec.exe /passive /i python-2.7.18.amd64.msi /norestart /L*V "python_install.log" ADDLOCAL=ALL ALLUSERS=1 TARGETDIR=c:\python27
type "python_install.log"
This step takes about 60 secs to run for me.
@anthonyeden, perhaps you could try choco install python2
.
On the other hand, I've created an action for publishing Python2-only packages available here, and a Docker image with Python 3.10 and 2.7 called coatldev/six.