setup: the pinned-shard mark helper needs no 'hf' key (the NVFP4 families have none) (#4088)

main() and mac_control_setup() read fam['hf'] to build the pin lookup URL; the NVFP4 families download a file list and have no such key, so every NVFP4 install raised KeyError.
The helper takes None and then keeps the old mark. Found by the INT3 merge run (tools/test_setup_nvfp4.py, tools/test_setup_dl_fix.py).
This commit is contained in:
Niko1221 committed 2026-11-04 17:33:39 +01:00
1 parent c6dda74bf2
commit 71395ec9c7
2 files changed
+14 -5

No files matched your search

+6 -5
View File
@@ -3219,18 +3219,19 @@ def whole_shard(s: Path) -> bool:
return False
def mark_whole_unless_pinned(shards, hf: str, own: bool) -> None:
def mark_whole_unless_pinned(shards, hf: str | None, own: bool) -> None:
"""#173's finish mark for a file copied in by hand (it has the length its own tensor directory says), except a file with a pinned SHA-256 (#4088).
A run that stopped between the rename of a finished .part and the end of verify_sha256 leaves a full-length shard with no mark. Marking it "whole"
made done() true, download() skipped it and the pinned hash was never looked at, so a shard damaged by that crash stayed in place (a deleted mark
was written again by the next run). For a file the pin table names, leave it unmarked: download() takes its "finished by an older setup (no mark
yet), or stopped before the check" path, hashes it, repairs the damaged parts and writes the finish mark itself. `own` is --gguf-dir: a person's
own file is not a download and is not hash-checked here either way, so it keeps the mark; so does a file the pin table does not name."""
own file is not a download and is not hash-checked here either way, so it keeps the mark; so does a file the pin table does not name, and every file of a
family with no Hugging Face folder of its own (`hf` None: the NVFP4 families download a file list, not shards)."""
for s in shards:
if not (s.exists() and not done(s) and whole_shard(s)):
continue
if not own and file_pin(hf + s.name) is not None:
if not own and hf is not None and file_pin(hf + s.name) is not None:
continue
try:
mark(s, "whole (checked against its own tensor directory)")
@@ -9482,7 +9483,7 @@ def mac_control_setup(a) -> int:
problem = gguf_dir_problem(models_dir, files[0], fam, model) if a.gguf_dir else None
if problem: # files Strata cannot run, or another choice's files
fail(*problem)
mark_whole_unless_pinned(files, fam["hf"].format(q=model), bool(a.gguf_dir)) # a whole file copied in by hand has no finish mark
mark_whole_unless_pinned(files, fam["hf"].format(q=model) if fam.get("hf") else None, bool(a.gguf_dir)) # a whole file copied in by hand has no finish mark
need = (0 if a.gguf_dir or all(s.exists() and done(s) for s in files) else MODELS[model]["download_gb"]) + 6
if free_gb(models_dir if models_dir.exists() else data) < need:
warn(f"about {need:.0f} GB are needed on the disk: kept as you chose; it may run out")
@@ -10448,7 +10449,7 @@ def main() -> int:
models_dir, shards = cand[0].parent, cand
ok(f"model files found in {models_dir}")
break
mark_whole_unless_pinned([] if ready else shards, fam["hf"].format(q=model), bool(a.gguf_dir)) # #173: a whole file copied in by hand has no finish mark
mark_whole_unless_pinned([] if ready else shards, fam["hf"].format(q=model) if fam.get("hf") else None, bool(a.gguf_dir)) # #173: a whole file copied in by hand has no finish mark
have_model = all(ready_verified(ready_where(models_dir, f), f[5]) for f in ready_needed(model, models_dir)) if ready else \
all(s.exists() and (done(s) or a.gguf_dir) for s in shards)
# #425 (jctaborda): a download that resumes needs room only for what is still missing - the finished shards and
+8
View File
@@ -599,6 +599,14 @@ class WholeMarkNeedsThePin(unittest.TestCase):
setup.mark_whole_unless_pinned([shard], self.hf, own=True) # --gguf-dir: not a download
self.assertTrue(setup.done(shard))
def test_a_family_with_no_hf_folder_keeps_the_mark_and_does_not_raise(self):
"""The NVFP4 families have no "hf" key (they download a file list): the helper must not need one (it raised KeyError in main())."""
shard = self.folder / self.name
shard.write_bytes(b"x")
setup.mark_whole_unless_pinned([shard], None, own=False)
self.assertTrue(setup.done(shard))
setup.mark_whole_unless_pinned([], None, own=False)
def test_a_marked_or_missing_file_is_not_touched(self):
shard = self.folder / "marked.gguf"
shard.write_bytes(b"x")