Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Deprecated support for Python 3.10. ([#1972](https://github.com/heroku/heroku-buildpack-python/pull/1972))
- Updated uv from 0.9.9 to 0.9.11. ([#1973](https://github.com/heroku/heroku-buildpack-python/pull/1973))
- Added more messaging to the build log recommending uv. ([#1975](https://github.com/heroku/heroku-buildpack-python/pull/1975))
- Switched from using `--disable-pip-version-check` to the env var `PIP_DISABLE_PIP_VERSION_CHECK=1` when using pip. ([#1974](https://github.com/heroku/heroku-buildpack-python/pull/1974))

## [v320] - 2025-11-20
Expand Down
14 changes: 14 additions & 0 deletions bin/compile
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,18 @@ hooks::run_hook "post_compile"

cache::save "${BUILD_DIR}" "${CACHE_DIR}" "${STACK}" "${python_full_version}" "${package_manager}"

if [[ "${package_manager}" != "uv" ]]; then
output::notice <<-EOF
Note: We recently added support for the package manager uv:
https://devcenter.heroku.com/changelog-items/3238

It's now our recommended Python package manager, since it
supports lockfiles, is faster, gives more helpful error
messages, and is actively maintained by a full-time team.

If you haven't tried it yet, we suggest you take a look!
https://docs.astral.sh/uv/
EOF
fi

build_data::set_duration "total_duration" "${compile_start_time}"
5 changes: 5 additions & 0 deletions bin/detect
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ If your app already has a package manager file, check that it:
Otherwise, add a package manager file to your app. If your app has
no dependencies, then create an empty 'requirements.txt' file.

If you aren't sure which package manager to use, we recommend
trying uv, since it supports lockfiles, is extremely fast, and
is actively maintained by a full-time team:
https://docs.astral.sh/uv/

For help with using Python on Heroku, see:
https://devcenter.heroku.com/articles/getting-started-with-python
https://devcenter.heroku.com/articles/python-support
Expand Down
6 changes: 4 additions & 2 deletions lib/package_manager.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ function package_manager::determine_package_manager() {
delete your 'Pipfile' and then add either a 'requirements.txt',
'poetry.lock' or 'uv.lock' file.

Note: This error replaces the warning which was displayed in
build logs starting 12th November 2024.
If you aren't sure which package manager to use, we recommend
trying uv, since it supports lockfiles, is extremely fast, and
is actively maintained by a full-time team:
https://docs.astral.sh/uv/
EOF
build_data::set_string "failure_reason" "package-manager::pipenv-missing-lockfile"
exit 1
Expand Down
33 changes: 33 additions & 0 deletions spec/hatchet/ci_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@
PKG_CONFIG_PATH=/app/.heroku/python/lib/pkg-config
PYTHONUNBUFFERED=1
-----> Saving cache

! Note: We recently added support for the package manager uv:
! https://devcenter.heroku.com/changelog-items/3238
!
! It's now our recommended Python package manager, since it
! supports lockfiles, is faster, gives more helpful error
! messages, and is actively maintained by a full-time team.
!
! If you haven't tried it yet, we suggest you take a look!
! https://docs.astral.sh/uv/

-----> Inline app detected
LANG=en_US.UTF-8
LD_LIBRARY_PATH=/app/.heroku/python/lib
Expand Down Expand Up @@ -117,6 +128,17 @@
PYTHONUNBUFFERED=1
VIRTUAL_ENV=/app/.heroku/python
-----> Saving cache

! Note: We recently added support for the package manager uv:
! https://devcenter.heroku.com/changelog-items/3238
!
! It's now our recommended Python package manager, since it
! supports lockfiles, is faster, gives more helpful error
! messages, and is actively maintained by a full-time team.
!
! If you haven't tried it yet, we suggest you take a look!
! https://docs.astral.sh/uv/

-----> Inline app detected
LANG=en_US.UTF-8
LD_LIBRARY_PATH=/app/.heroku/python/lib
Expand Down Expand Up @@ -205,6 +227,17 @@
POETRY_VIRTUALENVS_USE_POETRY_PYTHON=true
PYTHONUNBUFFERED=1
-----> Saving cache

! Note: We recently added support for the package manager uv:
! https://devcenter.heroku.com/changelog-items/3238
!
! It's now our recommended Python package manager, since it
! supports lockfiles, is faster, gives more helpful error
! messages, and is actively maintained by a full-time team.
!
! If you haven't tried it yet, we suggest you take a look!
! https://docs.astral.sh/uv/

-----> Inline app detected
LANG=en_US.UTF-8
LD_LIBRARY_PATH=/app/.heroku/python/lib
Expand Down
5 changes: 5 additions & 0 deletions spec/hatchet/detect_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@
remote: ! Otherwise, add a package manager file to your app. If your app has
remote: ! no dependencies, then create an empty 'requirements.txt' file.
remote: !
remote: ! If you aren't sure which package manager to use, we recommend
remote: ! trying uv, since it supports lockfiles, is extremely fast, and
remote: ! is actively maintained by a full-time team:
remote: ! https://docs.astral.sh/uv/
remote: !
remote: ! For help with using Python on Heroku, see:
remote: ! https://devcenter.heroku.com/articles/getting-started-with-python
remote: ! https://devcenter.heroku.com/articles/python-support
Expand Down
18 changes: 15 additions & 3 deletions spec/hatchet/pip_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@
remote: PKG_CONFIG_PATH=/app/.heroku/python/lib/pkg-config
remote: PYTHONUNBUFFERED=1
remote: -----> Saving cache
remote:
remote: ! Note: We recently added support for the package manager uv:
remote: ! https://devcenter.heroku.com/changelog-items/3238
remote: !
remote: ! It's now our recommended Python package manager, since it
remote: ! supports lockfiles, is faster, gives more helpful error
remote: ! messages, and is actively maintained by a full-time team.
remote: !
remote: ! If you haven't tried it yet, we suggest you take a look!
remote: ! https://docs.astral.sh/uv/
remote:
remote: -----> Inline app detected
remote: LANG=en_US.UTF-8
remote: LD_LIBRARY_PATH=/app/.heroku/python/lib
Expand Down Expand Up @@ -96,7 +107,6 @@
remote: -----> Running bin/post_compile hook
remote: .+
remote: -----> Saving cache
remote: -----> Inline app detected
REGEX

# For historical reasons pip is made available at run-time too, unlike some of the other package managers.
Expand Down Expand Up @@ -162,7 +172,7 @@

it 'rewrites .pth, .egg-link and finder paths correctly for hooks, later buildpacks, runtime and cached builds' do
app.deploy do |app|
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX))
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX, Regexp::MULTILINE))
remote: -----> Running bin/post_compile hook
remote: easy-install.pth:/app/.heroku/python/src/gunicorn
remote: easy-install.pth:/tmp/build_.+/packages/local_package_setup_py
Expand All @@ -174,6 +184,7 @@
remote: Running entrypoint for the setup.py-based local package: Hello from setup.py!
remote: Running entrypoint for the VCS package: gunicorn \\(version 20.1.0\\)
remote: -----> Saving cache
.+
remote: -----> Inline app detected
remote: easy-install.pth:/app/.heroku/python/src/gunicorn
remote: easy-install.pth:/tmp/build_.+/packages/local_package_setup_py
Expand Down Expand Up @@ -202,7 +213,7 @@
# Test that the cached .pth files work correctly.
app.commit!
app.push!
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX))
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX, Regexp::MULTILINE))
remote: -----> Running bin/post_compile hook
remote: easy-install.pth:/app/.heroku/python/src/gunicorn
remote: easy-install.pth:/tmp/build_.+/packages/local_package_setup_py
Expand All @@ -214,6 +225,7 @@
remote: Running entrypoint for the setup.py-based local package: Hello from setup.py!
remote: Running entrypoint for the VCS package: gunicorn \\(version 20.1.0\\)
remote: -----> Saving cache
.+
remote: -----> Inline app detected
remote: easy-install.pth:/app/.heroku/python/src/gunicorn
remote: easy-install.pth:/tmp/build_.+/packages/local_package_setup_py
Expand Down
26 changes: 19 additions & 7 deletions spec/hatchet/pipenv_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@
remote: PYTHONUNBUFFERED=1
remote: VIRTUAL_ENV=/app/.heroku/python
remote: -----> Saving cache
remote:
remote: ! Note: We recently added support for the package manager uv:
remote: ! https://devcenter.heroku.com/changelog-items/3238
remote: !
remote: ! It's now our recommended Python package manager, since it
remote: ! supports lockfiles, is faster, gives more helpful error
remote: ! messages, and is actively maintained by a full-time team.
remote: !
remote: ! If you haven't tried it yet, we suggest you take a look!
remote: ! https://docs.astral.sh/uv/
remote:
remote: -----> Inline app detected
remote: LANG=en_US.UTF-8
remote: LD_LIBRARY_PATH=/app/.heroku/python/lib
Expand Down Expand Up @@ -96,7 +107,6 @@
remote: -----> Running bin/post_compile hook
remote: .+
remote: -----> Saving cache
remote: -----> Inline app detected
REGEX

# For historical reasons Pipenv is made available at run-time too, unlike some of the other package managers.
Expand Down Expand Up @@ -141,7 +151,6 @@
remote: -----> Installing dependencies using 'pipenv install --deploy'
remote: Installing dependencies from Pipfile.lock \\(.+\\)...
remote: -----> Saving cache
remote: -----> Discovering process types
REGEX
end
end
Expand Down Expand Up @@ -303,8 +312,10 @@
remote: ! delete your 'Pipfile' and then add either a 'requirements.txt',
remote: ! 'poetry.lock' or 'uv.lock' file.
remote: !
remote: ! Note: This error replaces the warning which was displayed in
remote: ! build logs starting 12th November 2024.
remote: ! If you aren't sure which package manager to use, we recommend
remote: ! trying uv, since it supports lockfiles, is extremely fast, and
remote: ! is actively maintained by a full-time team:
remote: ! https://docs.astral.sh/uv/
remote:
remote: ! Push rejected, failed to compile Python app.
REGEX
Expand Down Expand Up @@ -465,7 +476,6 @@
remote: -----> Installing dependencies using 'pipenv install --deploy'
remote: Installing dependencies from Pipfile.lock \\(.+\\)...
remote: -----> Saving cache
remote: -----> Discovering process types
REGEX
end
end
Expand All @@ -477,7 +487,7 @@

it 'rewrites .pth and finder paths correctly for hooks, later buildpacks, runtime and cached builds' do
app.deploy do |app|
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX))
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX, Regexp::MULTILINE))
remote: -----> Installing dependencies using 'pipenv install --deploy'
remote: Installing dependencies from Pipfile.lock \\(.+\\)...
remote: -----> Running bin/post_compile hook
Expand All @@ -491,6 +501,7 @@
remote: Running entrypoint for the setup.py-based local package: Hello from setup.py!
remote: Running entrypoint for the VCS package: gunicorn \\(version 23.0.0\\)
remote: -----> Saving cache
.+
remote: -----> Inline app detected
remote: __editable___gunicorn_23_0_0_finder.py:/app/.heroku/python/src/gunicorn/gunicorn'}
remote: __editable___local_package_pyproject_toml_0_0_1_finder.py:/tmp/build_.+/packages/local_package_pyproject_toml/local_package_pyproject_toml'}
Expand Down Expand Up @@ -519,7 +530,7 @@
# Test that the cached .pth files work correctly.
app.commit!
app.push!
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX))
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX, Regexp::MULTILINE))
remote: -----> Installing dependencies using 'pipenv install --deploy'
remote: Installing dependencies from Pipfile.lock \\(.+\\)...
remote: -----> Running bin/post_compile hook
Expand All @@ -533,6 +544,7 @@
remote: Running entrypoint for the setup.py-based local package: Hello from setup.py!
remote: Running entrypoint for the VCS package: gunicorn \\(version 23.0.0\\)
remote: -----> Saving cache
.+
remote: -----> Inline app detected
remote: __editable___gunicorn_23_0_0_finder.py:/app/.heroku/python/src/gunicorn/gunicorn'}
remote: __editable___local_package_pyproject_toml_0_0_1_finder.py:/tmp/build_.+/packages/local_package_pyproject_toml/local_package_pyproject_toml'}
Expand Down
19 changes: 15 additions & 4 deletions spec/hatchet/poetry_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@
remote: POETRY_VIRTUALENVS_USE_POETRY_PYTHON=true
remote: PYTHONUNBUFFERED=1
remote: -----> Saving cache
remote:
remote: ! Note: We recently added support for the package manager uv:
remote: ! https://devcenter.heroku.com/changelog-items/3238
remote: !
remote: ! It's now our recommended Python package manager, since it
remote: ! supports lockfiles, is faster, gives more helpful error
remote: ! messages, and is actively maintained by a full-time team.
remote: !
remote: ! If you haven't tried it yet, we suggest you take a look!
remote: ! https://docs.astral.sh/uv/
remote:
remote: -----> Inline app detected
remote: LANG=en_US.UTF-8
remote: LD_LIBRARY_PATH=/app/.heroku/python/lib
Expand Down Expand Up @@ -98,7 +109,6 @@
remote: -----> Running bin/post_compile hook
remote: .+
remote: -----> Saving cache
remote: -----> Inline app detected
REGEX

