"""Read back the actual GUI-produced quit.blend using original native recovery.""" import argparse, hashlib, json, pathlib, sys import bpy assert bpy.app.version == (5, 2, 0) and sys.platform != "emscripten" parser = argparse.ArgumentParser() parser.add_argument("--work-dir", required=True) args = parser.parse_args(sys.argv[sys.argv.index("--") + 1:]) work = pathlib.Path(args.work_dir).resolve(); expected_path = work / "native-last-session-expected.json"; expected = json.loads(expected_path.read_text()) assert bpy.app.background, "Readback must not generate another GUI-exit quit file" assert expected["schemaVersion"] == 1 and expected["kind"] == "source-derived-original-native-exit" and expected["phase"] == "EXPECTED_STATE_WRITTEN_QUIT_PENDING" producer = pathlib.Path(__file__).with_name("native-last-session-prepare.py") assert expected["producerSha256"] == hashlib.sha256(producer.read_bytes()).hexdigest() quit_file = pathlib.Path(expected["quitFile"]).resolve(); assert quit_file == work / "native-temp" / "quit.blend" quit_bytes = quit_file.read_bytes(); assert quit_bytes; quit_sha256 = hashlib.sha256(quit_bytes).hexdigest() assert expected["expectedMain"]["filepath"] == str(work / "source-session.blend") bpy.context.preferences.filepaths.temporary_directory = str(quit_file.parent) assert pathlib.Path(bpy.app.tempdir).parent == quit_file.parent assert bpy.ops.wm.recover_last_session("EXEC_DEFAULT", use_scripts=False) == {"FINISHED"} actual = {"filepath": bpy.data.filepath, "scene": bpy.context.scene.name, "marker": bpy.context.scene.get("wbv2_last_session_unsaved"), "objects": sorted(obj.name for obj in bpy.data.objects), "images": {image.name: {"pixels": list(image.pixels[:4]), "size": list(image.size), "packed": bool(image.packed_file)} for image in bpy.data.images if image.source == "FILE"}} assert actual == expected["expectedMain"], "Actual native quit recovery differs from the producer Main" assert hashlib.sha256(quit_file.read_bytes()).hexdigest() == quit_sha256, "Readback changed the original quit artifact" receipt = {"schemaVersion": 1, "kind": "desktop-native-quit-readback", "phase": "NATIVE_QUIT_READBACK_CAPTURED", "acceptance": "NOT_CLAIMED", "inputSha256": expected["inputSha256"], "producerSha256": expected["producerSha256"], "readerSha256": hashlib.sha256(pathlib.Path(__file__).read_bytes()).hexdigest(), "expectedReceiptSha256": hashlib.sha256(expected_path.read_bytes()).hexdigest(), "quitFile": {"path": str(quit_file), "bytes": len(quit_bytes), "sha256": quit_sha256}, "actualMain": actual, "version": list(bpy.app.version), "platform": sys.platform, "nativeBinary": str(pathlib.Path(bpy.app.binary_path).resolve())} with (work / "native-last-session-readback.json").open("x") as stream: json.dump(receipt, stream, indent=2) print("WBV2_NATIVE_QUIT_READBACK", str(work / "native-last-session-readback.json"), flush=True)