Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Python 3.8 support + deprecate Python 3.9 #1732

Merged
merged 1 commit into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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, and so (1) can no longer occur.
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 your ${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
47 changes: 26 additions & 21 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,13 @@ 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's no longer supported by 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 +310,18 @@ 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.

Please upgrade to a newer Python version by updating the
version configured via the '${python_version_origin}' file.

For a list of the supported Python versions, see:
As such, it's no longer supported by 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 changing the
version in your ${python_version_origin} file.
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 +335,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 @@ -350,12 +356,12 @@ function python_version::resolve_python_version() {
https://devcenter.heroku.com/articles/python-support#supported-python-versions

If it has, make sure that you are using the latest version
of this buildpack, and have not pinned to an older release:
of this buildpack, and haven't pinned to an older release:
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})
by updating the version configured via the '${python_version_origin}' file.
Otherwise, switch to a supported version (such as Python 3.${NEWEST_SUPPORTED_PYTHON_3_MINOR_VERSION})
by changing the version in your ${python_version_origin} file.
EOF
fi
meta_set "failure_reason" "python-version::unknown-major"
Expand All @@ -366,7 +372,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
30 changes: 22 additions & 8 deletions spec/hatchet/pipenv_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@
remote: -----> Using Python 3.9.0 specified in Pipfile.lock
remote: -----> Installing Python 3.9.0
remote:
remote: ! Warning: Support for Python 3.9 is ending soon!
remote: !
remote: ! Python 3.9 will reach its upstream end-of-life in October 2025,
remote: ! at which point it will no longer receive security updates:
remote: ! https://devguide.python.org/versions/#supported-versions
remote: !
remote: ! As such, support for Python 3.9 will be removed from this
remote: ! buildpack on 7th January 2026.
remote: !
remote: ! Upgrade to a newer Python version as soon as possible, by
remote: ! changing the version in your Pipfile.lock file.
remote: !
remote: ! For more information, see:
remote: ! https://devcenter.heroku.com/articles/python-support#supported-python-versions
remote:
remote:
remote: ! Warning: A Python security update is available!
remote: !
remote: ! Upgrade as soon as possible to: Python #{LATEST_PYTHON_3_9}
Expand Down Expand Up @@ -266,21 +282,19 @@
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: !
remote: ! Please upgrade to a newer Python version by updating the
remote: ! version configured via the 'Pipfile.lock' file.
remote: !
remote: ! For a list of the supported Python versions, see:
remote: ! As such, it's no longer supported by this buildpack:
remote: ! https://devcenter.heroku.com/articles/python-support#supported-python-versions
remote: !
remote: ! Please upgrade to at least Python 3.9 by changing the
remote: ! version in your Pipfile.lock file.
remote:
remote: ! Push rejected, failed to compile Python app.
OUTPUT
Expand Down
Loading