aboutsummaryrefslogtreecommitdiff
path: root/app/backends/sglomni/pythonenv.py
diff options
context:
space:
mode:
Diffstat (limited to 'app/backends/sglomni/pythonenv.py')
-rw-r--r--app/backends/sglomni/pythonenv.py96
1 files changed, 96 insertions, 0 deletions
diff --git a/app/backends/sglomni/pythonenv.py b/app/backends/sglomni/pythonenv.py
new file mode 100644
index 0000000..11bbaa6
--- /dev/null
+++ b/app/backends/sglomni/pythonenv.py
@@ -0,0 +1,96 @@
+"""The sglang-omni venv: interpreter selection and provisioning.
+
+sglang-omni requires Python >=3.10,<3.13 while the app itself is
+version-agnostic — a host whose only ``python`` is 3.13+ must still be
+able to install and run this backend. ``prepare_env`` resolves a usable
+interpreter for the dedicated venv (``app/envs/sglomni``), in order:
+
+1. the venv already exists with an acceptable interpreter (no-op);
+2. the app env's interpreter or a ``python3.10/3.11/3.12`` on PATH fits
+ (the venv is created from it — no download);
+3. uv (pip-installed into the app env) provisions a managed standalone
+ CPython 3.12 into ``app/envs/pythons`` and creates the venv from it —
+ the zero-prerequisites path for hosts like stock Arch, where only the
+ latest Python exists and no root/package-manager knowledge is needed.
+
+An existing venv built with an incompatible interpreter (an older tool
+version, a since-upgraded system Python) is transparently recreated: a
+venv holds nothing user-owned, and every package in it is reinstalled by
+the setup that follows anyway.
+"""
+
+import shutil
+import sys
+from pathlib import Path
+from typing import Optional, Tuple
+
+from backends import common, envs
+from backends.sglomni.constants import PYTHON_SPEC, PYTHON_VERSIONS
+
+# The dedicated venv (its interpreter may differ from the launching one).
+SGLOMNI_ENV = envs.SGLOMNI_ENV_DIR
+
+
+def env_version() -> Optional[Tuple[int, int]]:
+ """The (major, minor) Python version of the venv's interpreter."""
+ if not envs.env_exists(SGLOMNI_ENV):
+ return None
+ return envs.python_version(envs.env_python(SGLOMNI_ENV))
+
+
+def env_compatible() -> bool:
+ """True when the venv exists with a Python the sglang-omni stack accepts."""
+ version = env_version()
+ return version is not None and tuple(version) in {tuple(v) for v in PYTHON_VERSIONS}
+
+
+def prepare_env(*, emit=None, cancel=None) -> int:
+ """Make SGLOMNI_ENV exist with a Python in PYTHON_VERSIONS. Returns 0/1.
+
+ The three resolution paths are described in the module docstring; every
+ path ends with a pip-equipped venv so the regular ``python -m pip``
+ helpers (requirements installs, model-companion extras) keep working.
+ Prints what it does so the task view shows why a download happens (or,
+ usually, does not).
+ """
+ if env_compatible():
+ return 0
+ if envs.env_exists(SGLOMNI_ENV):
+ version = env_version()
+ found = f"{version[0]}.{version[1]}" if version else "unknown"
+ print(f"[WARNING] {SGLOMNI_ENV} was built with Python {found}, "
+ "which the sglang-omni stack does not support (needs "
+ "3.10-3.12); recreating it with a compatible interpreter.")
+ # Nothing user-owned lives in the tool-managed venv, and every
+ # package is reinstalled by the steps that follow this one.
+ shutil.rmtree(SGLOMNI_ENV, ignore_errors=True)
+ if SGLOMNI_ENV.exists():
+ print("[ERROR] Could not remove the incompatible venv; "
+ f"delete {SGLOMNI_ENV} manually and re-run setup.")
+ return 1
+
+ interpreter = envs.compatible_interpreter(PYTHON_VERSIONS)
+ if interpreter is not None:
+ if interpreter == envs.env_python(envs.ENV_DIR):
+ print(f"[INFO] using the app environment's interpreter "
+ f"({sys.version_info.major}.{sys.version_info.minor}) "
+ "for the sglang-omni venv.")
+ else:
+ print(f"[INFO] using {interpreter} for the sglang-omni venv.")
+ return envs.create_env(SGLOMNI_ENV, interpreter)
+
+ # No compatible interpreter anywhere: provision one with uv.
+ print("[INFO] no Python 3.10-3.12 found on this system — provisioning "
+ f"a managed CPython {PYTHON_SPEC} with uv (no root required).")
+ rc = envs.ensure_uv(emit=emit, cancel=cancel)
+ if rc != 0:
+ print("[WARNING] pip install uv failed (exit "
+ f"{rc}); install uv manually and re-run setup")
+ return rc
+ rc = envs.provision_env_with_uv(SGLOMNI_ENV, PYTHON_SPEC,
+ emit=emit, cancel=cancel)
+ if rc != 0:
+ print(f"[WARNING] uv venv failed (exit {rc}); create the venv "
+ f"manually, e.g.: uv venv --seed --python {PYTHON_SPEC} "
+ f"{SGLOMNI_ENV}")
+ return rc