Skip to content
Open
Changes from 2 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
94 changes: 74 additions & 20 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ else
fi

info() { printf "${GREY} %s${RESET}\n" "$*"; }
warn() { printf "${GREY} Warning: %s${RESET}\n" "$*" >&2; }
success() { printf "${GREEN} ✔ %s${RESET}\n" "$*"; }
header() { printf "${BOLD} %s${RESET}\n" "$*"; }
die() { printf "\n Error: %s\n\n" "$*" >&2; exit 1; }
Expand Down Expand Up @@ -72,34 +73,86 @@ if [ -z "$PYTHON_BIN" ]; then
Ubuntu: sudo apt install python3 python3-pip"
fi

# ── pip detection ──────────────────────────────────────────────────────────
if ! "$PYTHON_BIN" -m pip --version >/dev/null 2>&1; then
die "pip is not available. Install it with:
$PYTHON_BIN -m ensurepip --upgrade"
fi

# ── install ────────────────────────────────────────────────────────────────
# Prefer pipx or venv to avoid PEP 668 "externally-managed-environment" on
# Homebrew/ system Python. Neither strategy requires system pip — pipx
# manages its own venvs and the venv strategy uses Python's built-in
# ensurepip, so there is no unconditional pip gate here.
echo ""
header "Installing litellm[proxy]…"
echo ""

"$PYTHON_BIN" -m pip install --upgrade "${LITELLM_PACKAGE}" \
|| die "pip install failed. Try manually: $PYTHON_BIN -m pip install '${LITELLM_PACKAGE}'"

# ── find the litellm binary installed by pip for this Python ───────────────
# sysconfig.get_path('scripts') is where pip puts console scripts — reliable
# even when the Python lives in a libexec/ symlink tree (e.g. Homebrew).
SCRIPTS_DIR="$("$PYTHON_BIN" -c 'import sysconfig; print(sysconfig.get_path("scripts"))')"
LITELLM_BIN="${SCRIPTS_DIR}/litellm"
LITELLM_BIN=""

# Strategy 1: pipx (best for CLI apps, per PEP 668)
# Try upgrade first to preserve existing flags (e.g. --include-deps); fall
# back to a fresh install if the package is not yet managed by pipx.
if command -v pipx >/dev/null 2>&1; then
info "Using pipx (isolated install)"
if pipx upgrade litellm 2>/dev/null; then
# Ensure proxy extras are present (may be absent if originally installed
# as bare "litellm" without [proxy]). runpip installs inside the existing
# venv without disturbing pipx metadata (preserves --include-deps, etc.).
if ! _runpip_err="$(pipx runpip litellm install -q "${LITELLM_PACKAGE}" 2>&1)"; then
warn "could not ensure proxy extras via pipx runpip (proxy features may fail until fixed)."
printf '%s\n' "$_runpip_err" >&2
fi
unset _runpip_err 2>/dev/null || true
_pipx_upgraded=1
elif pipx install "${LITELLM_PACKAGE}"; then
_pipx_upgraded=1
fi
if [ "${_pipx_upgraded:-0}" = "1" ]; then
_pipx_bin_dir="${PIPX_BIN_DIR:-${HOME}/.local/bin}"
_pipx_home="${PIPX_HOME:-${HOME}/.local/share/pipx}"
for try in \
"${_pipx_bin_dir}/litellm" \
"${_pipx_home}/venvs/litellm/bin/litellm"; do
if [ -n "$try" ] && [ -x "$try" ]; then
LITELLM_BIN="$try"
break
fi
done
if [ -z "$LITELLM_BIN" ] && command -v litellm >/dev/null 2>&1; then
LITELLM_BIN="$(command -v litellm)"
fi
if [ -z "$LITELLM_BIN" ]; then
info "pipx reported success but litellm binary not found (PIPX_BIN_DIR=${_pipx_bin_dir}, PIPX_HOME=${_pipx_home}); falling back to venv"
fi
else
info "pipx install failed, falling back to venv"
fi
fi

