actions/setup-python

python2.7 will be removed from the python-versions on June 19

dmitry-shibanov opened this issue ยท 40 comments

Breaking changes

Hello everyone. The Python 2.7.x will be removed from python-versions and it won't be possible to set up Python 2.7.x by setup-python.

The motivation for the changes

Python2.7 is not supported since January 1, 2020.

Hi @dmitry-shibanov - do you have any recommended ways to mitigate this for those of us that cannot remove usage of Python 2.7 from our Github Actions before the June 19th deadline?

@dmitry-shibanov

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.

boegel commented

We started hitting this today already (1 June 2023), leading to:

Error: Version 2.7 with arch x64 not found

Support for Python 2.7 is deprecated in our project already, so we'll just stop testing on top of Python 2.7 and not lose sleep over it, but it would be nice if there's a documented/recommended alternative for people that do still want to keep testing on top of Python 2.7 in the near future.

hugovk commented

There's a community-maintained Dockerfile in the works: actions/runner-images#7401 (comment)

Guys, do we have a suggested workaround? This is a huge deal for us - whole project depends on python 2 so we would not be able to deploy anything. If anyone has an idea, please help :)

To anyone concerned:
You can continue using github-hosted runners with python2.7 by running the job inside a container.
e.g. I used python:2.7-buster image and everything works out just fine.

No need to use setup-python or be dependent of runner-images anymore.

If you don't need 2.7 for windows, you could use my custom action MatteoH2O1999/setup-python.
This action tries to build from source all Python versions that actions/setup-python does not support.
It also allows to cache built versions so that after the first run, installation time is really low.
For an example of a run see this workflow.

Windows support is in the works but no ETA (note that for Windows it will still allow for versions that are supported by 'actions/setup-python' to successfully complete).

To anyone concerned: You can continue using github-hosted runners with python2.7 by running the job inside a container. e.g. I used python:2.7-buster image and everything works out just fine.

Hello @tzortzispanagiotis, could you please provide an example for this? ๐Ÿ™

Thanks in advance.

Hello @dimitrisr,

In order to overcome this I modified:

runs-on: ubuntu-20.04

to

runs-on: ubuntu-20.04
    container:
      image: python:2.7.18-buster

So that the job is run using a github-hosted runner, but inside the python2.7-buster container, which has set up python2.7

Then I started running the pipeline and started fixing everything that was broken (because the container does not have things as sudo, so you have to install it with a command)

Also, If your CI pipeline has other services (e.g. mysql) that run inside a container, now that the whole job is running inside a container, the service container is accessible not through localhost (127.0.0.1), but through the service name.

I hope I was helpful!

Thank you @tzortzispanagiotis, this was really helpful! I was able to run the actions successfully :)

We are using a matrix in the Actions workflow file, where each matrix item specifies "os", "python-version" and one more parameter. Does anyone know how the python:2.7.18-buster container would be used with a matrix just for python 2.7?

Snippet from the workflow file:

jobs:

  set_matrix:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.select_matrix.outputs.matrix }}
    steps:
    - name: "Select matrix"
      id: select_matrix
      run: |
          echo "matrix={ \
            \"os\": [ \"ubuntu-latest\" ], \
            \"python-version\": [ \"3.10\", \"3.11\" ], \
            \"package_level\": [ \"minimum\", \"latest\", \"ansible\" ], \
            \"include\": [ \
              { \
                \"os\": \"ubuntu-20.04\", \
                \"python-version\": \"2.7\", \
                \"package_level\": \"minimum\" \
              }, \
              { \
                \"os\": \"ubuntu-20.04\", \
                \"python-version\": \"2.7\", \
                \"package_level\": \"latest\" \
              }, \
              { \
                \"os\": \"ubuntu-20.04\", \
                \"python-version\": \"3.5\", \
                \"package_level\": \"minimum\" \
              }, \
              { \
                \"os\": \"ubuntu-20.04\", \
                \"python-version\": \"3.5\", \
                \"package_level\": \"latest\" \
              }, \
              { \
                \"os\": \"ubuntu-20.04\", \
                \"python-version\": \"3.6\", \
                \"package_level\": \"minimum\" \
              }, \
              { \
                \"os\": \"ubuntu-latest\", \
                \"python-version\": \"3.7\", \
                \"package_level\": \"minimum\" \
              }, \
              . . .

  test:
    needs: set_matrix
    strategy:
      fail-fast: false
      max-parallel: 20
      matrix: ${{ fromJson(needs.set_matrix.outputs.matrix) }}
    runs-on: ${{ matrix.os }}
    steps:
        . . . 

