nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at python-updates 229 lines 5.6 kB view raw
1{ 2 lib, 3 stdenv, 4 fetchFromGitHub, 5 python3Packages, 6 replaceVars, 7 macmon, 8 9 # pyo3-bindings 10 rustPlatform, 11 12 # dashboard 13 buildNpmPackage, 14 fetchNpmDeps, 15 16 writableTmpDirAsHomeHook, 17 18 nix-update-script, 19}: 20let 21 version = "1.0.67"; 22 src = fetchFromGitHub { 23 name = "exo"; 24 owner = "exo-explore"; 25 repo = "exo"; 26 tag = "v${version}"; 27 hash = "sha256-hipCiAqCkkyrVcQXEZKbGoVbgjM3hykUcazNPEbT+q8="; 28 }; 29 30 pyo3-bindings = python3Packages.buildPythonPackage (finalAttrs: { 31 pname = "exo-pyo3-bindings"; 32 inherit version src; 33 pyproject = true; 34 35 buildAndTestSubdir = "rust/exo_pyo3_bindings"; 36 37 cargoDeps = rustPlatform.fetchCargoVendor { 38 inherit (finalAttrs) pname src version; 39 hash = "sha256-N7B1WFqPdqeNPZe9hXGyX7F3EbB1spzeKc19BFDDwls="; 40 }; 41 42 # Bypass rust nightly features not being available on rust stable 43 env.RUSTC_BOOTSTRAP = 1; 44 45 nativeBuildInputs = [ 46 rustPlatform.cargoSetupHook 47 rustPlatform.maturinBuildHook 48 ]; 49 50 nativeCheckInputs = with python3Packages; [ 51 pytest-asyncio 52 pytestCheckHook 53 ]; 54 55 enabledTestPaths = [ 56 "rust/exo_pyo3_bindings/tests/" 57 ]; 58 59 # RuntimeError 60 # Attempted to create a NULL object 61 doCheck = !stdenv.hostPlatform.isDarwin; 62 }); 63 64 dashboard = buildNpmPackage (finalAttrs: { 65 pname = "exo-dashboard"; 66 inherit src version; 67 68 sourceRoot = "${finalAttrs.src.name}/dashboard"; 69 70 npmDeps = fetchNpmDeps { 71 inherit (finalAttrs) 72 pname 73 version 74 src 75 sourceRoot 76 ; 77 fetcherVersion = 2; 78 hash = "sha256-3ZgE1ysb1OeB4BNszvlrnYcc7gOo7coPfOEQmMHC6E0="; 79 }; 80 }); 81 82 # exo requires building mlx-lm from its main branch to use the kimi-k2.5 model 83 mlx-lm-unstable = python3Packages.mlx-lm.overridePythonAttrs (old: { 84 version = "0.30.4-unstable-2026-01-27"; 85 src = old.src.override { 86 rev = "96699e6dadb13b82b28285bb131a0741997d19ae"; 87 tag = null; 88 hash = "sha256-L1ws8XA8VhR18pRuRGbVal/yEfJaFNW8QzS16C1dFpE="; 89 }; 90 meta = old.meta // { 91 changelog = "https://github.com/ml-explore/mlx-lm/releases/tag/v0.30.5"; 92 }; 93 }); 94in 95python3Packages.buildPythonApplication (finalAttrs: { 96 pname = "exo"; 97 pyproject = true; 98 99 inherit version src; 100 101 patches = [ 102 (replaceVars ./inject-dashboard-path.patch { 103 dashboard = "${dashboard}/lib/node_modules/${dashboard.pname}/build"; 104 }) 105 ]; 106 107 postPatch = '' 108 substituteInPlace pyproject.toml \ 109 --replace-fail "uv_build>=0.8.9,<0.9.0" "uv_build" 110 '' 111 # MemoryObjectStreamState was renamed in 112 # https://github.com/agronholm/anyio/pull/1009/changes/bdc945a826d0d5917aea3517ceb9fe335b468094 113 + '' 114 substituteInPlace src/exo/utils/channels.py \ 115 --replace-fail \ 116 "MemoryObjectStreamState as AnyioState," \ 117 "_MemoryObjectStreamState as AnyioState," 118 '' 119 + lib.optionalString stdenv.hostPlatform.isDarwin '' 120 substituteInPlace src/exo/utils/info_gatherer/info_gatherer.py \ 121 --replace-fail \ 122 'shutil.which("macmon")' \ 123 '"${lib.getExe macmon}"' 124 ''; 125 126 build-system = with python3Packages; [ 127 uv-build 128 ]; 129 130 pythonRelaxDeps = true; 131 132 pythonRemoveDeps = [ 133 "types-aiofiles" 134 "uuid" 135 ]; 136 dependencies = 137 with python3Packages; 138 [ 139 aiofiles 140 aiohttp 141 aiohttp-cors 142 anyio 143 fastapi 144 filelock 145 grpcio 146 grpcio-tools 147 httpx 148 huggingface-hub 149 hypercorn 150 jinja2 151 loguru 152 mflux 153 mlx 154 mlx-lm-unstable 155 nvidia-ml-py 156 openai 157 openai-harmony 158 opencv-python 159 pillow 160 prometheus-client 161 psutil 162 pydantic 163 pyo3-bindings 164 python-multipart 165 rustworkx 166 scapy 167 tiktoken 168 tinygrad 169 tomlkit 170 transformers 171 uvloop 172 ] 173 ++ sqlalchemy.optional-dependencies.asyncio; 174 175 pythonImportsCheck = [ 176 "exo" 177 "exo.main" 178 ]; 179 180 nativeCheckInputs = [ 181 python3Packages.pytest-asyncio 182 python3Packages.pytestCheckHook 183 writableTmpDirAsHomeHook 184 ]; 185 186 # Otherwise fails with 'import file mismatch' 187 preCheck = '' 188 rm src/exo/__init__.py 189 ''; 190 191 disabledTests = lib.optionals stdenv.hostPlatform.isDarwin [ 192 # AssertionError: assert "MacMon not found in PATH" in str(exc_info.value) 193 "test_macmon_not_found_raises_macmon_error" 194 195 # ValueError: zip() argument 2 is longer than argument 1 196 "test_events_processed_in_correct_order" 197 198 # system_profiler is not available in the sandbox 199 "test_tb_parsing" 200 201 # Flaky in the sandbox (even when __darwinAllowLocalNetworking is enabled) 202 # RuntimeError - Attempted to create a NULL object. 203 "test_sleep_on_multiple_items" 204 205 # Flaky in the sandbox (even when __darwinAllowLocalNetworking is enabled) 206 # AssertionError: Expected 2 results, got 0. Errors: {0: "[ring] Couldn't bind socket (error: 1)"} 207 "test_composed_call_works" 208 ]; 209 210 disabledTestPaths = [ 211 # All tests hang indefinitely 212 "src/exo/worker/tests/unittests/test_mlx/test_tokenizers.py" 213 ]; 214 215 passthru = { 216 updateScript = nix-update-script { }; 217 exo-pyo3-bindings = pyo3-bindings; 218 exo-dashboard = dashboard; 219 }; 220 221 meta = { 222 description = "Run your own AI cluster at home with everyday devices"; 223 homepage = "https://github.com/exo-explore/exo"; 224 changelog = "https://github.com/exo-explore/exo/releases/tag/${finalAttrs.src.tag}"; 225 license = lib.licenses.gpl3Only; 226 maintainers = with lib.maintainers; [ GaetanLepage ]; 227 mainProgram = "exo"; 228 }; 229})