if [ ! -x "$LITELLM_BIN" ]; then
# Fall back to user-base bin (pip install --user)
USER_BIN="$("$PYTHON_BIN" -c 'import site; print(site.getuserbase())')/bin"
LITELLM_BIN="${USER_BIN}/litellm"
# Strategy 2: venv in ~/.litellm (avoids PEP 668 externally-managed-environment)
if [ -z "$LITELLM_BIN" ]; then
LITELLM_VENV="${LITELLM_VENV:-${HOME}/.litellm/venv}"
info "Using isolated venv: $LITELLM_VENV"
mkdir -p "$(dirname "$LITELLM_VENV")"
# Preserve an existing venv on repeat runs; use LITELLM_FORCE_VENV_RECREATE=1 to wipe it.
if [ "${LITELLM_FORCE_VENV_RECREATE:-0}" = "1" ]; then
"$PYTHON_BIN" -m venv --clear "$LITELLM_VENV" \
|| die "Failed to recreate venv. Try: $PYTHON_BIN -m venv --clear $LITELLM_VENV
On Ubuntu/Debian you may first need: sudo apt install python3-venv"
elif [ ! -d "$LITELLM_VENV" ]; then
"$PYTHON_BIN" -m venv "$LITELLM_VENV" \
|| die "Failed to create venv. Try: $PYTHON_BIN -m venv $LITELLM_VENV
On Ubuntu/Debian you may first need: sudo apt install python3-venv"
elif [ ! -x "${LITELLM_VENV}/bin/python" ]; then
info "Existing venv at ${LITELLM_VENV} is incomplete; recreating"
"$PYTHON_BIN" -m venv --clear "$LITELLM_VENV" \
|| die "Failed to recreate venv. Try: $PYTHON_BIN -m venv --clear $LITELLM_VENV
On Ubuntu/Debian you may first need: sudo apt install python3-venv"
fi
"${LITELLM_VENV}/bin/pip" install -q --upgrade pip \
|| die "Failed to upgrade pip in venv. Try: ${LITELLM_VENV}/bin/pip install --upgrade pip"
Comment on lines +151 to +152
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 venv/bin/pip may not exist before pip upgrade step

The venv creation path falls through three branches (lines 137–150): LITELLM_FORCE_VENV_RECREATE=1, fresh directory, and incomplete-venv recreation. After any of them, the script reaches:

"${LITELLM_VENV}/bin/pip" install -q --upgrade pip

Python's venv module uses ensurepip to bootstrap pip. On some minimal environments (e.g. Ubuntu/Debian without the python3-venv package and without pip pre-installed), venv can succeed but create the venv without bin/pip — only bin/python and bin/pip3 may be present, depending on the Python build. If ${LITELLM_VENV}/bin/pip does not exist, this line fails with a confusing "not found" error rather than the die message.

The already-existing guard on line 145 ([ ! -x "${LITELLM_VENV}/bin/python" ]) checks for python, not pip. Consider adding an explicit check after venv creation:

if [ ! -x "${LITELLM_VENV}/bin/pip" ] && [ ! -x "${LITELLM_VENV}/bin/pip3" ]; then
  die "pip was not bootstrapped in the venv. Try: sudo apt install python3-pip python3-venv, then re-run."
fi
VENV_PIP="${LITELLM_VENV}/bin/pip3"
[ -x "${LITELLM_VENV}/bin/pip" ] && VENV_PIP="${LITELLM_VENV}/bin/pip"
"${VENV_PIP}" install -q --upgrade pip ...

"${LITELLM_VENV}/bin/pip" install --upgrade "${LITELLM_PACKAGE}" \
|| die "pip install failed. Try manually: ${LITELLM_VENV}/bin/pip install '${LITELLM_PACKAGE}'"
LITELLM_BIN="${LITELLM_VENV}/bin/litellm"
fi

if [ ! -x "$LITELLM_BIN" ]; then
die "litellm binary not found after install. Try: $PYTHON_BIN -m pip install --user '${LITELLM_PACKAGE}'"
die "litellm binary not found. Try: pipx install '${LITELLM_PACKAGE}' or use a venv."
fi

# ── success banner ─────────────────────────────────────────────────────────
Expand All @@ -111,7 +164,8 @@ installed_ver="$("$LITELLM_BIN" --version 2>&1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]

# ── PATH hint ──────────────────────────────────────────────────────────────
if ! command -v litellm >/dev/null 2>&1; then
info "Note: add litellm to your PATH: export PATH=\"\$PATH:${SCRIPTS_DIR}\""
LITELLM_DIR="$(dirname "$LITELLM_BIN")"
info "Note: add litellm to your PATH: export PATH=\"\$PATH:${LITELLM_DIR}\""
fi

# ── launch setup wizard ────────────────────────────────────────────────────
Expand Down
Loading