Apart from trying to find a circumvention, I have to say that you are leaning quite a bit out of the window in the setup-python project if you remove Python 2.7 while some of the major Linux distros (e.g. Ubuntu and RedHat) still support it for some years to come.

Please add it back in.

I found out how it works when using a matrix:

In the include list in the matrix definition job:

              { \
                \"os\": \"ubuntu-20.04\", \
                \"python-version\": \"2.7\", \
                \"package_level\": \"minimum\", \
                \"container\": {\"image\": \"python:2.7.18-buster\"} \      # <---- added line
              }, \

In the test job:

  test:
    needs: set_matrix
    strategy:
      fail-fast: false
      max-parallel: 20
      matrix: ${{ fromJson(needs.set_matrix.outputs.matrix) }}
    runs-on: ${{ matrix.os }}
    container: ${{ matrix.container }}      # <---- added line
    steps:
    - name: Checkout repo
      uses: actions/checkout@v3
      with:
        fetch-depth: 0
    - name: Set up Python ${{ matrix.python-version }}
      if: ${{ ! ( matrix.python-version == '2.7' ) }}      # <---- added line
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
    . . . 

Hello everyone. I'm going to close the issue because python 2.7 was removed from python-versions.

IMHO this is egregiously shortsighted as it breaks every existing CI system that still tests on Python2.7, and will now require organizations to invest (often limited) resources into editing/auditing or rebuilding their CI infrastructure.

The appropriate way to handle this should have been to ensure existing integrations do not break, such as bumping the @version and dropping support for it in all future versions.

This decision leaves me with zero trust in Github and the actions ecosystem, and I am now actively looking to replace it. For commercial and open source projects, the risk of having to deal with decisions like this is not worth it.

Just to be clear: I don't have any expectation for additional support on Python2.7, such as maintenance, upgrades, integration on new platforms, or support on new versions. I did have a realistic expectation that workflows pinned to a versioned action and operating system would not have features yanked out.

rotu commented

It's very surprising that this was done without a major version bump - it seems to be an unambiguously breaking change. I would expect such a change in main branch, not v4.

per https://docs.github.com/en/actions/creating-actions/about-custom-actions#using-tags-for-release-management

Introduce a new major version tag (v2) for changes that will break existing workflows. For example, changing an action's inputs would be a breaking change.

per https://github.com/actions/toolkit/blob/main/docs/action-versioning.md#compatibility

Major versions should guarantee compatibility. A major version can add net new capabilities but should not break existing input compatibility or break existing workflows.

Major version binding allows you to take advantage of bug fixes and critical functionality and security fixes. The main branch has the latest code and is unstable to bind to since changes get committed to main and released to the market place by creating a tag.

Canonical will maintain [Python 2.7] until April 2025, and it will have emergency security updates in 20.04 until April 2030. Similar for Red Hat and SUSE.

Awesome. If you open an issue on your paid long term support contract then these companies will provide you a solution. This is why you are paying for LTS.

If you are not paying for LTS then do not be surprised that nobody is willing to continue to invest in software that died 1,271 days ago.

Canonical will maintain [Python 2.7] until April 2025, and it will have emergency security updates in 20.04 until April 2030. Similar for Red Hat and SUSE.

Awesome. If you open an issue on your paid long term support contract then these companies will provide you a solution. This is why you are paying for LTS.

If you are not paying for LTS then do not be surprised that nobody is willing to continue to invest in software that died 1,271 days ago.

I don't think anybody expected anyone to invest time on Python 2. That's why we were surprised that time was actively invested to make sure it does not work anymore when it still worked. A simple deprecation warning that said "Python 2.7 may encounter issues with dependencies in the future and is not guaranteed to remain functional" would have done the trick: nobody invests time on Python 2, neither to make it or break it

joamag commented

I agree it would have made more sense to just bump a major version number (to v5) of setup-python. Without the bumping many of the current CI pipelines are now failing, this is a bit disappointing.
I understand that Python 2.7 has been deprecated but that does not mean that nobody is using it in their CI pipelines.

scoder commented

It seems that Py2.7 is still installed by default (sic!) on the Ubuntu 20.04 images and can be used from there. So setup-python is not strictly needed and this CI step can be disabled for Py2.7 tests.

That's probably not a complete solution for everyone since the overall setup might then be sufficiently different to require additional work to get everything back in shape. But it's an option.

We opted to install Python 2 + pip on the ubuntu runner manually until we're ready to finally drop Python 2 support.

    - name: Set up Python ${{ matrix.python_version }}
      if: matrix.python_version != '2.7'
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python_version }}

    - name: Set up Python 2.7
      if: matrix.python_version == '2.7'
      run: |
        sudo apt-get update
        sudo apt-get install -y \
          python2.7 python2.7-dev python2-pip-whl
        sudo ln -sf python2.7 /usr/bin/python
        export PYTHONPATH=`echo /usr/share/python-wheels/pip-*py2*.whl`
        sudo --preserve-env=PYTHONPATH python -m pip install --upgrade pip setuptools wheel
        sudo chown -R $USER /usr/local/lib/python2.7

