Skip to content

Commit

Permalink
Remove Python 3.8 support + deprecate Python 3.9
Browse files Browse the repository at this point in the history
Python 3.8 reached upstream EOL on 7th October 2024:
https://devguide.python.org/versions/#supported-versions

The Python version support policy is that supported versions
follows the upstream EOL lifecycle:
https://devcenter.heroku.com/articles/python-support#python-version-support-policy

As such, the buildpack has been showing a deprecation warning with a
scheduled removal date since December 2023:
- #1515
- #1721
- https://devcenter.heroku.com/changelog-items/2768

(Plus Python 3.8 binaries have never been available for Heroku-22
or Heroku-24, meaning it was only ever supported on Heroku-20
and older.)

Dropping support for Python 3.8 also unblocks upgrading to Poetry v2
(which has already dropped 3.8 support).

Apps using Python 3.8 that aren't able to upgrade immediately will
need to pin to an older buildpack version temporarily (at least
until Heroku-20 EOLs).

A deprecation warning has now also been added for Python 3.9.

GUS-W-17472311.
GUS-W-14846945.
  • Loading branch information
edmorley committed Jan 7, 2025
1 parent 9a649bc commit 0a06394
Show file tree
Hide file tree
Showing 19 changed files with 108 additions and 187 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/build_python_runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ jobs:
run: aws s3 sync ./upload "s3://${S3_BUCKET}"

heroku-22:
# On Heroku-22 we only support Python 3.9+.
if: inputs.stack == 'heroku-22' || (inputs.stack == 'auto' && !startsWith(inputs.python_version,'3.8.'))
if: inputs.stack == 'heroku-22' || inputs.stack == 'auto'
runs-on: pub-hk-ubuntu-24.04-xlarge
env:
STACK_VERSION: "22"
Expand All @@ -80,8 +79,7 @@ jobs:
run: aws s3 sync ./upload "s3://${S3_BUCKET}"

heroku-24:
# On Heroku-24 we only support Python 3.9+.
if: inputs.stack == 'heroku-24' || (inputs.stack == 'auto' && !startsWith(inputs.python_version,'3.8.'))
if: inputs.stack == 'heroku-24' || inputs.stack == 'auto'
strategy:
fail-fast: false
matrix:
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## [Unreleased]