command = 'bin/print-env-vars.sh && if command -v poetry; then echo "Poetry unexpectedly found!" && exit 1; fi'
Expand Down Expand Up @@ -145,7 +155,6 @@
remote:
remote: - Installing typing-extensions (4.12.2)
remote: -----> Saving cache
remote: -----> Discovering process types
OUTPUT
end
end
Expand All @@ -157,7 +166,7 @@

it 'rewrites .pth and finder paths correctly for hooks, later buildpacks, runtime and cached builds' do
app.deploy do |app|
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX))
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX, Regexp::MULTILINE))
remote: -----> Installing dependencies using 'poetry sync --only main'
remote: Installing dependencies from lock file
remote:
Expand All @@ -180,6 +189,7 @@
remote: Running entrypoint for the setup.py-based local package: Hello from setup.py!
remote: Running entrypoint for the VCS package: gunicorn \\(version 23.0.0\\)
remote: -----> Saving cache
.+
remote: -----> Inline app detected
remote: __editable___gunicorn_23_0_0_finder.py:/app/.heroku/python/src/gunicorn/gunicorn'}
remote: __editable___local_package_pyproject_toml_0_0_1_finder.py:/tmp/build_.+/packages/local_package_pyproject_toml/local_package_pyproject_toml'}
Expand Down Expand Up @@ -208,7 +218,7 @@
# Test that the cached .pth files work correctly.
app.commit!
app.push!
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX))
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX, Regexp::MULTILINE))
remote: -----> Installing dependencies using 'poetry sync --only main'
remote: Installing dependencies from lock file
remote:
Expand All @@ -230,6 +240,7 @@
remote: Running entrypoint for the setup.py-based local package: Hello from setup.py!
remote: Running entrypoint for the VCS package: gunicorn \\(version 23.0.0\\)
remote: -----> Saving cache
.+
remote: -----> Inline app detected
remote: __editable___gunicorn_23_0_0_finder.py:/app/.heroku/python/src/gunicorn/gunicorn'}
remote: __editable___local_package_pyproject_toml_0_0_1_finder.py:/tmp/build_.+/packages/local_package_pyproject_toml/local_package_pyproject_toml'}
Expand Down