It's very weird that the linux version of python2.7 is somehow removed as "unsupported" and "obsolete" yet the equally unsupported and obsolete windows compiles of 3.0, 3.1, 3.2, etc. are somehow completely fine...

Hello @dimitrisr,

In order to overcome this I modified:

runs-on: ubuntu-20.04

to

runs-on: ubuntu-20.04
    container:
      image: python:2.7.18-buster

So that the job is run using a github-hosted runner, but inside the python2.7-buster container, which has set up python2.7

Then I started running the pipeline and started fixing everything that was broken (because the container does not have things as sudo, so you have to install it with a command)

Also, If your CI pipeline has other services (e.g. mysql) that run inside a container, now that the whole job is running inside a container, the service container is accessible not through localhost (127.0.0.1), but through the service name.

I hope I was helpful!

I tried this, and the build kept failing. As a matter of fact, it didn't even get the python 2.7 or Am I missing something

All, if you're going to bother going through with insane actions to keep Python2.7 going, please also file Customer Service reports with Github for violating their stated best-practices for handling major changes by version-pinning. A few people have shared the specific references in the Actions documentation above.

Version Pinning exists so things like Python2.7 can be sunsetted without breaking existing CI/Actions.

All, if you're going to bother going through with insane actions to keep Python2.7 going ...

Probably better to spend that time and energy porting your code off of legacy Python.

Probably better to spend that time and energy porting your code off of legacy Python.

For forks sake.

Most people have, but still have old branches maintained (or maintain compatibility) as there are multiple Linux distributions with Python 2.7 in their active Long Term Support window. There are also concerns for legacy systems.

Version pinning exists in Githhub's Actions, and Python, for a reason.

Violating industry best practices, and Github's own stated directives, only shows this platform as unreliable and amateurish.

Probably better to spend that time and energy porting your code off of legacy Python

just because my software can run on python3.11 doesn't mean that it can't run on python2.7, and as was pointed out multiple times there are supported distributions of python2.7

in their active Long Term Support window

If they are paying a long-term support contract then legacy Python is not their problem. Their vendor owes them this legacy support.

TL;DR pypy2.7 works for me (cross platform). It's not CPython 2.7 but was the easiest to setup for me (after some failed other approaches).

I too want/need 2.7 support for testing, I use a GitHub Actions across Linux, Mac, and Windows. I already had PyPy 2.7 and 3.8 in my list.

I was not able to use the buster 2.7 container image workaround that @tzortzispanagiotis suggested in #672 (comment), at least I was not smart enough to figure out the conditional needed in the yaml file to pull it of :-(

clach04/puren_tonbo#59 has my notes.

If anyone is using matrix.os for mult-platform builds and has figured out a way to override the container with a conditional for Ubuntu, I'd love to hear about it (also for Windows, I'm less worried about Mac).

If they are paying a long-term support contract then legacy Python is not their problem. Their vendor owes them this legacy support.

I don't see how that is relevant.

Github officially supported python 2.7 in Actions. For CI we generally don't need or want a specific version of Python 2.7 (like the Ubuntu, SLES, or RHEL) we just need a version of python 2.7 to make sure the syntax used is compatible with it. It costs next to nothing for the Github to keep already existing py2.7 compile for ubuntu 20.04.

Instead they decided to put in extra effort to delete those compile and break python 2.7.

Now, you might have a personal vendetta against py2.7, that's fine, some of us don't have that luxury and have to meet our users where they are.

For anyone interested, I have created a setup_python2 action. It ensures Python 2.7 is installed for Windows, Linux, or macOS and creates a virtual environment to use. I don't plan on publishing this to the marketplace, and there will probably be bugs.

One known issue is that it doesn't work with the default shell on Windows (PowerShell), so you have to specify shell: bash

https://github.com/LizardByte/.github/tree/nightly/actions/setup_python2

It is only available on the nightly branch right now, so you need to specify the commit or branch -> uses: LizardByte/.github/actions/setup_python2@nightly

Edit: Fixed the issue of requiring the bash shell.

That's fantastic @tzortzispanagiotis. Effective, elegant, and cuts out a dependency whose maintainers have let down users of projects that still need to support Python 2. Running in a container works as part of a matrix strategy too, e.g.:

