Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions MANIFEST.sha256
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.22.0
3.22.1
13 changes: 13 additions & 0 deletions comfyui-base-handbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Binary file modified comfyui-base.zip
Binary file not shown.
65 changes: 64 additions & 1 deletion suite/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 <download available>
Expand All @@ -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
"""
Expand Down Expand Up @@ -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")
Expand Down
37 changes: 35 additions & 2 deletions testbed.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -315,6 +316,25 @@ _testbed_venv(){ # <x.y>
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; }
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand Down
Loading