- Added a deprecation warning for Python 3.9. ([#1732](https://github.com/heroku/heroku-buildpack-python/pull/1732))
- Removed support for Python 3.8. ([#1732](https://github.com/heroku/heroku-buildpack-python/pull/1732))
- Improved the error messages shown for EOL or unrecognised major Python versions. ([#1732](https://github.com/heroku/heroku-buildpack-python/pull/1732))

## [v273] - 2025-01-03

Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ The supported Python versions are:
These Python versions are deprecated on Heroku:

- Python 3.9
- Python 3.8 (only available on the [Heroku-20](https://devcenter.heroku.com/articles/heroku-20-stack) stack)

Python versions older than those listed above are no longer supported, since they have reached
end-of-life [upstream](https://devguide.python.org/versions/#supported-versions).
Expand Down
2 changes: 1 addition & 1 deletion bin/compile
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ meta_time "package_manager_install_duration" "${package_manager_install_start_ti
# Installs the sqlite3 dev headers and sqlite3 binary but not the
# libsqlite3-0 library since that exists in the base image.
# We skip this step on Python 3.13 or when using Poetry, as a first step towards removing this feature.
if [[ "${python_major_version}" == +(3.8|3.9|3.10|3.11|3.12) && "${package_manager}" != "poetry" ]]; then
if [[ "${python_major_version}" == +(3.9|3.10|3.11|3.12) && "${package_manager}" != "poetry" ]]; then
install_sqlite_start_time=$(nowms)
source "${BUILDPACK_DIR}/bin/steps/sqlite3"
buildpack_sqlite3_install
Expand Down
22 changes: 13 additions & 9 deletions bin/steps/python
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ PYTHON_URL="${S3_BASE_URL}/python-${python_full_version}-ubuntu-${UBUNTU_VERSION
# 1. It's a Python major version we've deprecated and so is only available on older stacks (i.e: Python 3.8).
# 2. If an exact Python version was requested and the patch version doesn't exist (e.g. 3.12.999).
# 3. The user has pinned to an older buildpack version and the S3 bucket location or layout has changed since.
# TODO: Update this message to be more specific once Python 3.8 support is dropped.
# TODO: Update this message to be more specific now that Python 3.8 support has been removed.
if ! curl --output /dev/null --silent --head --fail --retry 3 --retry-connrefused --connect-timeout 10 "${PYTHON_URL}"; then
output::error <<-EOF
Error: Python ${python_full_version} isn't available for this stack (${STACK}).
Expand Down Expand Up @@ -74,18 +74,22 @@ function warn_if_patch_update_available() {
# We wait until now to display outdated Python version warnings, since we only want to show them
# if there weren't any errors with the version to avoid adding noise to the error messages.
# TODO: Move this into lib/ as part of the warnings refactor.
if [[ "${python_major_version}" == "3.8" ]]; then
output::warning <<-'EOF'
Warning: Support for Python 3.8 is ending soon!
if [[ "${python_major_version}" == "3.9" ]]; then
output::warning <<-EOF
Warning: Support for Python 3.9 is ending soon!
Python 3.8 reached its upstream end-of-life on 7th October 2024, and so
no longer receives security updates:
Python 3.9 will reach its upstream end-of-life in October 2025,
at which point it will no longer receive security updates:
https://devguide.python.org/versions/#supported-versions
Support for Python 3.8 will be removed from this buildpack on 7th January 2025.
As such, support for Python 3.9 will be removed from this
buildpack on 7th January 2026.
Upgrade to a newer Python version as soon as possible to keep your app secure.
See: https://devcenter.heroku.com/articles/python-runtimes
Upgrade to a newer Python version as soon as possible, by
changing the version in the '${python_version_origin}' file.
For more information, see:
https://devcenter.heroku.com/articles/python-support#supported-python-versions
EOF
fi

Expand Down
24 changes: 7 additions & 17 deletions builds/build_python_runtime.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function abort() {
}

case "${STACK:?}" in
heroku-22 | heroku-24)
heroku-20 | heroku-22 | heroku-24)
SUPPORTED_PYTHON_VERSIONS=(
"3.9"
"3.10"
Expand All @@ -30,16 +30,6 @@ case "${STACK:?}" in
"3.13"
)
;;
heroku-20)
SUPPORTED_PYTHON_VERSIONS=(
"3.8"
"3.9"
"3.10"
"3.11"
"3.12"
"3.13"
)
;;
*)
abort "Unsupported stack '${STACK}'!"
;;
Expand All @@ -63,7 +53,7 @@ case "${PYTHON_MAJOR_VERSION}" in
# https://keybase.io/pablogsal/
GPG_KEY_FINGERPRINT='A035C8C19219BA821ECEA86B64E628F8D684696D'
;;
3.8 | 3.9)
3.9)
# https://keybase.io/ambv/
GPG_KEY_FINGERPRINT='E3FF2839C048B25C084DEBE9B26995E310250568'
;;
Expand Down Expand Up @@ -122,7 +112,7 @@ CONFIGURE_OPTS=(
"--with-system-expat"
)

if [[ "${PYTHON_MAJOR_VERSION}" != +(3.8|3.9) ]]; then
if [[ "${PYTHON_MAJOR_VERSION}" != +(3.9) ]]; then
CONFIGURE_OPTS+=(
# Shared builds are beneficial for a number of reasons:
# - Reduces the size of the build, since it avoids the duplication between
Expand All @@ -147,7 +137,7 @@ if [[ "${PYTHON_MAJOR_VERSION}" != +(3.8|3.9) ]]; then
)
fi

if [[ "${PYTHON_MAJOR_VERSION}" != +(3.8|3.9|3.10) ]]; then
if [[ "${PYTHON_MAJOR_VERSION}" != +(3.9|3.10) ]]; then
CONFIGURE_OPTS+=(
# Skip building the test modules, since we remove them after the build anyway.
# This feature was added in Python 3.10+, however it wasn't until Python 3.11
Expand All @@ -170,7 +160,7 @@ fi
# - https://github.com/docker-library/python/issues/810
# We only use `dpkg-buildflags` for Python versions where we build in shared mode (Python 3.9+),
# since some of the options it enables interferes with the stripping of static libraries.
if [[ "${PYTHON_MAJOR_VERSION}" == +(3.8|3.9) ]]; then
if [[ "${PYTHON_MAJOR_VERSION}" == +(3.9) ]]; then
EXTRA_CFLAGS=''
LDFLAGS='-Wl,--strip-all'
else
Expand All @@ -182,7 +172,7 @@ CPU_COUNT="$(nproc)"
make -j "${CPU_COUNT}" "EXTRA_CFLAGS=${EXTRA_CFLAGS}" "LDFLAGS=${LDFLAGS}"
make install

if [[ "${PYTHON_MAJOR_VERSION}" == +(3.8|3.9) ]]; then
if [[ "${PYTHON_MAJOR_VERSION}" == +(3.9) ]]; then
# On older versions of Python we're still building the static library, which has to be
# manually stripped since the linker stripping enabled in LDFLAGS doesn't cover them.
# We're using `--strip-unneeded` since `--strip-all` would remove the `.symtab` section
Expand Down Expand Up @@ -233,7 +223,7 @@ LD_LIBRARY_PATH="${SRC_DIR}" "${SRC_DIR}/python" -m compileall -f --invalidation
# (e.g. `python -m pydoc`) if needed.
rm "${INSTALL_DIR}"/bin/{idle,pydoc}*
# The 2to3 module and entrypoint was removed from the stdlib in Python 3.13.
if [[ "${PYTHON_MAJOR_VERSION}" == +(3.8|3.9|3.10|3.11|3.12) ]]; then
if [[ "${PYTHON_MAJOR_VERSION}" == +(3.9|3.10|3.11|3.12) ]]; then
rm "${INSTALL_DIR}"/bin/2to3*
fi

Expand Down
2 changes: 1 addition & 1 deletion lib/pip.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function pip::install_pip_setuptools_wheel() {
# them installed.
# - Most of the Python ecosystem has stopped installing them for Python 3.12+ already.
# See the Python CNB's removal for more details: https://github.com/heroku/buildpacks-python/pull/243
if [[ "${python_major_version}" == +(3.8|3.9|3.10|3.11|3.12) ]]; then
if [[ "${python_major_version}" == +(3.9|3.10|3.11|3.12) ]]; then
meta_set "setuptools_version" "${SETUPTOOLS_VERSION}"
meta_set "wheel_version" "${WHEEL_VERSION}"
packages_to_install+=(
Expand Down
43 changes: 25 additions & 18 deletions lib/python_version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
# however, it helps Shellcheck realise the options under which these functions will run.
set -euo pipefail

LATEST_PYTHON_3_8="3.8.20"
LATEST_PYTHON_3_9="3.9.21"
LATEST_PYTHON_3_10="3.10.16"
LATEST_PYTHON_3_11="3.11.11"
LATEST_PYTHON_3_12="3.12.8"
LATEST_PYTHON_3_13="3.13.1"

OLDEST_SUPPORTED_PYTHON_3_MINOR_VERSION=9
NEWEST_SUPPORTED_PYTHON_3_MINOR_VERSION=13

DEFAULT_PYTHON_FULL_VERSION="${LATEST_PYTHON_3_13}"
DEFAULT_PYTHON_MAJOR_VERSION="${DEFAULT_PYTHON_FULL_VERSION%.*}"

Expand Down Expand Up @@ -280,7 +282,7 @@ function python_version::resolve_python_version() {
local major="${BASH_REMATCH[1]}"
local minor="${BASH_REMATCH[2]}"

if ((major < 3 || (major == 3 && minor < 8))); then
if ((major < 3 || (major == 3 && minor < OLDEST_SUPPORTED_PYTHON_3_MINOR_VERSION))); then
if [[ "${python_version_origin}" == "cached" ]]; then
output::error <<-EOF
Error: The cached Python version has reached end-of-life.
Expand All @@ -292,14 +294,14 @@ function python_version::resolve_python_version() {
and is therefore no longer receiving security updates:
https://devguide.python.org/versions/#supported-versions
As such, it is no longer supported by this buildpack.
Please upgrade to a newer Python version by creating a
'.python-version' file that contains a Python version like:
${DEFAULT_PYTHON_MAJOR_VERSION}
For a list of the supported Python versions, see:
As such, it is no longer supported by the latest version
of this buildpack:
https://devcenter.heroku.com/articles/python-support#supported-python-versions
Please upgrade to at least Python 3.${OLDEST_SUPPORTED_PYTHON_3_MINOR_VERSION} by creating a
'.python-version' file in the root directory of your app,
that contains a Python version like:
3.${OLDEST_SUPPORTED_PYTHON_3_MINOR_VERSION}
EOF
else
output::error <<-EOF
Expand All @@ -309,20 +311,19 @@ function python_version::resolve_python_version() {
therefore no longer receiving security updates:
https://devguide.python.org/versions/#supported-versions
As such, it is no longer supported by this buildpack.
As such, it is no longer supported by the latest version
of this buildpack:
https://devcenter.heroku.com/articles/python-support#supported-python-versions
Please upgrade to a newer Python version by updating the
Please upgrade to at least Python 3.${OLDEST_SUPPORTED_PYTHON_3_MINOR_VERSION} by updating the
version configured via the '${python_version_origin}' file.
For a list of the supported Python versions, see:
https://devcenter.heroku.com/articles/python-support#supported-python-versions
EOF
fi
meta_set "failure_reason" "python-version::eol"
exit 1
fi

if (((major == 3 && minor > 13) || major >= 4)); then
if (((major == 3 && minor > NEWEST_SUPPORTED_PYTHON_3_MINOR_VERSION) || major >= 4)); then
if [[ "${python_version_origin}" == "cached" ]]; then
output::error <<-EOF
Error: The cached Python version isn't recognised.
Expand All @@ -336,7 +337,14 @@ function python_version::resolve_python_version() {
This can occur if you have downgraded the version of the
buildpack to an older version.
Please switch back to a newer version of this buildpack.
Please switch back to a newer version of this buildpack:
https://devcenter.heroku.com/articles/managing-buildpacks#view-your-buildpacks
https://devcenter.heroku.com/articles/managing-buildpacks#classic-buildpacks-references
Alternatively, request an older Python version by creating
a '.python-version' file in the root directory of your app,
that contains a Python version like:
3.${NEWEST_SUPPORTED_PYTHON_3_MINOR_VERSION}
EOF
else
output::error <<-EOF
Expand All @@ -354,7 +362,7 @@ function python_version::resolve_python_version() {
https://devcenter.heroku.com/articles/managing-buildpacks#view-your-buildpacks
https://devcenter.heroku.com/articles/managing-buildpacks#classic-buildpacks-references
Otherwise, switch to a supported version (such as Python ${DEFAULT_PYTHON_MAJOR_VERSION})
Otherwise, switch to a supported version (such as Python 3.${NEWEST_SUPPORTED_PYTHON_3_MINOR_VERSION})
by updating the version configured via the '${python_version_origin}' file.
EOF
fi
Expand All @@ -366,7 +374,6 @@ function python_version::resolve_python_version() {
# Otherwise map major version specifiers to the latest patch release.
case "${requested_python_version}" in
*.*.*) echo "${requested_python_version}" ;;
3.8) echo "${LATEST_PYTHON_3_8}" ;;
3.9) echo "${LATEST_PYTHON_3_9}" ;;
3.10) echo "${LATEST_PYTHON_3_10}" ;;
3.11) echo "${LATEST_PYTHON_3_11}" ;;
Expand Down
2 changes: 1 addition & 1 deletion spec/fixtures/pipenv_python_version_eol/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ typing-extensions = "*"
[dev-packages]

[requires]
python_version = "3.7"
python_version = "3.8"
4 changes: 2 additions & 2 deletions spec/fixtures/pipenv_python_version_eol/Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions spec/fixtures/python_3.8/.python-version

This file was deleted.

2 changes: 0 additions & 2 deletions spec/fixtures/python_3.8/requirements.txt

This file was deleted.

2 changes: 1 addition & 1 deletion spec/fixtures/python_version_eol/.python-version
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
# So are empty lines, and leading/trailing whitespace.


3.7
3.8

2 changes: 1 addition & 1 deletion spec/fixtures/python_version_outdated/.python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.9.0
3.10.0
Original file line number Diff line number Diff line change
@@ -1 +1 @@
python-3.8.0
python-3.9.0
13 changes: 6 additions & 7 deletions spec/hatchet/pipenv_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -266,21 +266,20 @@
app.deploy do |app|
expect(clean_output(app.output)).to match(Regexp.new(<<~OUTPUT))
remote: -----> Python app detected
remote: -----> Using Python 3.7 specified in Pipfile.lock
remote: -----> Using Python 3.8 specified in Pipfile.lock
remote:
remote: ! Error: The requested Python version has reached end-of-life.
remote: !
remote: ! Python 3.7 has reached its upstream end-of-life, and is
remote: ! Python 3.8 has reached its upstream end-of-life, and is
remote: ! therefore no longer receiving security updates:
remote: ! https://devguide.python.org/versions/#supported-versions
remote: !
remote: ! As such, it is no longer supported by this buildpack.
remote: ! As such, it is no longer supported by the latest version
remote: ! of this buildpack:
remote: ! https://devcenter.heroku.com/articles/python-support#supported-python-versions
remote: !
remote: ! Please upgrade to a newer Python version by updating the
remote: ! Please upgrade to at least Python 3.9 by updating the
remote: ! version configured via the 'Pipfile.lock' file.
remote: !
remote: ! For a list of the supported Python versions, see:
remote: ! https://devcenter.heroku.com/articles/python-support#supported-python-versions
remote:
remote: ! Push rejected, failed to compile Python app.
OUTPUT
Expand Down
Loading

0 comments on commit 0a06394

Please sign in to comment.