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
6 changes: 5 additions & 1 deletion bin/release
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#!/usr/bin/env bash
# Release script for Python buildpack with uv support

if command -v python3 >/dev/null 2>&1; then
if [ -x ".python/bin/python3" ]; then
PYTHON_BIN=".python/bin/python3"
elif [ -x ".python/bin/python" ]; then
PYTHON_BIN=".python/bin/python"
elif command -v python3 >/dev/null 2>&1; then
PYTHON_BIN="python3"
elif command -v python >/dev/null 2>&1; then
PYTHON_BIN="python"
Expand Down
1 change: 1 addition & 0 deletions example/my-app/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.13
Empty file added example/my-app/README.md
Empty file.
9 changes: 9 additions & 0 deletions example/my-app/manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
applications:
- name: my-app
memory: 256M
disk_quota: 512M
instances: 1
buildpacks:
- https://github.com/NickChecan/uv-python-buildpack
random-route: true
17 changes: 17 additions & 0 deletions example/my-app/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[project]
name = "my-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"fastapi>=0.135.3",
"uvicorn[standard]>=0.44.0",
]

[project.scripts]
start = "my_app.main:start"

[build-system]
requires = ["uv_build>=0.11.5,<0.12.0"]
build-backend = "uv_build"
Empty file.
12 changes: 12 additions & 0 deletions example/my-app/src/my_app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from fastapi import FastAPI
import uvicorn

app = FastAPI()


@app.get("/")
def hello_world():
return {"message": "Hello, World!"}

def start() -> None:
uvicorn.run("my_app.main:app", host="0.0.0.0", port=8000, reload=True)
414 changes: 414 additions & 0 deletions example/my-app/uv.lock

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions test/unit/release_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,33 @@ EOF
assert_contains "$output" 'web: python3 -c "from server.main import start; start()"' "release should fall back to the start script"
}

test_release_prefers_buildpack_managed_python_when_present() {
# Arrange
local app_dir="$TEST_ROOT/managed-python-app"
mkdir -p "$app_dir/.python/bin"
setup_fake_python_commands
cat > "$app_dir/pyproject.toml" <<'EOF'
[project]
name = "my-app"

[project.scripts]
start = "server.main:start"
EOF
cat > "$app_dir/.python/bin/python3" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
exec "$REAL_PYTHON3" "$@"
EOF
chmod +x "$app_dir/.python/bin/python3"

# Act
run_release "$app_dir"

# Assert
assert_exit_code "$status" 0 "release should succeed when the buildpack-managed python is present"
assert_contains "$output" 'web: .python/bin/python3 -c "from server.main import start; start()"' "release should prefer the buildpack-managed python shim"
}

test_release_falls_back_to_main_py() {
# Arrange
local app_dir="$TEST_ROOT/main-py-app"
Expand Down Expand Up @@ -194,6 +221,7 @@ test_release_leaves_web_process_empty_when_no_entrypoint_exists() {
test_release_exits_when_procfile_exists
test_release_prefers_project_name_script_over_start
test_release_falls_back_to_start_script
test_release_prefers_buildpack_managed_python_when_present
test_release_falls_back_to_main_py
test_release_falls_back_to_app_py
test_release_leaves_web_process_empty_when_no_entrypoint_exists
Expand Down
Loading