Skip to content

Commit d9bdeab

Browse files
authored
Add support for the .python-version file (#1664)
Following on from the recent Python version refactoring, this now adds support for configuring the app's Python version using a `.python-version` file. This file is used by several tools in the Python ecosystem (such as pyenv, `actions/setup-python`, uv), whereas the existing `runtime.txt` file is proprietary to Heroku. This change is the classic Python buildpack equivalent of the Python CNB change here: heroku/buildpacks-python#272 If both a `runtime.txt` file and a `.python-version` file are present, then the `runtime.txt` file will take precedence. However, use of the `.python-version` file is now recommended, since `runtime.txt` will be deprecated in the future. Both the `runtime.txt` file and `.python-version` file take precedence over any Python version specified in a `Pipfile.lock` for Pipenv users. We support the following `.python-version` syntax: - Major Python version (e.g. `3.13`, which will then be resolved to the latest Python 3.13). (This form is recommended, since it allows for Python security updates to be pulled in without having to manually bump the version.) - Exact Python version (e.g. `3.13.0`) - Comments (lines starting with `#`) - Blank lines We don't support the following `.python-version` features: - Specifying multiple Python versions - Prefixing versions with `python-` (since this form is undocumented and will likely be deprecated by pyenv in the future) In addition, the existing `runtime.txt` support has been updated to allow specifying just the major Python version, in order to increase feature parity between the files, and avoid confusion if users try to use the major version only syntax from `.python-version` in their `runtime.txt`. Refs #913. Refs #932. GUS-W-7671453. GUS-W-16821357.
1 parent 737bba1 commit d9bdeab

File tree

91 files changed

+630
-726
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+630
-726
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,4 @@ jobs:
7373
- name: Run buildpack using default app fixture
7474
run: make run
7575
- name: Run buildpack using an app fixture that's expected to fail
76-
run: make run FIXTURE=spec/fixtures/python_version_invalid/
76+
run: make run FIXTURE=spec/fixtures/python_version_file_invalid_version/

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## [Unreleased]
44

5+
- Added support for configuring the Python version using a `.python-version` file. Both the `3.N` and `3.N.N` version forms are supported (the former is recommended). The existing `runtime.txt` file will take precedence if both files are found, however, we recommend switching to `.python-version` since it is more commonly supported in the Python ecosystem. ([#1664](https://github.com/heroku/heroku-buildpack-python/pull/1664))
6+
- Added support for specifying only the Python major version in `runtime.txt` instead of requiring the full Python version (for example `python-3.N` instead of `python-3.N.N`). ([#1664](https://github.com/heroku/heroku-buildpack-python/pull/1664))
57

68
## [v260] - 2024-10-10
79

README.md

+49-58
Original file line numberDiff line numberDiff line change
@@ -8,61 +8,52 @@ This is the official [Heroku buildpack](https://devcenter.heroku.com/articles/bu
88

99
Recommended web frameworks include **Django** and **Flask**, among others. The recommended webserver is **Gunicorn**. There are no restrictions around what software can be used (as long as it's pip-installable). Web processes must bind to `$PORT`, and only the HTTP protocol is permitted for incoming connections.
1010

11-
See it in Action
12-
----------------
13-
```
14-
$ ls
15-
my-application requirements.txt runtime.txt
16-
17-
$ git push heroku main
18-
Counting objects: 4, done.
19-
Delta compression using up to 8 threads.
20-
Compressing objects: 100% (2/2), done.
21-
Writing objects: 100% (4/4), 276 bytes | 276.00 KiB/s, done.
22-
Total 4 (delta 0), reused 0 (delta 0)
23-
remote: Compressing source files... done.
24-
remote: Building source:
25-
remote:
26-
remote: -----> Python app detected
27-
remote: -----> Installing python
28-
remote: -----> Installing pip
29-
remote: -----> Installing SQLite3
30-
remote: -----> Installing requirements with pip
31-
remote: Collecting flask (from -r /tmp/build_c2c067ef79ff14c9bf1aed6796f9ed1f/requirements.txt (line 1))
32-
remote: Downloading ...
33-
remote: Installing collected packages: Werkzeug, click, MarkupSafe, Jinja2, itsdangerous, flask
34-
remote: Successfully installed Jinja2-2.10 MarkupSafe-1.1.0 Werkzeug-0.14.1 click-7.0 flask-1.0.2 itsdangerous-1.1.0
35-
remote:
36-
remote: -----> Discovering process types
37-
remote: Procfile declares types -> (none)
38-
remote:
39-
```
40-
41-
A `requirements.txt` must be present at the root of your application's repository to deploy.
42-
43-
To specify your python version, you also need a `runtime.txt` file - unless you are using the default Python runtime version.
44-
45-
Current default Python Runtime: Python 3.12.7
46-
47-
Alternatively, you can provide a `setup.py` file, or a `Pipfile`.
48-
Using `pipenv` will generate `runtime.txt` at build time if one of the field `python_version` or `python_full_version` is specified in the `requires` section of your `Pipfile`.
49-
50-
Specify a Buildpack Version
51-
---------------------------
52-
53-
You can specify the latest production release of this buildpack for upcoming builds of an existing application:
54-
55-
$ heroku buildpacks:set heroku/python
56-
57-
58-
Specify a Python Runtime
59-
------------------------
60-
61-
Supported runtime options include:
62-
63-
- `python-3.13.0` on all [supported stacks](https://devcenter.heroku.com/articles/stack#stack-support-details)
64-
- `python-3.12.7` on all [supported stacks](https://devcenter.heroku.com/articles/stack#stack-support-details)
65-
- `python-3.11.10` on all [supported stacks](https://devcenter.heroku.com/articles/stack#stack-support-details)
66-
- `python-3.10.15` on all [supported stacks](https://devcenter.heroku.com/articles/stack#stack-support-details)
67-
- `python-3.9.20` on all [supported stacks](https://devcenter.heroku.com/articles/stack#stack-support-details)
68-
- `python-3.8.20` on Heroku-20 only
11+
## Getting Started
12+
13+
See the [Getting Started on Heroku with Python](https://devcenter.heroku.com/articles/getting-started-with-python) tutorial.
14+
15+
## Application Requirements
16+
17+
A `requirements.txt` or `Pipfile` file must be present in the root (top-level) directory of your app's source code.
18+
19+
## Configuration
20+
21+
### Python Version
22+
23+
We recommend that you specify a Python version for your app rather than relying on the buildpack's default Python version.
24+
25+
For example, to request the latest patch release of Python 3.13, create a `.python-version` file in
26+
the root directory of your app containing:
27+
`3.13`
28+
29+
The buildpack will look for a Python version in the following places (in descending order of precedence):
30+
31+
1. `runtime.txt` file (deprecated)
32+
2. `.python-version` file (recommended)
33+
3. The `python_full_version` field in the `Pipfile.lock` file
34+
4. The `python_version` field in the `Pipfile.lock` file
35+
36+
If none of those are found, the buildpack will use a default Python version for the first
37+
build of an app, and then subsequent builds of that app will be pinned to that version
38+
unless the build cache is cleared or you request a different version.
39+
40+
The current default Python version is: 3.12
41+
42+
The supported Python versions are:
43+
44+
- Python 3.13
45+
- Python 3.12
46+
- Python 3.11
47+
- Python 3.10
48+
49+
These Python versions are deprecated on Heroku:
50+
51+
- Python 3.9
52+
- Python 3.8 (only available on the [Heroku-20](https://devcenter.heroku.com/articles/heroku-20-stack) stack)
53+
54+
Python versions older than those listed above are no longer supported, since they have reached
55+
end-of-life [upstream](https://devguide.python.org/versions/#supported-versions).
56+
57+
## Documentation
58+
59+
For more information about using Python on Heroku, see [Dev Center](https://devcenter.heroku.com/categories/python-support).

bin/compile

+3
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ fi
154154
python_version::read_requested_python_version "${BUILD_DIR}" "${package_manager}" "${cached_python_version}" requested_python_version python_version_origin
155155
meta_set "python_version_reason" "${python_version_origin}"
156156

157+
# TODO: More strongly recommend specifying a Python version (eg switch the messaging to
158+
# be a warning instead, after version resolution, and mention .python-version inline)
159+
# TODO: Add runtime.txt deprecation warning.
157160
case "${python_version_origin}" in
158161
default)
159162
puts-step "No Python version was specified. Using the buildpack default: Python ${requested_python_version}"

bin/steps/python

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ PYTHON_URL="${S3_BASE_URL}/python-${python_full_version}-ubuntu-${UBUNTU_VERSION
1818
# TODO: Update this message to be more specific once Python 3.8 support is dropped.
1919
if ! curl --output /dev/null --silent --head --fail --retry 3 --retry-connrefused --connect-timeout 10 "${PYTHON_URL}"; then
2020
display_error <<-EOF
21-
Error: Python ${python_full_version} is not available for this stack (${STACK}).
21+
Error: Python ${python_full_version} isn't available for this stack (${STACK}).
2222
2323
For a list of the supported Python versions, see:
2424
https://devcenter.heroku.com/articles/python-support#supported-runtimes
@@ -35,6 +35,8 @@ function warn_if_patch_update_available() {
3535
# Extract the patch version component of the version strings (ie: the '5' in '3.10.5').
3636
local requested_patch_number="${requested_full_version##*.}"
3737
local latest_patch_number="${latest_patch_version##*.}"
38+
# TODO: Update this message to suggest using the .python-version major version syntax to stay up to date,
39+
# once runtime.txt is deprecated and sticky-versioning only pins to the major version.
3840
if ((requested_patch_number < latest_patch_number)); then
3941
puts-warn
4042
puts-warn "A Python security update is available! Upgrade as soon as possible to: Python ${latest_patch_version}"

0 commit comments

Comments
 (0)