-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Entrypoint script shebang uses resolved path for symlinked Python rather than sys.executable
#11048
Comments
Thanks for all the details! I'll dig into this tomorrow. |
Briefly...
When you use
Given your above statement (thank you so much for sharing that information!) I believe this would cause the behavior you're seeing. It's relatively unambiguous that we use uv/crates/uv-install-wheel/src/wheel.rs Line 203 in ad075c3
|
And it looks like canonicalization happens at uv/crates/uv-python/src/environment.rs Line 164 in bec8468
|
Interesting. I fixed the canonicalization there, but... we still get the same value for edit: Oh interesting, it's different in CI than locally! #11083 (comment) |
) Closes #11048 This brings the `PythonEnvironment::from_root` behavior in-line with the rest of uv Python discovery behavior (and in-line with pip). It's not clear why we were canonicalizing the path in the first place here.
I can confirm this is resolved with #11083 - my tests now pass - thank you! |
Thanks for following up Ed! |
Summary
The shebang lines of entrypoint scripts created by
uv sync
when usingUV_PROJECT_ENVIRONMENT
with a symlinked Python installation use the resolved Python binary path rather than thesys.executable
path, which differs from pip anduv pip
's behaviour and causes some issues with the older of our two build systems.Steps
Dockerfile
based on the below.docker build . --progress plain --no-cache
(We don't actually use Docker to build on our older build system - the below is for MRE purposes only)
Expected
which ...
commands, plussys.path
andsys.executable
to all report paths under/app/...
(rather than/tmp/...
).#!/app/.heroku/python/bin/python
gunicorn --version
command to succeed.Actual
which ...
commands, plussys.path
andsys.executable
all report paths under/app/...
.head -n1 $(which gunicorn)
command shows the gunicorn entrypoint as having a shebang of#!/tmp/build/.heroku/python/bin/python3
gunicorn --version
command fails due to the shebang referencing the wrong path (/tmp/...
, which no longer exists).See:
Docker build output
Other findings
For comparison, if I use
uv pip install --system
instead, then I get the shebang I expect. e.g: Try replacing the threeuv sync
related lines above with:Similarly, if that's then replaced with
pip install
, the shebang is also as expected:Interestingly,
uv venv
does use/app
paths for thepyvenv.cfg
metadata and the symlink target:So I'm presuming this might be specific to when
UV_PROJECT_ENVIRONMENT
is used?I also tried setting
UV_PYTHON
explicitly (both to/app/.heroku/python
and/app/.heroku/python/bin/python
), but that didn't affect the shebang.Related issues
These look vaguely related?
Context
Heroku has two platform generations, each with its own build system and buildpack implementations.
In the older generation (Cedar, which uses classic buildpacks), the app source is located at a location like
/tmp/build_<hash>
during the build, then at app run-time the app archive is mounted at/app
. [1]As you can imagine for Python this relocation can cause some issues, however, we're able to work around these pretty easily in practice, by:
/app/.heroku/python
(which is what will be the actual location at app run-time) to/tmp/build_<hash>/.heroku/python
(the location of Python install during the build)/app/.heroku/python/bin
toPATH
instead of the/tmp
location.pth
files created for editable local directory installsThis works because:
/app/.heroku/python/bin/python
given that's what's onPATH
), and thussys.prefix
/sys.executable
use/app/...
pathssys.executable
when calculating the shebangs for entrypoint scripts, eg:sys.executable
heresys.executable
via here and here...and thus entrypoint scripts will end up with a shebang like:
#!/app/.heroku/python/bin/python
...which will also work at app run-time, when the app is actually mounted at
/app
.[1] The original need to use a different directory has long since passed, however, it's not possible for us to change the build location without breaking many third-party classic buildpacks, so we're sadly stuck with this relocation for the classic build system. Thankfully the Cloud Native Buildpack spec has the build time and run time paths the same, so our newer build system doesn't have to work around this issue.
[2] The reason for the symlink and not copying the app source back and forth from /tmp <-> /app at the start/end of the Python build step is due to a combination of compatibility concerns with other language buildpacks (that can run before/after the Python buildpack and can also use our Python install), plus build end to end time impact from the additional I/O.
Platform
Ubuntu (but not using distro Python)
Version
0.5.25
Python version
Python 3.13.1
The text was updated successfully, but these errors were encountered: