Skip to content

Commit 65d5bf0

Browse files
committed
fix(common): make sure deps are going to be available at runtime
1 parent 01cb7b5 commit 65d5bf0

File tree

2 files changed

+21
-14
lines changed

2 files changed

+21
-14
lines changed

bin/compile

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,31 +89,32 @@ if [ -f "pyproject.toml" ] && [ -f "uv.lock" ]; then
8989
PYTHON_VERSION=$("$PYTHON_BIN" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
9090
# Stage dependencies into a buildpack-owned location instead of a local venv
9191
# because CF launches the app from the droplet, not from a project virtualenv.
92+
PACKAGE_HOME="$BUILD_DIR/.python_packages"
93+
PACKAGE_BIN_DIR="$PACKAGE_HOME/bin"
9294
SITE_PACKAGES_DIR="$BUILD_DIR/.python_packages/lib/python${PYTHON_VERSION}/site-packages"
9395
SRC_DIR="$BUILD_DIR/src"
9496
PROFILE_DIR="$BUILD_DIR/.profile.d"
9597
EXPORT_FILE="$BUILD_DIR/.uv-export-requirements.txt"
9698

97-
mkdir -p "$SITE_PACKAGES_DIR" "$PROFILE_DIR"
99+
mkdir -p "$SITE_PACKAGES_DIR" "$PACKAGE_BIN_DIR" "$PROFILE_DIR"
98100

99101
# Export the exact locked dependency set from uv, then install those
100-
# packages into the staged site-packages directory. Use `uv pip` instead of
101-
# `python -m pip` because uv-managed Python installations are intentionally
102-
# marked as externally managed.
102+
# packages into a staged prefix so console scripts like `uvicorn` land in a
103+
# buildpack-owned bin directory that we can add to PATH at runtime.
103104
"$UV_BIN" export --locked --format requirements-txt --no-emit-local -o "$EXPORT_FILE"
104-
"$UV_BIN" pip install --python "$PYTHON_BIN" --no-deps --target "$SITE_PACKAGES_DIR" -r "$EXPORT_FILE"
105+
"$UV_BIN" pip install --python "$PYTHON_BIN" --no-deps --prefix "$PACKAGE_HOME" -r "$EXPORT_FILE"
105106

106107
# Add the staged packages to PYTHONPATH so the app can import them at runtime.
107108
# If the project uses a `src/` layout, include that too because the local
108109
# project itself is not installed by the exported third-party requirements.
109110
if [ -d "$SRC_DIR" ]; then
110111
cat > "$PROFILE_DIR/python.sh" <<EOF
111-
export PATH="$PYTHON_SHIM_DIR:\${PATH}"
112+
export PATH="$PYTHON_SHIM_DIR:$PACKAGE_BIN_DIR:\${PATH}"
112113
export PYTHONPATH="$SRC_DIR:$SITE_PACKAGES_DIR:\${PYTHONPATH}"
113114
EOF
114115
else
115116
cat > "$PROFILE_DIR/python.sh" <<EOF
116-
export PATH="$PYTHON_SHIM_DIR:\${PATH}"
117+
export PATH="$PYTHON_SHIM_DIR:$PACKAGE_BIN_DIR:\${PATH}"
117118
export PYTHONPATH="$SITE_PACKAGES_DIR:\${PYTHONPATH}"
118119
EOF
119120
fi

test/unit/compile_test.sh

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,14 @@ REQ
121121
fi
122122
123123
if [ "$1" = "pip" ] && [ "$2" = "install" ]; then
124-
target_dir=""
124+
prefix_dir=""
125125
requirements_file=""
126126
127127
while [ "$#" -gt 0 ]; do
128128
case "$1" in
129-
--target)
129+
--prefix)
130130
shift
131-
target_dir="$1"
131+
prefix_dir="$1"
132132
;;
133133
-r)
134134
shift
@@ -138,9 +138,11 @@ if [ "$1" = "pip" ] && [ "$2" = "install" ]; then
138138
shift || true
139139
done
140140
141-
if [ -n "$target_dir" ]; then
142-
mkdir -p "$target_dir"
143-
touch "$target_dir/fake-installed-package.txt"
141+
if [ -n "$prefix_dir" ]; then
142+
mkdir -p "$prefix_dir/bin"
143+
touch "$prefix_dir/bin/uvicorn"
144+
mkdir -p "$prefix_dir/lib/python3.13/site-packages"
145+
touch "$prefix_dir/lib/python3.13/site-packages/fake-installed-package.txt"
144146
fi
145147
146148
if [ -n "$requirements_file" ]; then
@@ -189,6 +191,8 @@ test_compile_succeeds_for_locked_uv_project() {
189191
local build_dir="$TEST_ROOT/success/build"
190192
local cache_dir="$TEST_ROOT/success/cache"
191193
local env_dir="$TEST_ROOT/success/env"
194+
local package_home="$build_dir/.python_packages"
195+
local package_bin_dir="$package_home/bin"
192196
local site_packages_dir="$build_dir/.python_packages/lib/python3.13/site-packages"
193197
local profile_file="$build_dir/.profile.d/python.sh"
194198
local export_file="$build_dir/.uv-export-requirements.txt"
@@ -207,16 +211,18 @@ test_compile_succeeds_for_locked_uv_project() {
207211
assert_contains "$output" "Detected uv project with lockfile. Installing dependencies with uv." "compile should announce supported uv projects"
208212
assert_contains "$output" "Installing Python 3.13 from .python-version." "compile should install the requested Python version"
209213
assert_path_exists "$site_packages_dir" "compile should create the staged site-packages directory"
214+
assert_path_exists "$package_bin_dir/uvicorn" "compile should stage console scripts into the package bin directory"
210215
assert_path_exists "$profile_file" "compile should write a profile script for runtime imports"
211216
assert_path_exists "$export_file" "compile should write the exported requirements file"
212217
assert_path_exists "$shim_dir/python3" "compile should create a python3 shim for runtime commands"
213218
assert_path_exists "$shim_dir/python" "compile should create a python shim for runtime commands"
214219
assert_file_contains "$profile_file" "$site_packages_dir" "profile script should add staged dependencies to PYTHONPATH"
215220
assert_file_contains "$profile_file" "$shim_dir" "profile script should add the managed Python shims to PATH"
221+
assert_file_contains "$profile_file" "$package_bin_dir" "profile script should add staged console scripts to PATH"
216222
assert_file_contains "$TEST_ROOT/uv.log" "python install 3.13" "compile should install the Python version pinned by .python-version"
217223
assert_file_contains "$TEST_ROOT/uv.log" "python find --managed-python 3.13" "compile should resolve the managed interpreter path after installation"
218224
assert_file_contains "$TEST_ROOT/uv.log" "export --locked --format requirements-txt --no-emit-local -o $export_file" "compile should export locked third-party dependencies"
219-
assert_file_contains "$TEST_ROOT/uv.log" "pip install --python $FAKE_MANAGED_PYTHON --no-deps --target $site_packages_dir -r $export_file" "compile should install exported dependencies into the staged site-packages directory via uv pip"
225+
assert_file_contains "$TEST_ROOT/uv.log" "pip install --python $FAKE_MANAGED_PYTHON --no-deps --prefix $package_home -r $export_file" "compile should install exported dependencies into the staged prefix via uv pip"
220226
}
221227

222228
test_compile_adds_src_directory_to_pythonpath_when_present() {

0 commit comments

Comments
 (0)