Ask before reopening a bundle that carries no cuts

A bundle without a source block cannot be round-tripped, but its PDF can
still be cut from scratch. Offer that instead of refusing: confirm, run
detection, and line the markers up by position when the slice counts
match exactly.
This commit is contained in:
Esa Kataja
2026-07-29 15:06:45 +03:00
parent 61b8ec8301
commit cdf37302d7
5 changed files with 223 additions and 66 deletions
+43 -1
View File
@@ -165,6 +165,38 @@ def main() -> int:
assert back.bars[second] == 7
assert back.replacements[second].voices[0].lyrics == "la la"
# A bundle from a producer that records no cuts: refused by default, and
# cut from scratch by detection when the caller says so. The slices are in
# reading order either way, so markers can be lined up by position — but
# only when detection finds exactly as many.
plain = tmp / "plain.zip"
with zipfile.ZipFile(out) as src, zipfile.ZipFile(plain, "w") as dst:
for name in src.namelist():
data = src.read(name)
if name == "song.json":
manifest = json.loads(data)
manifest.pop("source")
for entry in manifest["slices"]:
entry.pop("page", None)
entry.pop("slot", None)
data = json.dumps(manifest).encode()
dst.writestr(name, data)
assert bundle.has_cuts(out) and not bundle.has_cuts(plain)
try:
bundle.read(plain, tmp / "nocuts.pdf")
except bundle.NoCuts as error:
assert "no cuts" in str(error), error
else:
raise AssertionError("a bundle without cuts should not open silently")
cut_again, again_pdf = bundle.read(plain, tmp / "nocuts.pdf", detect=True)
assert again_pdf.exists()
assert cut_again.metadata["title"] == "Test song", "the title block still comes back"
assert len(cut_again.kept_slices()) == len(reloaded.kept_slices())
placed = [m for page in cut_again.pages for slot in page.markers for m in slot]
assert len(placed) == 3, placed
assert placed[0].label == "A"
# Unpacking never lands on files that are already there.
try:
bundle.read(out, tmp / "reopened.pdf")
@@ -174,7 +206,17 @@ def main() -> int:
raise AssertionError("reopening over an existing PDF should be refused")
source.close()
for f in (pdf, out, saved, unpacked, default_path(unpacked), default_path(pdf)):
for f in (
pdf,
out,
plain,
saved,
unpacked,
again_pdf,
default_path(unpacked),
default_path(again_pdf),
default_path(pdf),
):
f.unlink(missing_ok=True)
tmp.rmdir()
print("ok")