Reject sd-cli batch runs and clear stale output targets before a run

This commit is contained in:
Daniel Han 2026-07-05 01:49:19 +00:00
commit 098809d2fe
4 changed files with 35 additions and 3 deletions

View file

@ -269,7 +269,12 @@ def build_sd_cpp_command(
if params.seed is not None:
cmd += ["--seed", str(int(params.seed))]
if params.batch_count and params.batch_count != 1:
cmd += ["--batch-count", str(int(params.batch_count))]
# sd-cli names the extra batch images itself (output_2.png, ...) and the runner
# collects only the literal --output path, so a CLI batch would silently drop
# every image after the first. Batches go through the sdcpp server API instead.
raise ValueError(
"sd-cli runs are single-image; use the sdcpp server API for batch generation."
)
cmd += ["--output", output_path]
if threads is not None:

View file

@ -364,6 +364,9 @@ class SdCppEngine:
def _prepare_out(output_path: str) -> Path:
out = Path(output_path)
out.parent.mkdir(parents = True, exist_ok = True)
# Drop a stale file at the target so the post-run is_file() check proves THIS
# run produced the image, not a leftover from an earlier run at the same path.
out.unlink(missing_ok = True)
return out
def _run(

View file

@ -166,10 +166,18 @@ def test_build_appends_offload_and_extra_args_last():
def test_build_negative_prompt_and_batch():
files = SdCppModelFiles(diffusion_model = "/m/z.gguf")
params = SdCppGenParams(prompt = "x", negative_prompt = "blurry", batch_count = 3)
params = SdCppGenParams(prompt = "x", negative_prompt = "blurry")
cmd = build_sd_cpp_command("/bin/sd-cli", files, params, output_path = "/o.png")
assert _pair(cmd, "--negative-prompt") == "blurry"
assert _pair(cmd, "--batch-count") == "3"
# A CLI batch would silently drop every image after the first (the runner only
# collects the literal --output path), so the builder rejects it outright.
with pytest.raises(ValueError, match = "single-image"):
build_sd_cpp_command(
"/bin/sd-cli",
files,
SdCppGenParams(prompt = "x", batch_count = 3),
output_path = "/o.png",
)
def test_build_omits_unset_optional_params():

View file

@ -323,6 +323,22 @@ def test_generate_raises_when_no_output_despite_success(tmp_path, monkeypatch):
)
def test_generate_does_not_return_stale_preexisting_output(tmp_path, monkeypatch):
# A leftover file at the target path must not satisfy the post-run output check
# when the run itself produced nothing: the target is cleared before the run.
e = _engine(tmp_path)
out = tmp_path / "img.png"
out.write_bytes(b"stale")
_patch_popen(monkeypatch, lines = ["ok"], returncode = 0, out_file = out, write = False)
with pytest.raises(RuntimeError, match = "no image"):
e.generate(
SdCppModelFiles(diffusion_model = "/m/z.gguf"),
SdCppGenParams(prompt = "x"),
output_path = str(out),
)
assert not out.exists()
def test_generate_raises_when_binary_missing():
e = SdCppEngine(binary = None)
with pytest.raises(RuntimeError, match = "not found"):