diff --git a/MANIFEST.sha256 b/MANIFEST.sha256 index 8730e0e..b83fd58 100644 --- a/MANIFEST.sha256 +++ b/MANIFEST.sha256 @@ -1,7 +1,7 @@ af891a1c6f3f3958b43ea1f97a079ff898394ac72b2f49f88f3db66276f94eaf base.sh 577a83f8e3e3c4d69e04f4cbcee7ead42c49981c76f9bb07f8f78fd076876e01 comfyui-base-script.sh -0052e9272c027a271b54c19b6aad625e3da0b087e768a0a1acfad76103ab1ada comfyui-base-handbook.md -46058ff89ee6dab89b7f99a6a21b117815ecf0e1f3967e51802d462c95f332fb VERSION +e667f0ef982941ae4de05c2b0bc30427b669310c6e5f160f8a15f5078dc19b92 comfyui-base-handbook.md +08842eac2718502d9d72a2f89396da3c28fbc73356b2077551bf662c832101f8 VERSION 939c10b34e782bb77792eb876d8a51d74b38192598483c8c628f5da1b877397d pytest.ini 8aa67b7331d052dbbd1dcf9b357f088891e0fa0f4ed56e6669c105046fe881b2 LICENSE 3dcc371917e882b798f0f326a61d0fc3e1b6d65a799adba36344371d26568405 lib/00-env.sh @@ -79,7 +79,7 @@ e4840d044d8bc334e9a816815bada3beb95882d41c8f30c55a0622d1e9415a06 suite/test_run 786deecfaa096c2ab77a15c924b8f5b032257fc3923b4c952a6ec067b6a663d9 suite/test_runtime.py 70b1fe09d400958c2e3680fade6750ea6f9639ee99f325f4abc0e8035b99b220 suite/test_speed.py dbc1df30af0c04ecbc0eef14dc08e3d756dc4a4dfa934be96f71c49d423c9c93 suite/test_staged.py -a799fa8528007764ac2cbdafe208e7ff64779bb1baec9e9eee3906155cf521d4 suite/test_unit.py +8fd525063926553b677264dd8ed9aea0cededaab2e37f9e228b393a0de2bf8df suite/test_unit.py 56dbcab4c427fbdc13a05c0eb4626ba464c84bced1486fb459877f25690835cb suite/test_verda.py 44edb78dcde7390a35b626b7b7a37b8568ccca0d2959683988e2d61b9887bb5f hosts/README.md 38feee74e9b4fc39aeded6a69c6f194ffc866d23d0dac7b4632fcdd27a28137e hosts/__init__.py diff --git a/VERSION b/VERSION index a7e7070..732c061 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.22.0 +3.22.1 diff --git a/comfyui-base-handbook.md b/comfyui-base-handbook.md index 7540c88..dd0f45a 100644 --- a/comfyui-base-handbook.md +++ b/comfyui-base-handbook.md @@ -837,6 +837,19 @@ for any invocation that somehow arrives without the environment. The suite asser ## 10. Record +- 3.22.1: triton beside the testbed's CPU torch on Linux (2026-10-17, found by image-creator-krea-2#10). The CPU torch + that 3.18.2 gave the testbed has no triton, which a pod's CUDA torch carries (`lib/30-venv.sh` keeps it in the torch + family), and packs import it at module level: ComfyUI-RMBG's HEAD (229529e) bundles a sam3 whose `edt.py` does + `import triton`, the pack's loader then raises a NameError in its own except branch and none of its nodes register, + and ComfyUI-Easy-Sam3 stops on `No module named 'triton'`. Every package that uses RMBG saw a missing node on CI. + `testbed.sh --server` on Linux now installs the newest triton right after torch, against a constraints file of the + torch family as installed (`testbed/.testbed-torch.txt`), so it never moves torch; importing it needs no GPU. A miss is + a warning and the build goes on. `--status` names the venv's triton on Linux, and, for every package, the packs its own + server could not import: each pack ComfyUI's "Import times for custom nodes" marks `(IMPORT FAILED)` in that server's + log, or "none". Krea 2's CI (run 39078526395) had passed its suite while RMBG never registered, with nothing in the + log to say so. macOS (no triton wheels) and the pod's install are unchanged. Unit tests hold the order, the + constraints, the warning, the macOS path, and the import report (a failed pack named, a clean one not, "none", a + foreign server never read). Exercised on the CI runner only. - 3.22.0: install speed on the critical path, and a clock that shows it (Paul's priority 3, 2026-10-17). Read from the last Video Replacer pod (1x B200, EU-RO-1, base 3.20.0, every row: 42 files, 295.5 GB): about 5:17 from create to the App for a fresh install, with the 66.3 GB B300-only file the long pole (147 s with its sha256) and VENV 116 s beside diff --git a/comfyui-base.zip b/comfyui-base.zip index a431b4d..80a9d03 100644 Binary files a/comfyui-base.zip and b/comfyui-base.zip differ diff --git a/suite/test_unit.py b/suite/test_unit.py index 2aa5490..7b05c2f 100644 --- a/suite/test_unit.py +++ b/suite/test_unit.py @@ -1295,8 +1295,10 @@ def test_unit_the_testbed_finds_packages_without_naming_one(): _FAKE_UV = r"""#!/bin/bash # a uv stand-in: `python list` prints a canned listing, `pip compile` resolves only on $TORCH_OK's minors, -# `venv` behaves like uv 0.13 (refuses an existing directory) and makes a python that reports the minor it was given +# `venv` behaves like uv 0.13 (refuses an existing directory) and makes a python that reports the minor it was given, +# `pip freeze` lists a CPU torch family, and an install of triton fails while $UV_NO_TRITON is set echo "$*" >> "$UV_LOG" +case "$*" in *" triton") [ -z "${UV_NO_TRITON:-}" ] || { echo "No solution found when resolving dependencies: triton" >&2; exit 1; };; esac case "$1 $2" in "python list") cat <<'EOF' cpython-3.16.0a1-macos-aarch64-none @@ -1315,6 +1317,7 @@ def test_unit_the_testbed_finds_packages_without_naming_one(): "venv --python") d="$4" [ -e "$d" ] && { echo "error: A virtual environment already exists at $d" >&2; exit 2; } mkdir -p "$d/bin"; printf '#!/bin/bash\necho %s\n' "$3" > "$d/bin/python"; chmod +x "$d/bin/python"; exit 0;; + "pip freeze") printf 'numpy==2.3.4\ntorch==2.14.1+cpu\ntorchaudio==2.14.1+cpu\ntorchvision==0.29.1+cpu\n'; exit 0;; esac exit 0 """ @@ -1383,6 +1386,66 @@ def test_unit_testbed_replaces_a_half_made_venv(tmp_path): assert r.returncode == 0 and "rebuilding it" in r.stdout and r.stdout.strip().endswith("3.15"), r.stdout + r.stderr +def test_unit_testbed_puts_triton_beside_cpu_torch_on_linux(tmp_path): + """3.22.1 (image-creator-krea-2#10): CPU torch has no triton, and packs import it at module level (ComfyUI-RMBG's HEAD + through its bundled sam3, ComfyUI-Easy-Sam3), so neither registered on the Linux testbed while a pod's CUDA torch + carries it. On Linux --server installs the newest triton right after torch, against a constraints file of the torch + family as installed so it never moves torch; a triton that will not install is a warning and the build goes on; + macOS (no triton wheels) asks for none.""" + _repo_only("the repo's testbed.sh") + go = 'uname(){ echo %s; }; start_server(){ echo "server started"; }; provision_server' + tb, log, run = _testbed_sandbox(tmp_path / "linux", "3.14") + r = run(go % "Linux") + assert r.returncode == 0 and "server started" in r.stdout, r.stdout + r.stderr + calls = log.read_text().splitlines() + def at(pred): + return next((i for i, c in enumerate(calls) if pred(c.split())), None) + torch = at(lambda a: a[:2] == ["pip", "install"] and a[-3:] == ["torch", "torchvision", "torchaudio"]) + freeze = at(lambda a: a[:2] == ["pip", "freeze"]) + triton = at(lambda a: a[:2] == ["pip", "install"] and a[-1] == "triton") + reqs = at(lambda a: a[:2] == ["pip", "install"] and "-r" in a) + assert None not in (torch, freeze, triton, reqs) and torch < freeze < triton < reqs, calls + args = calls[triton].split() + assert "--upgrade" in args, args # the newest, on a reused venv too + cons = pathlib.Path(args[args.index("-c") + 1]) + assert sorted(cons.read_text().split()) == ["torch==2.14.1+cpu", "torchaudio==2.14.1+cpu", "torchvision==0.29.1+cpu"], cons.read_text() + assert "beside torch 2.14.1+cpu" in r.stdout, r.stdout + # no triton build resolves: a warning, and the requirements and the server still follow + tb, log, run = _testbed_sandbox(tmp_path / "miss", "3.14") + r = run("export UV_NO_TRITON=1; " + go % "Linux") + assert r.returncode == 0 and "triton did not install" in r.stdout and "server started" in r.stdout, r.stdout + r.stderr + # macOS: nothing asked for + tb, log, run = _testbed_sandbox(tmp_path / "mac", "3.14") + r = run(go % "Darwin") + assert r.returncode == 0 and "server started" in r.stdout, r.stdout + r.stderr + assert not [c for c in log.read_text().splitlines() if "triton" in c or c.startswith("pip freeze")], log.read_text() + + +def test_unit_testbed_status_names_the_packs_its_server_could_not_import(tmp_path): + """3.22.1: image-creator-krea-2's CI (run 39078526395) passed its suite while ComfyUI-RMBG never registered on the + testbed, and nothing in the log said so. --status reads ComfyUI's own import times from this server's log and names + every pack marked (IMPORT FAILED), or "none"; a server this testbed did not start is never read.""" + _repo_only("the repo's testbed.sh") + tb, log, run = _testbed_sandbox(tmp_path, "3.14") + slog, cn = tb / "server.log", "/x/testbed/custom_nodes" + ours = 'LOG="%s"; owned_server(){ echo 127.0.0.1:8199; }; own_pids(){ echo 4242; }; status' % slog + # one pack failed, one imported: only the failed one is named + slog.write_text("Import times for custom nodes:\n" + " 0.4 seconds (IMPORT FAILED): %s/ComfyUI-RMBG\n" + " 1.2 seconds: %s/ComfyUI-KJNodes\n" % (cn, cn)) + r = run(ours) + assert r.returncode == 0 and "could not import: ComfyUI-RMBG (" in r.stdout and "KJNodes" not in r.stdout, r.stdout + r.stderr + # every pack imported: "none" + slog.write_text("Import times for custom nodes:\n" + " 0.4 seconds: %s/ComfyUI-RMBG\n" + " 1.2 seconds: %s/ComfyUI-KJNodes\n" % (cn, cn)) + r = run(ours) + assert r.returncode == 0 and "could not import: none" in r.stdout, r.stdout + r.stderr + # a server that is not this testbed's: its log says nothing about the one answering + r = run('LOG="%s"; owned_server(){ return 1; }; status' % slog) + assert r.returncode == 0 and "could not import" not in r.stdout, r.stdout + r.stderr + + def test_unit_testbed_sourced_runs_nothing(tmp_path): """The suite sources testbed.sh for its functions: sourcing defines and returns, it never provisions or prints usage.""" _repo_only("the repo's testbed.sh") diff --git a/testbed.sh b/testbed.sh index 2102d57..c83be0f 100644 --- a/testbed.sh +++ b/testbed.sh @@ -41,7 +41,8 @@ # read from each pack's real source — the checks that catch a pod install # failing to load the graph. # ✔ server (--server): the pure-Python packs import and register under a -# current Python, and /object_info answers. +# current Python, and /object_info answers. On Linux triton sits beside the +# CPU torch (3.22.1), so packs that import it at module level register too. # ✘ CUDA: this host has no NVIDIA GPU. SolAttn (Triton), the Nvidia RTX nodes # and the int8-ConvRot loader (comfy-kitchen) cannot import here. # ✘ rendering: needs the weights and an sm_120 GPU. That is the pod. @@ -315,6 +316,25 @@ _testbed_venv(){ # fi } +# 3.22.1: triton beside the CPU torch, on Linux. A pod's CUDA torch carries it (lib/30-venv.sh keeps it in the torch +# family) and the CPU build does not, while packs import it at module level: ComfyUI-RMBG's HEAD (229529e, 2026-10-17) +# bundles a sam3 whose edt.py does `import triton`, the pack's loader then raises a NameError in its own except branch +# and none of its nodes register, and ComfyUI-Easy-Sam3 stops on "No module named 'triton'". Importing it needs no GPU +# (on the soulcraft-hf runner triton 3.8.0 imported and RMBG registered its 45 nodes). The newest triton, resolved +# against a constraints file of the torch family as installed, so adding it never moves torch. A miss is a warning: the +# packs that need it then fail to register on their own, and every other check still runs. macOS has no triton wheels. +_testbed_triton(){ + local cons="$COMFY/.testbed-torch.txt" v="" tv # inside the ignored testbed tree + uv pip freeze --python "$VENV/bin/python" 2>/dev/null | grep -E '^(torch|torchvision|torchaudio)==' >"$cons" || true + tv="$(sed -n 's/^torch==//p' "$cons")" + if uv pip install -q --upgrade --python "$VENV/bin/python" -c "$cons" triton >/dev/null 2>&1 \ + && v="$("$VENV/bin/python" -c 'import triton; print(triton.__version__)' 2>/dev/null)" && [ -n "$v" ]; then + ok "triton $v beside torch ${tv:-?} (packs that import it at module level register)" + else + warn "triton did not install or import beside the CPU torch: packs that import it at module level (ComfyUI-RMBG, ComfyUI-Easy-Sam3) will not register" + fi +} + provision_server() { hdr "VENV + SERVER (CPU)" command -v uv >/dev/null || { warn "uv is not installed — needed to build the venv"; return 1; } @@ -329,9 +349,10 @@ provision_server() { if [ "$(uname -s)" = Linux ]; then export UV_TORCH_BACKEND=cpu; fi note "installing torch (CPU${UV_TORCH_BACKEND:+, uv --torch-backend $UV_TORCH_BACKEND}) + every requirement at its newest: this is the slow part …" uv pip install -q --upgrade --python "$VENV/bin/python" torch torchvision torchaudio >/dev/null + if [ "$(uname -s)" = Linux ]; then _testbed_triton; fi # one pin-free set: ComfyUI's own == pins (its frontend packages) and every pack's are lifted by the base's reqlift local row dir files=("ComfyUI=$COMFY/requirements.txt") derived="$COMFY/.testbed-derived.txt" # inside the ignored testbed tree - for row in "${PACKS[@]}"; do + for row in ${PACKS[@]+"${PACKS[@]}"}; do # PACKS may be empty (bash 3.2 + set -u) dir="${row%%|*}" [ -f "$CN/$dir/requirements.txt" ] && files+=("$dir=$CN/$dir/requirements.txt") done @@ -421,10 +442,22 @@ status() { hdr "STATUS" [ -d "$COMFY/.git" ] && ok "ComfyUI $(git -C "$COMFY" describe --tags 2>/dev/null || echo '?') · $(ls -1 "$CN" 2>/dev/null | wc -l | tr -d ' ') packs" || note "no source tree yet" [ -x "$VENV/bin/python" ] && ok "venv $($VENV/bin/python -V 2>&1)" || note "no venv" + if [ -x "$VENV/bin/python" ] && [ "$(uname -s)" = Linux ]; then # 3.22.1: _testbed_triton; macOS has none to show + local tri; tri="$("$VENV/bin/python" -c 'import importlib.metadata as m; print(m.version("triton"))' 2>/dev/null || true)" + if [ -n "$tri" ]; then ok "triton $tri"; else warn "no triton in the venv: packs that import it at module level do not register (--server installs it)"; fi + fi local mine if mine="$(owned_server 2>/dev/null)"; then ok "server answering at $mine (this testbed's, pid $(own_pids | head -1))" elif curl -fsS "http://127.0.0.1:$PORT/system_stats" >/dev/null 2>&1; then note "a server answers on $PORT, but not this testbed's (TESTBED_PORT picks another)" else note "server not running"; fi + # 3.22.1: the packs this server could not import, from ComfyUI's own "Import times for custom nodes" in its log. A suite + # passes around a pack that never registered (ComfyUI-RMBG without triton did, image-creator-krea-2 CI run 39078526395), + # so the CI log names them instead + if [ -n "${mine:-}" ] && [ -f "$LOG" ] && grep -q "Import times for custom nodes" "$LOG"; then + local failed; failed="$(sed -n 's|.* seconds (IMPORT FAILED): .*/||p' "$LOG" | sort -u | tr '\n' ' ')" + if [ -n "$failed" ]; then warn "packs this server could not import: ${failed% } (their nodes are missing; see $LOG)" + else ok "packs this server could not import: none (ComfyUI's import times in $LOG)"; fi + fi [ -f "$PORTF" ] && note "port file: $PORTF ($(tr -d '[:space:]' < "$PORTF"))" # what a provision WOULD install, and where the packages were found. Silent derivation is how 2.6.0 shipped # a testbed that quietly provisioned the base's packs and none of a consumer repository's.