Skip to content

Commit 70c3238

Browse files
committed
Update pip from 25.2 to 25.3
Changelog: https://pip.pypa.io/en/stable/news/#v25-3 Additionally, we now no longer install the `wheel` package when using pip with Python 3.12 and older, since: - With modern setuptools, it's no longer necessary to manually install wheel, since setuptools will trigger its installation if needed. - As of pip 25.3, pip prepares/builds dependencies inside an isolated ephemeral build environment (~venv) that means even if wheel is installed globally, it won't be used anyway. - The Python CNB (and much of the rest of the Python ecosystem) doesn't install wheel globally any more either. This doesn't affect apps using either a different package manager, or that are using pip with Python 3.13 or newer, since we already didn't install the wheel package in those environments. GUS-W-17605676. GUS-W-20804745.
1 parent 76f07d9 commit 70c3238

File tree

11 files changed

+37
-54
lines changed

11 files changed

+37
-54
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## [Unreleased]
44

5+
- Updated pip from 25.2 to 25.3. ([#2008](https://github.com/heroku/heroku-buildpack-python/pull/2008))
6+
- Stopped installing wheel when using pip with Python 3.12 and older. ([#2008](https://github.com/heroku/heroku-buildpack-python/pull/2008))
57

68
## [v327] - 2026-01-07
79

lib/pip.sh

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ set -euo pipefail
66

77
PIP_VERSION=$(utils::get_requirement_version 'pip')
88
SETUPTOOLS_VERSION=$(utils::get_requirement_version 'setuptools')
9-
WHEEL_VERSION=$(utils::get_requirement_version 'wheel')
109

1110
function pip::install_pip() {
1211
local python_home="${1}"
@@ -21,21 +20,17 @@ function pip::install_pip() {
2120
)
2221
local packages_display_text="pip ${PIP_VERSION}"
2322

24-
# We only install setuptools and wheel on Python 3.12 and older, since:
25-
# - If either is not installed, pip will automatically install them into an isolated build
26-
# environment if needed when installing packages from an sdist. This means that for
27-
# all packages that correctly declare their metadata, it's no longer necessary to have
28-
# them installed.
23+
# We only install setuptools on Python 3.12 and older, since:
24+
# - pip now uses isolated build environments into which it installed setuptools and wheel
25+
# if needed when installing packages from an sdist.
2926
# - Most of the Python ecosystem has stopped installing them for Python 3.12+ already.
3027
# See the Python CNB's removal for more details: https://github.com/heroku/buildpacks-python/pull/243
3128
if [[ "${python_major_version}" == +(3.10|3.11|3.12) ]]; then
3229
build_data::set_string "setuptools_version" "${SETUPTOOLS_VERSION}"
33-
build_data::set_string "wheel_version" "${WHEEL_VERSION}"
3430
packages_to_install+=(
3531
"setuptools==${SETUPTOOLS_VERSION}"
36-
"wheel==${WHEEL_VERSION}"
3732
)
38-
packages_display_text+=", setuptools ${SETUPTOOLS_VERSION} and wheel ${WHEEL_VERSION}"
33+
packages_display_text+=" and setuptools ${SETUPTOOLS_VERSION}"
3934
fi
4035

4136
# Note: We still perform this install step even if the cache was reused, since we have no guarantee

requirements/pip.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
pip==25.2
1+
pip==25.3

requirements/wheel.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
# Note: This test intentionally uses Python 3.12, so that we test *.egg-link
2-
# path rewriting using older globally installed setuptools.
3-
3.12
1+
3.14

spec/fixtures/pip_editable/bin/test-entrypoints.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ set -euo pipefail
44

55
cd .heroku/python/lib/python*/site-packages/
66

7-
# List any path like strings in the .egg-link, .pth, and finder files in site-packages.
8-
grep --extended-regexp --only-matching -- '/\S+' *.egg-link *.pth __editable___*_finder.py | sort
7+
# List any path like strings in the .pth and finder files in site-packages.
8+
grep --extended-regexp --only-matching -- '/\S+' *.pth __editable___*_finder.py | sort
99
echo
1010

1111
echo -n "Running entrypoint for the pyproject.toml-based local package: "

spec/fixtures/pip_editable/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# https://github.com/pypa/setuptools/issues/3535
33
-e ./packages/local_package_pyproject_toml
44
-e ./packages/local_package_setup_py
5-
-e git+https://github.com/benoitc/gunicorn@20.1.0#egg=gunicorn
5+
-e git+https://github.com/benoitc/gunicorn@56b5ad87f8d72a674145c273ed8f547513c2b409#egg=gunicorn

spec/hatchet/pip_spec.rb

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -163,82 +163,72 @@
163163
end
164164
end
165165

166-
# This test intentionally uses Python 3.12, so that we test rewriting using older globally installed
167-
# setuptools (which causes .egg-link files to be created too). The Pipenv and Poetry equivalents of
168-
# this test covers the PEP-517/518 setuptools case.
169166
context 'when requirements.txt contains editable requirements (both VCS and local package)' do
170167
let(:buildpacks) { [:default, 'heroku-community/inline'] }
171168
let(:app) { Hatchet::Runner.new('spec/fixtures/pip_editable', buildpacks:) }
172169

173-
it 'rewrites .pth, .egg-link and finder paths correctly for hooks, later buildpacks, runtime and cached builds' do
170+
it 'rewrites .pth and finder paths correctly for hooks, later buildpacks, runtime and cached builds' do
174171
app.deploy do |app|
175172
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX, Regexp::MULTILINE))
176173
remote: -----> Running bin/post_compile hook
177-
remote: easy-install.pth:/app/.heroku/python/src/gunicorn
178-
remote: easy-install.pth:/tmp/build_.+/packages/local_package_setup_py
174+
remote: __editable___gunicorn_23_0_0_finder.py:/app/.heroku/python/src/gunicorn/gunicorn'}
179175
remote: __editable___local_package_pyproject_toml_0_0_1_finder.py:/tmp/build_.+/packages/local_package_pyproject_toml/local_package_pyproject_toml'}
180-
remote: gunicorn.egg-link:/app/.heroku/python/src/gunicorn
181-
remote: local-package-setup-py.egg-link:/tmp/build_.+/packages/local_package_setup_py
176+
remote: __editable___local_package_setup_py_0_0_1_finder.py:/tmp/build_.+/packages/local_package_setup_py/local_package_setup_py'}
182177
remote:
183178
remote: Running entrypoint for the pyproject.toml-based local package: Hello from pyproject.toml!
184179
remote: Running entrypoint for the setup.py-based local package: Hello from setup.py!
185-
remote: Running entrypoint for the VCS package: gunicorn \\(version 20.1.0\\)
180+
remote: Running entrypoint for the VCS package: gunicorn \\(version 23.0.0\\)
186181
remote: -----> Saving cache
187182
.+
188183
remote: -----> Inline app detected
189-
remote: easy-install.pth:/app/.heroku/python/src/gunicorn
190-
remote: easy-install.pth:/tmp/build_.+/packages/local_package_setup_py
184+
remote: __editable___gunicorn_23_0_0_finder.py:/app/.heroku/python/src/gunicorn/gunicorn'}
191185
remote: __editable___local_package_pyproject_toml_0_0_1_finder.py:/tmp/build_.+/packages/local_package_pyproject_toml/local_package_pyproject_toml'}
192-
remote: gunicorn.egg-link:/app/.heroku/python/src/gunicorn
193-
remote: local-package-setup-py.egg-link:/tmp/build_.+/packages/local_package_setup_py
186+
remote: __editable___local_package_setup_py_0_0_1_finder.py:/tmp/build_.+/packages/local_package_setup_py/local_package_setup_py'}
194187
remote:
195188
remote: Running entrypoint for the pyproject.toml-based local package: Hello from pyproject.toml!
196189
remote: Running entrypoint for the setup.py-based local package: Hello from setup.py!
197-
remote: Running entrypoint for the VCS package: gunicorn \\(version 20.1.0\\)
190+
remote: Running entrypoint for the VCS package: gunicorn \\(version 23.0.0\\)
198191
REGEX
199192

200193
# Test rewritten paths work at runtime.
201194
expect(app.run('bin/test-entrypoints.sh')).to include(<<~OUTPUT)
202-
easy-install.pth:/app/.heroku/python/src/gunicorn
203-
easy-install.pth:/app/packages/local_package_setup_py
195+
__editable___gunicorn_23_0_0_finder.py:/app/.heroku/python/src/gunicorn/gunicorn'}
204196
__editable___local_package_pyproject_toml_0_0_1_finder.py:/app/packages/local_package_pyproject_toml/local_package_pyproject_toml'}
205-
gunicorn.egg-link:/app/.heroku/python/src/gunicorn
206-
local-package-setup-py.egg-link:/app/packages/local_package_setup_py
197+
__editable___local_package_setup_py_0_0_1_finder.py:/app/packages/local_package_setup_py/local_package_setup_py'}
207198
208199
Running entrypoint for the pyproject.toml-based local package: Hello from pyproject.toml!
209200
Running entrypoint for the setup.py-based local package: Hello from setup.py!
210-
Running entrypoint for the VCS package: gunicorn (version 20.1.0)
201+
Running entrypoint for the VCS package: gunicorn (version 23.0.0)
211202
OUTPUT
212203

213204
# Test that the cached .pth files work correctly.
214205
app.commit!
215206
app.push!
216207
expect(clean_output(app.output)).to match(Regexp.new(<<~REGEX, Regexp::MULTILINE))
217208
remote: -----> Running bin/post_compile hook
218-
remote: easy-install.pth:/app/.heroku/python/src/gunicorn
219-
remote: easy-install.pth:/tmp/build_.+/packages/local_package_setup_py
209+
remote: __editable___gunicorn_23_0_0_finder.py:/app/.heroku/python/src/gunicorn/gunicorn'}
220210
remote: __editable___local_package_pyproject_toml_0_0_1_finder.py:/tmp/build_.+/packages/local_package_pyproject_toml/local_package_pyproject_toml'}
221-
remote: gunicorn.egg-link:/app/.heroku/python/src/gunicorn
222-
remote: local-package-setup-py.egg-link:/tmp/build_.+/packages/local_package_setup_py
211+
remote: __editable___local_package_setup_py_0_0_1_finder.py:/tmp/build_.+/packages/local_package_setup_py/local_package_setup_py'}
223212
remote:
224213
remote: Running entrypoint for the pyproject.toml-based local package: Hello from pyproject.toml!
225214
remote: Running entrypoint for the setup.py-based local package: Hello from setup.py!
226-
remote: Running entrypoint for the VCS package: gunicorn \\(version 20.1.0\\)
215+
remote: Running entrypoint for the VCS package: gunicorn \\(version 23.0.0\\)
227216
remote: -----> Saving cache
228217
.+
229218
remote: -----> Inline app detected
230-
remote: easy-install.pth:/app/.heroku/python/src/gunicorn
231-
remote: easy-install.pth:/tmp/build_.+/packages/local_package_setup_py
219+
remote: __editable___gunicorn_23_0_0_finder.py:/app/.heroku/python/src/gunicorn/gunicorn'}
232220
remote: __editable___local_package_pyproject_toml_0_0_1_finder.py:/tmp/build_.+/packages/local_package_pyproject_toml/local_package_pyproject_toml'}
233-
remote: gunicorn.egg-link:/app/.heroku/python/src/gunicorn
234-
remote: local-package-setup-py.egg-link:/tmp/build_.+/packages/local_package_setup_py
221+
remote: __editable___local_package_setup_py_0_0_1_finder.py:/tmp/build_.+/packages/local_package_setup_py/local_package_setup_py'}
235222
remote:
236223
remote: Running entrypoint for the pyproject.toml-based local package: Hello from pyproject.toml!
237224
remote: Running entrypoint for the setup.py-based local package: Hello from setup.py!
238-
remote: Running entrypoint for the VCS package: gunicorn \\(version 20.1.0\\)
225+
remote: Running entrypoint for the VCS package: gunicorn \\(version 23.0.0\\)
239226
REGEX
240227
# Test that the VCS repo checkout was cached correctly.
241-
expect(app.output).to include('Updating /app/.heroku/python/src/gunicorn clone (to revision 20.1.0)')
228+
expect(app.output).to include(<<~OUTPUT)
229+
remote: Obtaining gunicorn from git+https://github.com/benoitc/gunicorn@56b5ad87f8d72a674145c273ed8f547513c2b409#egg=gunicorn (from -r requirements.txt (line 5))
230+
remote: Skipping because already up-to-date.
231+
OUTPUT
242232
end
243233
end
244234
end
@@ -318,7 +308,7 @@
318308
remote: ! patch version automatically and prevent this warning.
319309
remote:
320310
remote: -----> Installing Python 3.10.0
321-
remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION}
311+
remote: -----> Installing pip #{PIP_VERSION} and setuptools #{SETUPTOOLS_VERSION}
322312
remote: -----> Installing dependencies using 'pip install -r requirements.txt'
323313
remote: Collecting typing-extensions==4.15.0 (from -r requirements.txt (line 2))
324314
remote: Downloading typing_extensions-4.15.0-py3-none-any.whl.metadata (3.3 kB)
@@ -378,7 +368,7 @@
378368
it 'outputs instructions for how to resolve the build failure' do
379369
app.deploy do |app|
380370
expect(clean_output(app.output)).to include(<<~OUTPUT)
381-
remote: note: This error originates from a subprocess, and is likely not a problem with pip.
371+
remote: ERROR: Failed to build 'GDAL' when getting requirements to build wheel
382372
remote:
383373
remote: ! Error: Package installation failed since the GDAL library wasn't found.
384374
remote: !

spec/hatchet/python_version_spec.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
remote: -----> Python app detected
1111
remote: -----> Using Python #{requested_version} specified in .python-version
1212
remote: -----> Installing Python #{resolved_version}
13-
remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION}
13+
remote: -----> Installing pip #{PIP_VERSION} and setuptools #{SETUPTOOLS_VERSION}
1414
remote: -----> Installing dependencies using 'pip install -r requirements.txt'
1515
remote: Collecting typing-extensions==4.15.0 (from -r requirements.txt (line 2))
1616
OUTPUT
@@ -152,7 +152,7 @@
152152
remote: - The pip version has changed from 24.0 to #{PIP_VERSION}
153153
remote: - The legacy SQLite3 headers and CLI binary need to be uninstalled
154154
remote: -----> Installing Python #{LATEST_PYTHON_3_12}
155-
remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION}
155+
remote: -----> Installing pip #{PIP_VERSION} and setuptools #{SETUPTOOLS_VERSION}
156156
OUTPUT
157157
expect(app.run('python -V')).to eq("Python #{LATEST_PYTHON_3_12}\n")
158158
expect($CHILD_STATUS.exitstatus).to eq(0)
@@ -274,7 +274,7 @@
274274
remote: ! https://devcenter.heroku.com/articles/python-support#supported-python-versions
275275
remote:
276276
remote: -----> Installing Python #{LATEST_PYTHON_3_10}
277-
remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION}
277+
remote: -----> Installing pip #{PIP_VERSION} and setuptools #{SETUPTOOLS_VERSION}
278278
remote: -----> Installing dependencies using 'pip install -r requirements.txt'
279279
remote: Collecting typing-extensions==4.15.0 (from -r requirements.txt (line 2))
280280
OUTPUT

spec/hatchet/stack_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
remote: - The buildpack cache format has changed
7070
remote: - The legacy SQLite3 headers and CLI binary need to be uninstalled
7171
remote: -----> Installing Python #{LATEST_PYTHON_3_12}
72-
remote: -----> Installing pip #{PIP_VERSION}, setuptools #{SETUPTOOLS_VERSION} and wheel #{WHEEL_VERSION}
72+
remote: -----> Installing pip #{PIP_VERSION} and setuptools #{SETUPTOOLS_VERSION}
7373
remote: -----> Installing dependencies using 'pip install -r requirements.txt'
7474
remote: Collecting typing-extensions==4.15.0 (from -r requirements.txt (line 2))
7575
OUTPUT

0 commit comments

Comments
 (0)