diff --git a/.github/workflows/build_python_runtime.yml b/.github/workflows/build_python_runtime.yml index 724d4045a..9b90fc052 100644 --- a/.github/workflows/build_python_runtime.yml +++ b/.github/workflows/build_python_runtime.yml @@ -5,7 +5,7 @@ on: workflow_dispatch: inputs: python_version: - description: "Python version (eg: 3.12.0)" + description: "Python version (eg: 3.13.0)" type: string required: true stack: diff --git a/CHANGELOG.md b/CHANGELOG.md index 7584f3c9d..9ce314759 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [Unreleased] +- Changed the default Python version for new apps from 3.12 to 3.13. ([#1715](https://github.com/heroku/heroku-buildpack-python/pull/1715)) - Changed Python version pinning behaviour for apps that do not specify a Python version. Repeat builds are now pinned to the major Python version only (`3.X`) instead of the full Python version (`3.X.Y`), so that they always use the latest patch version. ([#1714](https://github.com/heroku/heroku-buildpack-python/pull/1714)) ## [v269] - 2024-12-04 diff --git a/README.md b/README.md index f2767f7db..34684120f 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ If none of those are found, the buildpack will use a default Python version for build of an app, and then subsequent builds of that app will be pinned to that version unless the build cache is cleared or you request a different version. -The current default Python version is: 3.12 +The current default Python version is: 3.13 The supported Python versions are: diff --git a/lib/python_version.sh b/lib/python_version.sh index 9513d7470..161118294 100644 --- a/lib/python_version.sh +++ b/lib/python_version.sh @@ -11,7 +11,7 @@ LATEST_PYTHON_3_11="3.11.11" LATEST_PYTHON_3_12="3.12.8" LATEST_PYTHON_3_13="3.13.1" -DEFAULT_PYTHON_FULL_VERSION="${LATEST_PYTHON_3_12}" +DEFAULT_PYTHON_FULL_VERSION="${LATEST_PYTHON_3_13}" DEFAULT_PYTHON_MAJOR_VERSION="${DEFAULT_PYTHON_FULL_VERSION%.*}" # Integer with no redundant leading zeros. diff --git a/spec/fixtures/ci_pipenv/.python-version b/spec/fixtures/ci_pipenv/.python-version index e4fba2183..24ee5b1be 100644 --- a/spec/fixtures/ci_pipenv/.python-version +++ b/spec/fixtures/ci_pipenv/.python-version @@ -1 +1 @@ -3.12 +3.13 diff --git a/spec/fixtures/ci_pipenv/Pipfile.lock b/spec/fixtures/ci_pipenv/Pipfile.lock index aa11d8ecf..a7d99ba86 100644 --- a/spec/fixtures/ci_pipenv/Pipfile.lock +++ b/spec/fixtures/ci_pipenv/Pipfile.lock @@ -35,11 +35,11 @@ }, "packaging": { "hashes": [ - "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", - "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" ], "markers": "python_version >= '3.8'", - "version": "==24.1" + "version": "==24.2" }, "pluggy": { "hashes": [ @@ -51,12 +51,12 @@ }, "pytest": { "hashes": [ - "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", - "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" + "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", + "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==8.3.3" + "version": "==8.3.4" } } } diff --git a/spec/fixtures/ci_poetry/.python-version b/spec/fixtures/ci_poetry/.python-version index e4fba2183..24ee5b1be 100644 --- a/spec/fixtures/ci_poetry/.python-version +++ b/spec/fixtures/ci_poetry/.python-version @@ -1 +1 @@ -3.12 +3.13 diff --git a/spec/fixtures/ci_poetry/poetry.lock b/spec/fixtures/ci_poetry/poetry.lock index a727a186c..7fe5d0794 100644 --- a/spec/fixtures/ci_poetry/poetry.lock +++ b/spec/fixtures/ci_poetry/poetry.lock @@ -24,13 +24,13 @@ files = [ [[package]] name = "packaging" -version = "24.1" +version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -50,13 +50,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pytest" -version = "8.3.3" +version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, - {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] @@ -81,5 +81,5 @@ files = [ [metadata] lock-version = "2.0" -python-versions = "^3.12" -content-hash = "2e71a7976f439ce69fc771708b83dcfc6f795072ea73a7c2de0241878cbd378a" +python-versions = "^3.13" +content-hash = "56ec6342f4a39b402d2b65bd08cfb3af4136a02bb58674df49eac8d317376a7f" diff --git a/spec/fixtures/ci_poetry/pyproject.toml b/spec/fixtures/ci_poetry/pyproject.toml index 99aa593b8..ad7398c6e 100644 --- a/spec/fixtures/ci_poetry/pyproject.toml +++ b/spec/fixtures/ci_poetry/pyproject.toml @@ -2,7 +2,7 @@ package-mode = false [tool.poetry.dependencies] -python = "^3.12" +python = "^3.13" typing-extensions = "*" [tool.poetry.group.test.dependencies] diff --git a/spec/fixtures/ci_requirements/.python-version b/spec/fixtures/ci_requirements/.python-version index e4fba2183..24ee5b1be 100644 --- a/spec/fixtures/ci_requirements/.python-version +++ b/spec/fixtures/ci_requirements/.python-version @@ -1 +1 @@ -3.12 +3.13 diff --git a/spec/fixtures/ci_requirements/requirements-test.txt b/spec/fixtures/ci_requirements/requirements-test.txt index 40543aaba..d197ada2f 100644 --- a/spec/fixtures/ci_requirements/requirements-test.txt +++ b/spec/fixtures/ci_requirements/requirements-test.txt @@ -1 +1 @@ -pytest==8.3.3 +pytest==8.3.4 diff --git a/spec/fixtures/pipenv_and_requirements_txt/Pipfile b/spec/fixtures/pipenv_and_requirements_txt/Pipfile index 9bf60112c..73f50fc86 100644 --- a/spec/fixtures/pipenv_and_requirements_txt/Pipfile +++ b/spec/fixtures/pipenv_and_requirements_txt/Pipfile @@ -9,4 +9,4 @@ urllib3 = "*" [dev-packages] [requires] -python_version = "3.12" +python_version = "3.13" diff --git a/spec/fixtures/pipenv_and_requirements_txt/Pipfile.lock b/spec/fixtures/pipenv_and_requirements_txt/Pipfile.lock index cc5ce05bc..dcd0b3ca7 100644 --- a/spec/fixtures/pipenv_and_requirements_txt/Pipfile.lock +++ b/spec/fixtures/pipenv_and_requirements_txt/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "13de6076b4dc8bbad334b7e4ae8e8ae63f7f8b4aad794c7f0173871b6927c8d0" + "sha256": "60dc67ee4223a391c5e0ae2b4d7ea54a7b245773d76b6ff82156dda97a3e4fb2" }, "pipfile-spec": 6, "requires": { - "python_version": "3.12" + "python_version": "3.13" }, "sources": [ { @@ -18,12 +18,12 @@ "default": { "urllib3": { "hashes": [ - "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", - "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==2.2.1" + "version": "==2.2.3" } }, "develop": {} diff --git a/spec/fixtures/pipenv_basic/Pipfile b/spec/fixtures/pipenv_basic/Pipfile index 883fd6c01..7a763f509 100644 --- a/spec/fixtures/pipenv_basic/Pipfile +++ b/spec/fixtures/pipenv_basic/Pipfile @@ -9,4 +9,4 @@ typing-extensions = "*" [dev-packages] [requires] -python_version = "3.12" +python_version = "3.13" diff --git a/spec/fixtures/pipenv_basic/Pipfile.lock b/spec/fixtures/pipenv_basic/Pipfile.lock index 30824a47d..44a737c1a 100644 --- a/spec/fixtures/pipenv_basic/Pipfile.lock +++ b/spec/fixtures/pipenv_basic/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "9661ed313a79ccb68c7dc4e639068f86ddd91e307ec2ed60498858d002e9b547" + "sha256": "83d7242edaa31ec24731c102c5debc217f3e5f5fa5b4e992de07d4d25805715e" }, "pipfile-spec": 6, "requires": { - "python_version": "3.12" + "python_version": "3.13" }, "sources": [ { diff --git a/spec/fixtures/pipenv_editable/.python-version b/spec/fixtures/pipenv_editable/.python-version new file mode 100644 index 000000000..e4fba2183 --- /dev/null +++ b/spec/fixtures/pipenv_editable/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/spec/fixtures/pipenv_editable/Pipfile.lock b/spec/fixtures/pipenv_editable/Pipfile.lock index 9ed2169b9..ae096d558 100644 --- a/spec/fixtures/pipenv_editable/Pipfile.lock +++ b/spec/fixtures/pipenv_editable/Pipfile.lock @@ -30,11 +30,11 @@ }, "setuptools": { "hashes": [ - "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987", - "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32" + "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6", + "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d" ], - "markers": "python_version >= '3.8'", - "version": "==69.5.1" + "markers": "python_version >= '3.9'", + "version": "==75.6.0" } }, "develop": {} diff --git a/spec/fixtures/pipenv_lockfile_out_of_sync/Pipfile b/spec/fixtures/pipenv_lockfile_out_of_sync/Pipfile index 9bf60112c..73f50fc86 100644 --- a/spec/fixtures/pipenv_lockfile_out_of_sync/Pipfile +++ b/spec/fixtures/pipenv_lockfile_out_of_sync/Pipfile @@ -9,4 +9,4 @@ urllib3 = "*" [dev-packages] [requires] -python_version = "3.12" +python_version = "3.13" diff --git a/spec/fixtures/pipenv_no_lockfile/Pipfile b/spec/fixtures/pipenv_no_lockfile/Pipfile index 883fd6c01..7a763f509 100644 --- a/spec/fixtures/pipenv_no_lockfile/Pipfile +++ b/spec/fixtures/pipenv_no_lockfile/Pipfile @@ -9,4 +9,4 @@ typing-extensions = "*" [dev-packages] [requires] -python_version = "3.12" +python_version = "3.13" diff --git a/spec/fixtures/poetry_basic/.python-version b/spec/fixtures/poetry_basic/.python-version index e4fba2183..24ee5b1be 100644 --- a/spec/fixtures/poetry_basic/.python-version +++ b/spec/fixtures/poetry_basic/.python-version @@ -1 +1 @@ -3.12 +3.13 diff --git a/spec/fixtures/poetry_basic/poetry.lock b/spec/fixtures/poetry_basic/poetry.lock index a727a186c..7fe5d0794 100644 --- a/spec/fixtures/poetry_basic/poetry.lock +++ b/spec/fixtures/poetry_basic/poetry.lock @@ -24,13 +24,13 @@ files = [ [[package]] name = "packaging" -version = "24.1" +version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -50,13 +50,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pytest" -version = "8.3.3" +version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, - {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] @@ -81,5 +81,5 @@ files = [ [metadata] lock-version = "2.0" -python-versions = "^3.12" -content-hash = "2e71a7976f439ce69fc771708b83dcfc6f795072ea73a7c2de0241878cbd378a" +python-versions = "^3.13" +content-hash = "56ec6342f4a39b402d2b65bd08cfb3af4136a02bb58674df49eac8d317376a7f" diff --git a/spec/fixtures/poetry_basic/pyproject.toml b/spec/fixtures/poetry_basic/pyproject.toml index 1b21050ab..9fc0e8356 100644 --- a/spec/fixtures/poetry_basic/pyproject.toml +++ b/spec/fixtures/poetry_basic/pyproject.toml @@ -2,7 +2,7 @@ package-mode = false [tool.poetry.dependencies] -python = "^3.12" +python = "^3.13" typing-extensions = "*" # This group shouldn't be installed due to us passing `--only main`. diff --git a/spec/fixtures/poetry_editable/poetry.lock b/spec/fixtures/poetry_editable/poetry.lock index 4047b0d15..a26fb9272 100644 --- a/spec/fixtures/poetry_editable/poetry.lock +++ b/spec/fixtures/poetry_editable/poetry.lock @@ -52,25 +52,25 @@ url = "packages/local_package_setup_py" [[package]] name = "setuptools" -version = "75.2.0" +version = "75.6.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "setuptools-75.2.0-py3-none-any.whl", hash = "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8"}, - {file = "setuptools-75.2.0.tar.gz", hash = "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec"}, + {file = "setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"}, + {file = "setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.7.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] [metadata] lock-version = "2.0" -python-versions = "^3.12" -content-hash = "f362eb3b600ebb153055e8c4ed85f1cdeb18ffd8528710d5e1631c448a2f8adc" +python-versions = "^3.13" +content-hash = "622d4971a16f64f64de12d8208024658e6d7b9e30e1315e6970110ec5e70975c" diff --git a/spec/fixtures/poetry_editable/pyproject.toml b/spec/fixtures/poetry_editable/pyproject.toml index 7bcc6ab80..b7659537b 100644 --- a/spec/fixtures/poetry_editable/pyproject.toml +++ b/spec/fixtures/poetry_editable/pyproject.toml @@ -5,7 +5,7 @@ description = "" authors = [] [tool.poetry.dependencies] -python = "^3.12" +python = "^3.13" gunicorn = { git = "https://github.com/benoitc/gunicorn.git", tag = "20.1.0", develop = true } local-package-pyproject-toml = { path = "packages/local_package_pyproject_toml", develop = true } local-package-setup-py = { path = "packages/local_package_setup_py", develop = true } diff --git a/spec/fixtures/poetry_lockfile_out_of_sync/poetry.lock b/spec/fixtures/poetry_lockfile_out_of_sync/poetry.lock index 8738e5fc8..e9d42af7d 100644 --- a/spec/fixtures/poetry_lockfile_out_of_sync/poetry.lock +++ b/spec/fixtures/poetry_lockfile_out_of_sync/poetry.lock @@ -3,5 +3,5 @@ package = [] [metadata] lock-version = "2.0" -python-versions = "^3.12" -content-hash = "34e39677d8527182346093002688d17a5d2fc204b9eb3e094b2e6ac519028228" +python-versions = "^3.13" +content-hash = "f01b553f3895e558c34b4f10542e05acdef39bf0527c8090bd136d914dc73f94" diff --git a/spec/fixtures/poetry_lockfile_out_of_sync/pyproject.toml b/spec/fixtures/poetry_lockfile_out_of_sync/pyproject.toml index f0367e35e..032945f60 100644 --- a/spec/fixtures/poetry_lockfile_out_of_sync/pyproject.toml +++ b/spec/fixtures/poetry_lockfile_out_of_sync/pyproject.toml @@ -2,7 +2,7 @@ package-mode = false [tool.poetry.dependencies] -python = "^3.12" +python = "^3.13" # This dependency isn't in the lockfile. typing-extensions = "*" diff --git a/spec/fixtures/requirements_basic/.python-version b/spec/fixtures/requirements_basic/.python-version index e4fba2183..24ee5b1be 100644 --- a/spec/fixtures/requirements_basic/.python-version +++ b/spec/fixtures/requirements_basic/.python-version @@ -1 +1 @@ -3.12 +3.13 diff --git a/spec/fixtures/requirements_compiled/.python-version b/spec/fixtures/requirements_compiled/.python-version new file mode 100644 index 000000000..56ada5c99 --- /dev/null +++ b/spec/fixtures/requirements_compiled/.python-version @@ -0,0 +1,2 @@ +# TODO: Switch this to using Python 3.13 as part of the sqlite removal. +3.12 diff --git a/spec/fixtures/requirements_editable/.python-version b/spec/fixtures/requirements_editable/.python-version new file mode 100644 index 000000000..9b9fc4643 --- /dev/null +++ b/spec/fixtures/requirements_editable/.python-version @@ -0,0 +1,3 @@ +# Note: This test intentionally uses Python 3.12, so that we test *.egg-link +# path rewriting using older globally installed setuptools. +3.12 diff --git a/spec/fixtures/requirements_txt_and_poetry_lock/.python-version b/spec/fixtures/requirements_txt_and_poetry_lock/.python-version index e4fba2183..24ee5b1be 100644 --- a/spec/fixtures/requirements_txt_and_poetry_lock/.python-version +++ b/spec/fixtures/requirements_txt_and_poetry_lock/.python-version @@ -1 +1 @@ -3.12 +3.13 diff --git a/spec/fixtures/requirements_txt_and_poetry_lock/poetry.lock b/spec/fixtures/requirements_txt_and_poetry_lock/poetry.lock index 7022f9054..f80c1b5c7 100644 --- a/spec/fixtures/requirements_txt_and_poetry_lock/poetry.lock +++ b/spec/fixtures/requirements_txt_and_poetry_lock/poetry.lock @@ -13,5 +13,5 @@ files = [ [metadata] lock-version = "2.0" -python-versions = "^3.12" -content-hash = "2600e9ec45a8acb482a004ff092cb1453c2550aeec843430255a623cad8f7f86" +python-versions = "^3.13" +content-hash = "247bc9eddaeea191a758d051d2eae56b572964d566c6ab0c81822ee7535083dd" diff --git a/spec/fixtures/requirements_txt_and_poetry_lock/pyproject.toml b/spec/fixtures/requirements_txt_and_poetry_lock/pyproject.toml index b6077bf2c..ebfd436a7 100644 --- a/spec/fixtures/requirements_txt_and_poetry_lock/pyproject.toml +++ b/spec/fixtures/requirements_txt_and_poetry_lock/pyproject.toml @@ -2,5 +2,5 @@ package-mode = false [tool.poetry.dependencies] -python = "^3.12" +python = "^3.13" typing-extensions = "*" diff --git a/spec/fixtures/setup_py_only/.python-version b/spec/fixtures/setup_py_only/.python-version index e4fba2183..24ee5b1be 100644 --- a/spec/fixtures/setup_py_only/.python-version +++ b/spec/fixtures/setup_py_only/.python-version @@ -1 +1 @@ -3.12 +3.13 diff --git a/spec/hatchet/ci_spec.rb b/spec/hatchet/ci_spec.rb index 661cd36b0..824564447 100644 --- a/spec/hatchet/ci_spec.rb +++ b/spec/hatchet/ci_spec.rb @@ -14,11 +14,10 @@ -----> Python app detected -----> Using Python #{DEFAULT_PYTHON_MAJOR_VERSION} specified in .python-version -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} - -----> Installing SQLite3 + -----> Installing pip #{PIP_VERSION} -----> Installing dependencies using 'pip install -r requirements.txt -r requirements-test.txt' .+ - Successfully installed .+ pytest-8.3.3 typing-extensions-4.12.2 + Successfully installed .+ pytest-.+ typing-extensions-.+ -----> Skipping Django collectstatic since the env var DISABLE_COLLECTSTATIC is set. -----> Running bin/post_compile hook CI=true @@ -58,7 +57,7 @@ PYTHONPATH=/app PYTHONUNBUFFERED=true WEB_CONCURRENCY=5 - pytest 8.3.3 + pytest .+ -----> test command `./bin/print-env-vars.sh && pytest --version` completed successfully REGEX @@ -68,8 +67,7 @@ -----> Using Python #{DEFAULT_PYTHON_MAJOR_VERSION} specified in .python-version -----> Restoring cache -----> Using cached install of Python #{DEFAULT_PYTHON_FULL_VERSION} - -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} - -----> Installing SQLite3 + -----> Installing pip #{PIP_VERSION} -----> Installing dependencies using 'pip install -r requirements.txt -r requirements-test.txt' -----> Skipping Django collectstatic since the env var DISABLE_COLLECTSTATIC is set. -----> Running bin/post_compile hook @@ -87,9 +85,8 @@ -----> Python app detected -----> Using Python #{DEFAULT_PYTHON_MAJOR_VERSION} specified in .python-version -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} + -----> Installing pip #{PIP_VERSION} -----> Installing Pipenv #{PIPENV_VERSION} - -----> Installing SQLite3 -----> Installing dependencies using 'pipenv install --deploy --dev' Installing dependencies from Pipfile.lock \\(.+\\)... Installing dependencies from Pipfile.lock \\(.+\\)... @@ -132,7 +129,7 @@ PYTHONPATH=/app PYTHONUNBUFFERED=true WEB_CONCURRENCY=5 - pytest 8.3.3 + pytest .+ -----> test command `./bin/print-env-vars.sh && pytest --version` completed successfully REGEX @@ -142,9 +139,8 @@ -----> Using Python #{DEFAULT_PYTHON_MAJOR_VERSION} specified in .python-version -----> Restoring cache -----> Using cached install of Python #{DEFAULT_PYTHON_FULL_VERSION} - -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} + -----> Installing pip #{PIP_VERSION} -----> Installing Pipenv #{PIPENV_VERSION} - -----> Installing SQLite3 -----> Installing dependencies using 'pipenv install --deploy --dev' Installing dependencies from Pipfile.lock \\(.+\\)... Installing dependencies from Pipfile.lock \\(.+\\)... @@ -216,7 +212,7 @@ PYTHONPATH=/app PYTHONUNBUFFERED=true WEB_CONCURRENCY=5 - pytest 8.3.3 + pytest .+ -----> test command `./bin/print-env-vars.sh && pytest --version` completed successfully REGEX diff --git a/spec/hatchet/pip_spec.rb b/spec/hatchet/pip_spec.rb index e2af8d585..1468c0e0b 100644 --- a/spec/hatchet/pip_spec.rb +++ b/spec/hatchet/pip_spec.rb @@ -22,8 +22,7 @@ remote: -----> Python app detected remote: -----> Using Python #{DEFAULT_PYTHON_MAJOR_VERSION} specified in .python-version remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} - remote: -----> Installing SQLite3 + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing dependencies using 'pip install -r requirements.txt' remote: Collecting typing-extensions==4.12.2 (from -r requirements.txt (line 5)) remote: Downloading typing_extensions-4.12.2-py3-none-any.whl.metadata (3.0 kB) @@ -42,19 +41,17 @@ remote: remote: ['', remote: '/app', - remote: '/app/.heroku/python/lib/python312.zip', - remote: '/app/.heroku/python/lib/python3.12', - remote: '/app/.heroku/python/lib/python3.12/lib-dynload', - remote: '/app/.heroku/python/lib/python3.12/site-packages'] + remote: '/app/.heroku/python/lib/python313.zip', + remote: '/app/.heroku/python/lib/python3.13', + remote: '/app/.heroku/python/lib/python3.13/lib-dynload', + remote: '/app/.heroku/python/lib/python3.13/site-packages'] remote: remote: Package Version remote: ----------------- ------- remote: pip #{PIP_VERSION} - remote: setuptools #{SETUPTOOLS_VERSION} remote: typing_extensions 4.12.2 - remote: wheel #{WHEEL_VERSION} remote: - remote: + remote: OUTPUT app.commit! app.push! @@ -63,8 +60,7 @@ remote: -----> Using Python #{DEFAULT_PYTHON_MAJOR_VERSION} specified in .python-version remote: -----> Restoring cache remote: -----> Using cached install of Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} - remote: -----> Installing SQLite3 + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing dependencies using 'pip install -r requirements.txt' remote: -----> Inline app detected OUTPUT @@ -88,8 +84,7 @@ remote: -----> Discarding cache since: remote: - The contents of requirements.txt changed remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} - remote: -----> Installing SQLite3 + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing dependencies using 'pip install -r requirements.txt' remote: Collecting typing-extensions==4.12.2 (from -r requirements.txt (line 5)) remote: Downloading typing_extensions-4.12.2-py3-none-any.whl.metadata (3.0 kB) @@ -120,8 +115,7 @@ remote: -----> Discarding cache since: remote: - The package manager has changed from pipenv to pip remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} - remote: -----> Installing SQLite3 + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing dependencies using 'pip install -r requirements.txt' remote: Collecting typing-extensions==4.12.2 (from -r requirements.txt (line 5)) remote: Downloading typing_extensions-4.12.2-py3-none-any.whl.metadata (3.0 kB) @@ -133,12 +127,15 @@ end end + # TODO: Switch this to using Python 3.13 as part of the sqlite removal. context 'when requirements.txt contains popular compiled packages' do let(:app) { Hatchet::Runner.new('spec/fixtures/requirements_compiled') } include_examples 'installs successfully using pip' end + # This test intentionally uses Python 3.12, so that we test rewriting using older globally installed + # setuptools. The Poetry equivalent of this test covers the PEP-517/518 setuptools case. context 'when requirements.txt contains editable requirements (both VCS and local package)' do let(:buildpacks) { [:default, 'heroku-community/inline'] } let(:app) { Hatchet::Runner.new('spec/fixtures/requirements_editable', buildpacks:) } @@ -219,16 +216,12 @@ remote: -----> Python app detected remote: -----> Using Python #{DEFAULT_PYTHON_MAJOR_VERSION} specified in .python-version remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} - remote: -----> Installing SQLite3 + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing dependencies using 'pip install --editable .' remote: Obtaining file:///tmp/build_.* - remote: Preparing metadata \\(setup.py\\): started - remote: Preparing metadata \\(setup.py\\): finished with status 'done' remote: .+ remote: Installing collected packages: six, test - remote: DEPRECATION: Legacy editable install of test==0.0.0 from file:///tmp/build_.* \\(setup.py develop\\) is deprecated. pip 25.0 will enforce this behaviour change. A possible replacement is to add a pyproject.toml or enable --use-pep517, and use setuptools >= 64. If the resulting installation is not behaving as expected, try using --config-settings editable_mode=compat. Please consult the setuptools documentation for more information. Discussion can be found at https://github.com/pypa/pip/issues/11457 - remote: Running setup.py develop for test + remote: Successfully installed six-.+ test-0.0.0 REGEX end end diff --git a/spec/hatchet/pipenv_spec.rb b/spec/hatchet/pipenv_spec.rb index 8aeeb697f..7683592fd 100644 --- a/spec/hatchet/pipenv_spec.rb +++ b/spec/hatchet/pipenv_spec.rb @@ -14,9 +14,8 @@ remote: -----> Python app detected remote: -----> Using Python #{DEFAULT_PYTHON_MAJOR_VERSION} specified in Pipfile.lock remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing Pipenv #{PIPENV_VERSION} - remote: -----> Installing SQLite3 remote: -----> Installing dependencies using 'pipenv install --deploy' remote: Installing dependencies from Pipfile.lock \\(.+\\)... remote: -----> Inline app detected @@ -31,10 +30,10 @@ remote: remote: \\['', remote: '/app', - remote: '/app/.heroku/python/lib/python312.zip', - remote: '/app/.heroku/python/lib/python3.12', - remote: '/app/.heroku/python/lib/python3.12/lib-dynload', - remote: '/app/.heroku/python/lib/python3.12/site-packages'\\] + remote: '/app/.heroku/python/lib/python313.zip', + remote: '/app/.heroku/python/lib/python3.13', + remote: '/app/.heroku/python/lib/python3.13/lib-dynload', + remote: '/app/.heroku/python/lib/python3.13/site-packages'\\] remote: remote: Package Version remote: ----------------- --------- @@ -44,12 +43,11 @@ remote: pip #{PIP_VERSION} remote: pipenv #{PIPENV_VERSION} remote: platformdirs .+ - remote: setuptools #{SETUPTOOLS_VERSION} + remote: setuptools .+ remote: typing_extensions 4.12.2 remote: virtualenv .+ - remote: wheel #{WHEEL_VERSION} remote: - remote: \\ + remote: \\ REGEX app.commit! app.push! @@ -58,9 +56,8 @@ remote: -----> Using Python #{DEFAULT_PYTHON_MAJOR_VERSION} specified in Pipfile.lock remote: -----> Restoring cache remote: -----> Using cached install of Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing Pipenv #{PIPENV_VERSION} - remote: -----> Installing SQLite3 remote: -----> Installing dependencies using 'pipenv install --deploy' remote: Installing dependencies from Pipfile.lock \\(.+\\)... remote: -----> Inline app detected @@ -126,9 +123,8 @@ remote: -----> No Python version was specified. Using the buildpack default: Python #{DEFAULT_PYTHON_MAJOR_VERSION} remote: To use a different version, see: https://devcenter.heroku.com/articles/python-runtimes remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing Pipenv #{PIPENV_VERSION} - remote: -----> Installing SQLite3 remote: -----> Installing dependencies using 'pipenv install --deploy' remote: Installing dependencies from Pipfile.lock \\(.+\\)... REGEX @@ -160,9 +156,8 @@ remote: -----> No Python version was specified. Using the buildpack default: Python #{DEFAULT_PYTHON_MAJOR_VERSION} remote: To use a different version, see: https://devcenter.heroku.com/articles/python-runtimes remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing Pipenv #{PIPENV_VERSION} - remote: -----> Installing SQLite3 remote: -----> Installing dependencies using 'pipenv install --skip-lock' remote: The flag --skip-lock has been reintroduced \\(but is not recommended\\). Without remote: the lock resolver it is difficult to manage multiple package indexes, and hash @@ -309,9 +304,8 @@ remote: - The Python version has changed from 3.12.4 to #{DEFAULT_PYTHON_FULL_VERSION} remote: - The Pipenv version has changed from 2023.12.1 to #{PIPENV_VERSION} remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing Pipenv #{PIPENV_VERSION} - remote: -----> Installing SQLite3 remote: -----> Installing dependencies using 'pipenv install --deploy' remote: Installing dependencies from Pipfile.lock \\(.+\\)... remote: -----> Discovering process types @@ -337,9 +331,8 @@ remote: -----> Discarding cache since: remote: - The package manager has changed from pip to pipenv remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing Pipenv #{PIPENV_VERSION} - remote: -----> Installing SQLite3 remote: -----> Installing dependencies using 'pipenv install --deploy' remote: Installing dependencies from Pipfile.lock \\(.+\\)... remote: -----> Discovering process types @@ -371,11 +364,10 @@ remote: ! Decide which package manager you want to use with your app, and remote: ! then delete the file\\(s\\) and any config from the others. remote: - remote: -----> Using Python 3.12 specified in Pipfile.lock - remote: -----> Installing Python #{LATEST_PYTHON_3_12} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} + remote: -----> Using Python #{DEFAULT_PYTHON_MAJOR_VERSION} specified in Pipfile.lock + remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing Pipenv #{PIPENV_VERSION} - remote: -----> Installing SQLite3 remote: -----> Installing dependencies using 'pipenv install --deploy' remote: Installing dependencies from Pipfile.lock \\(.+\\)... REGEX @@ -395,9 +387,8 @@ remote: -----> No Python version was specified. Using the buildpack default: Python #{DEFAULT_PYTHON_MAJOR_VERSION} remote: To use a different version, see: https://devcenter.heroku.com/articles/python-runtimes remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing Pipenv #{PIPENV_VERSION} - remote: -----> Installing SQLite3 remote: -----> Installing dependencies using 'pipenv install --deploy' remote: Your Pipfile.lock \\(.+\\) is out of date. Expected: \\(.+\\). remote: .+ diff --git a/spec/hatchet/poetry_spec.rb b/spec/hatchet/poetry_spec.rb index ca2caf1d9..c4514019d 100644 --- a/spec/hatchet/poetry_spec.rb +++ b/spec/hatchet/poetry_spec.rb @@ -33,15 +33,15 @@ remote: remote: ['', remote: '/app', - remote: '/app/.heroku/python/lib/python312.zip', - remote: '/app/.heroku/python/lib/python3.12', - remote: '/app/.heroku/python/lib/python3.12/lib-dynload', - remote: '/app/.heroku/python/lib/python3.12/site-packages'] + remote: '/app/.heroku/python/lib/python313.zip', + remote: '/app/.heroku/python/lib/python3.13', + remote: '/app/.heroku/python/lib/python3.13/lib-dynload', + remote: '/app/.heroku/python/lib/python3.13/site-packages'] remote: remote: Skipping virtualenv creation, as specified in config file. remote: typing-extensions 4.12.2 Backported and Experimental Type Hints for Python ... remote: - remote: + remote: OUTPUT app.commit! app.push! @@ -64,18 +64,19 @@ # TODO: Make this also test the Poetry version changing, the next (first) time we update Poetry, # by using an older buildpack version for the initial build. context 'when the requested Python version has changed since the last build' do - let(:app) { Hatchet::Runner.new('spec/fixtures/poetry_basic') } + let(:buildpacks) { ['https://github.com/heroku/heroku-buildpack-python#v268'] } + let(:app) { Hatchet::Runner.new('spec/fixtures/poetry_basic', buildpacks:) } it 'clears the cache before installing' do app.deploy do |app| - File.write('.python-version', '3.13') + update_buildpacks(app, [:default]) app.commit! app.push! expect(clean_output(app.output)).to include(<<~OUTPUT) remote: -----> Python app detected remote: -----> Using Python 3.13 specified in .python-version remote: -----> Discarding cache since: - remote: - The Python version has changed from #{LATEST_PYTHON_3_12} to #{LATEST_PYTHON_3_13} + remote: - The Python version has changed from 3.13.0 to #{LATEST_PYTHON_3_13} remote: -----> Installing Python #{LATEST_PYTHON_3_13} remote: -----> Installing Poetry #{POETRY_VERSION} remote: -----> Installing dependencies using 'poetry install --sync --only main' @@ -270,9 +271,8 @@ remote: ! the warning above. remote: remote: -----> Using Python #{DEFAULT_PYTHON_MAJOR_VERSION} specified in .python-version - remote: -----> Installing Python #{LATEST_PYTHON_3_12} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} - remote: -----> Installing SQLite3 + remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing dependencies using 'pip install -r requirements.txt' OUTPUT end diff --git a/spec/hatchet/python_version_spec.rb b/spec/hatchet/python_version_spec.rb index 5c2227a33..28ee14641 100644 --- a/spec/hatchet/python_version_spec.rb +++ b/spec/hatchet/python_version_spec.rb @@ -206,7 +206,7 @@ remote: ! No Python version was found in the '.python-version' file. remote: ! remote: ! Update the file so that it contains a valid Python version - remote: ! such as '3.12'. + remote: ! such as '#{DEFAULT_PYTHON_MAJOR_VERSION}'. remote: ! remote: ! If the file already contains a version, check the line doesn't remote: ! begin with a '#', otherwise it will be treated as a comment. diff --git a/spec/hatchet/stack_spec.rb b/spec/hatchet/stack_spec.rb index b9cff5c9f..46817cad6 100644 --- a/spec/hatchet/stack_spec.rb +++ b/spec/hatchet/stack_spec.rb @@ -53,8 +53,7 @@ remote: -----> Discarding cache since: remote: - The stack has changed from heroku-24 to heroku-22 remote: -----> Installing Python #{DEFAULT_PYTHON_FULL_VERSION} - remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION} - remote: -----> Installing SQLite3 + remote: -----> Installing pip #{PIP_VERSION} remote: -----> Installing dependencies using 'pip install -r requirements.txt' remote: Collecting typing-extensions==4.12.2 (from -r requirements.txt (line 2)) OUTPUT diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9668d6aa3..2405d9303 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -15,7 +15,7 @@ LATEST_PYTHON_3_11 = '3.11.11' LATEST_PYTHON_3_12 = '3.12.8' LATEST_PYTHON_3_13 = '3.13.1' -DEFAULT_PYTHON_FULL_VERSION = LATEST_PYTHON_3_12 +DEFAULT_PYTHON_FULL_VERSION = LATEST_PYTHON_3_13 DEFAULT_PYTHON_MAJOR_VERSION = DEFAULT_PYTHON_FULL_VERSION.gsub(/\.\d+$/, '') # The requirement versions are effectively buildpack constants, however, we want