jobs:
  build:

    strategy:
      matrix:
        python-version: ["2.7.18", "3.6.15", "3.7.17", "3.8.18", "3.9.18", "3.10.13", "3.11.7", "3.12.1", "3.13.0a2"]

    runs-on: ubuntu-20.04
    container:
      image: python:${{ matrix.python-version }}-slim

    steps:

I've specified slim images (which are based on a range of Debian releases) pinned to the latest minor version I could find as of yesterday (and one for an alpha pre-release of 3.13). Alternatively, tags for any images with the required Python version installed could be used instead of actions/setup-python. These are the official Python Docker image tags (requires logging in to Docker hub).

In general there could be other side effects from switching environments to a Docker container, instead of a Github VM image. But it's well worth trying, especially for uncomplicated projects with straightforward CI tasks, that don't require one of the pre-installed packages on Github VM runner images (required packages might just have to be installed in the Docker container by other means).

@JamesParrott You are overthinking it because python2 is still available on ubuntu-20.04
% python2 --version

Python 2.7.18

On ubuntu-20.04...

      - if: matrix.python-version == '2.7'
        run: sudo ln -sf /usr/bin/python2.7 /usr/bin/python

Python 2 died 1,476 days ago on 1/1/2020 so enabling your customers to continue using it is a substantial security risk.

Python 2 died 1,476 days ago on 1/1/2020 so enabling your customers to continue using it is a substantial security risk.

just because upstream doesn't support Python 2 doesn't mean that nobody offers security updates to Python 2

@cclauss I just copied Ubuntu 20.04 from Panagiotis. It will work using ubuntu-latest just as well.

The advantage of using a matrix strategy is to reduce code duplication, to try to ensure as far as possible, that the exact same test code is run in CI, regardless of the Python version.

Running in containers from specifically tagged python docker images is more future proof, and doesn't requiring writing code for the special case where the Python version you want happens to be the global system Python, that anyway will only work until the Ubuntu 20.04 Github Actions runner image is dropped (like the Ubuntu 19 ones were).

I'm well aware of the security issues too, thank you Christian. In an ideal world, I agree. The Python 2 projects are not security critical. But they still deserve working CI systems, and tests.

https://github.com/LizardByte/setup-python-action

Works on all GitHub hosted runners (Windows, Linux, macOS... and all versions).

It uses the default action, unless you specify 2.7 as the version, allowing you to easily use a single action in matrix runs.

"2.7 is insecure for your clients" seems to be the response by amateur coders who do understand that large software projects and legacy systems often can not be upgraded to 3.x - or that these systems are often isolated and are not susceptible to the attack vectors of concern.

While there are workarounds to switch from this build to an OS build or third party system, I stress again what myself and others have stated above: Github could have and should have simply not provided Python 2.7 on new and future builds to sunset this system. Instead, Github violated their customer promise, industry best-practices, and the entire concept of versioning by dedicated resources to break all existing builds by removing Python2.7 from legacy versions.

This seems like a nice, minimal way to keep testing legacy Python... https://github.com/dateutil/dateutil/blob/0586f4afa26fc6799128d98d4f97a49c7d6ab314/.github/workflows/validate.yml#L39-L56

Yeah but it still misses the point: why should Github go out of their way to make sure that something that worked before does not work anymore, while they could have simply added a warning "Hey, Python 2 is deprecated and you should not rely on it. If it works great, if it doesn't too bad, you're on your own"?

Once again, not arguing that Python 2 isn't deprecated, it obviously is, but saying that this is a nice way to sunset anything more than a university project is not really a great flag regarding Github's likeliness of following THEIR OWN GUIDELINES on versioning in the future.

Yeah but it still misses the point: why should Github go out of their way to make sure that something that worked before does not work anymore, while they could have simply added a warning "Hey, Python 2 is deprecated and you should not rely on it. If it works great, if it doesn't too bad, you're on your own"?

Once again, not arguing that Python 2 isn't deprecated, it obviously is, but saying that this is a nice way to sunset anything more than a university project is not really a great flag regarding Github's likeliness of following THEIR OWN GUIDELINES on versioning in the future.

@MatteoH2O1999: To me, it looks like GitHub is under the influence of a very vocal Python Core developer who simply declared in essence that he is not going to maintain Python 2.7 for being too much work.

Told him in a comment somewhere here on GitHub that I did not see anything that would backup his claims and that simply not removing Python2 would not cost him anything, but he still pressed on and did not answer any of my stipulations that it's not an issue to still provide it as it is, is just fine.

I could not these comments quickly, but at least as far as public comments on GitHub, I could only find this single guy taking a public stance, but this guy was at least verbally nuking it.

https://github.com/LizardByte/setup-python-action

That works great, and on windows runner images too (unlike my docker suggestion). Thanks so much @ReenigneArcher & @LizardByte!