1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
"""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 typing import Optional, Tuple
from backends import 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
|