diff --git a/CHANGELOG.md b/CHANGELOG.md index 550ad7a40..bd0cec22e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- Added support for Python 3.12. ([#1490](https://github.com/heroku/heroku-buildpack-python/pull/1490)) ## v235 (2023-08-25) diff --git a/README.md b/README.md index 801fdd096..6483aeda2 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ Specify a Python Runtime Supported runtime options include: +- `python-3.12.0` on all [supported stacks](https://devcenter.heroku.com/articles/stack#stack-support-details) - `python-3.11.5` on all [supported stacks](https://devcenter.heroku.com/articles/stack#stack-support-details) - `python-3.10.13` on all [supported stacks](https://devcenter.heroku.com/articles/stack#stack-support-details) - `python-3.9.18` on all [supported stacks](https://devcenter.heroku.com/articles/stack#stack-support-details) diff --git a/bin/default_pythons b/bin/default_pythons index 98b1b1ed1..6789ed39d 100755 --- a/bin/default_pythons +++ b/bin/default_pythons @@ -5,6 +5,7 @@ # the env vars to subprocesses. # shellcheck disable=2034 +LATEST_312="python-3.12.0" LATEST_311="python-3.11.5" LATEST_310="python-3.10.13" LATEST_39="python-3.9.18" diff --git a/bin/steps/pipenv-python-version b/bin/steps/pipenv-python-version index d056737aa..20a314330 100755 --- a/bin/steps/pipenv-python-version +++ b/bin/steps/pipenv-python-version @@ -49,6 +49,9 @@ if [[ -f $BUILD_DIR/Pipfile ]]; then 3.11) echo "${LATEST_311}" > "${BUILD_DIR}/runtime.txt" ;; + 3.12) + echo "${LATEST_312}" > "${BUILD_DIR}/runtime.txt" + ;; esac fi diff --git a/bin/steps/python b/bin/steps/python index d6291fe2d..4804c245b 100755 --- a/bin/steps/python +++ b/bin/steps/python @@ -45,6 +45,9 @@ function warn_if_patch_update_available() { } case "${PYTHON_VERSION}" in + python-3.12.*) + warn_if_patch_update_available "${PYTHON_VERSION}" "${LATEST_312}" + ;; python-3.11.*) warn_if_patch_update_available "${PYTHON_VERSION}" "${LATEST_311}" ;; diff --git a/builds/build_python_runtime.sh b/builds/build_python_runtime.sh index 982f3370d..379505e63 100755 --- a/builds/build_python_runtime.sh +++ b/builds/build_python_runtime.sh @@ -20,6 +20,7 @@ case "${STACK}" in "3.9" "3.10" "3.11" + "3.12" ) ;; heroku-20) @@ -28,6 +29,7 @@ case "${STACK}" in "3.9" "3.10" "3.11" + "3.12" ) ;; *) @@ -41,6 +43,10 @@ fi # The release keys can be found on https://www.python.org/downloads/ -> "OpenPGP Public Keys". case "${PYTHON_MAJOR_VERSION}" in + 3.12) + # https://github.com/Yhg1s.gpg + GPG_KEY_FINGERPRINT='7169605F62C751356D054A26A821E680E5FA6305' + ;; 3.10|3.11) # https://keybase.io/pablogsal/ GPG_KEY_FINGERPRINT='A035C8C19219BA821ECEA86B64E628F8D684696D' @@ -115,7 +121,7 @@ if [[ "${PYTHON_MAJOR_VERSION}" != 3.[8-9] ]]; then ) fi -if [[ "${PYTHON_MAJOR_VERSION}" == "3.11" ]]; then +if [[ "${PYTHON_MAJOR_VERSION}" == "3.11" || "${PYTHON_MAJOR_VERSION}" == "3.12" ]]; 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 diff --git a/spec/fixtures/pipenv_python_3.12/Pipfile b/spec/fixtures/pipenv_python_3.12/Pipfile new file mode 100644 index 000000000..9bf60112c --- /dev/null +++ b/spec/fixtures/pipenv_python_3.12/Pipfile @@ -0,0 +1,12 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +urllib3 = "*" + +[dev-packages] + +[requires] +python_version = "3.12" diff --git a/spec/fixtures/pipenv_python_3.12/Pipfile.lock b/spec/fixtures/pipenv_python_3.12/Pipfile.lock new file mode 100644 index 000000000..48052353d --- /dev/null +++ b/spec/fixtures/pipenv_python_3.12/Pipfile.lock @@ -0,0 +1,30 @@ +{ + "_meta": { + "hash": { + "sha256": "13de6076b4dc8bbad334b7e4ae8e8ae63f7f8b4aad794c7f0173871b6927c8d0" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.12" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "urllib3": { + "hashes": [ + "sha256:13abf37382ea2ce6fb744d4dad67838eec857c9f4f57009891805e0b5e123594", + "sha256:ef16afa8ba34a1f989db38e1dbbe0c302e4289a47856990d0682e374563ce35e" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==2.0.5" + } + }, + "develop": {} +} diff --git a/spec/fixtures/python_3.12/requirements.txt b/spec/fixtures/python_3.12/requirements.txt new file mode 100644 index 000000000..a42590beb --- /dev/null +++ b/spec/fixtures/python_3.12/requirements.txt @@ -0,0 +1 @@ +urllib3 diff --git a/spec/fixtures/python_3.12/runtime.txt b/spec/fixtures/python_3.12/runtime.txt new file mode 100644 index 000000000..44f8fbe3a --- /dev/null +++ b/spec/fixtures/python_3.12/runtime.txt @@ -0,0 +1 @@ +python-3.12.0 diff --git a/spec/hatchet/pipenv_spec.rb b/spec/hatchet/pipenv_spec.rb index 5e63a01d1..6774bba74 100644 --- a/spec/hatchet/pipenv_spec.rb +++ b/spec/hatchet/pipenv_spec.rb @@ -174,6 +174,12 @@ include_examples 'builds using Pipenv with the requested Python version', LATEST_PYTHON_3_11 end + context 'with a Pipfile.lock containing python_version 3.12' do + let(:app) { Hatchet::Runner.new('spec/fixtures/pipenv_python_3.12') } + + include_examples 'builds using Pipenv with the requested Python version', LATEST_PYTHON_3_12 + end + context 'with a Pipfile.lock containing python_full_version 3.10.7' do let(:allow_failure) { false } let(:app) { Hatchet::Runner.new('spec/fixtures/pipenv_python_full_version', allow_failure:) } diff --git a/spec/hatchet/python_update_warning_spec.rb b/spec/hatchet/python_update_warning_spec.rb index 9ebd034ae..3bf7b0dc7 100644 --- a/spec/hatchet/python_update_warning_spec.rb +++ b/spec/hatchet/python_update_warning_spec.rb @@ -127,4 +127,6 @@ include_examples 'warns there is a Python update available', '3.11.0', LATEST_PYTHON_3_11 end + + # TODO: Add a Python 3.12.0 outdated test once Python 3.12.1 is released. end diff --git a/spec/hatchet/python_version_spec.rb b/spec/hatchet/python_version_spec.rb index 7dd77deef..bce79d2da 100644 --- a/spec/hatchet/python_version_spec.rb +++ b/spec/hatchet/python_version_spec.rb @@ -181,6 +181,12 @@ include_examples 'builds with the requested Python version', LATEST_PYTHON_3_11 end + context 'when runtime.txt contains python-3.12.0' do + let(:app) { Hatchet::Runner.new('spec/fixtures/python_3.12') } + + include_examples 'builds with the requested Python version', LATEST_PYTHON_3_12 + end + context 'when runtime.txt contains pypy3.6-7.3.2' do let(:app) { Hatchet::Runner.new('spec/fixtures/pypy_3.6', allow_failure: true) } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index be52103b2..3aeeb02bd 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,6 +11,7 @@ LATEST_PYTHON_3_9 = '3.9.18' LATEST_PYTHON_3_10 = '3.10.13' LATEST_PYTHON_3_11 = '3.11.5' +LATEST_PYTHON_3_12 = '3.12.0' DEFAULT_PYTHON_VERSION = LATEST_PYTHON_3_11 # The requirement versions are effectively buildpack constants, however, we want