Files
workinf_Blender_Wasm/tools/web/generate-blender-format-inventory.py
mes123456 10640aeb3c
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
Govern task context and advance execution pointer
2026-08-20 06:02:43 -04:00

128 lines
5.1 KiB
Python

#!/usr/bin/env python3
"""Generate deterministic Blender 5.2 sequencer, physics, and I/O inventories."""
import hashlib
import json
import pathlib
import re
import sys
import bpy
def text(value):
return value.decode("utf-8", errors="replace") if isinstance(value, bytes) else str(value)
def sha256_file(path):
digest = hashlib.sha256()
with open(path, "rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def property_info(prop):
result = {"identifier": prop.identifier, "type": prop.type, "readOnly": bool(prop.is_readonly)}
if hasattr(prop, "array_length"):
result["arrayLength"] = prop.array_length
return result
def enum_item_info(item):
return {"identifier": item.identifier, "name": text(item.name), "description": text(item.description), "value": item.value}
def enum_inventory(rna_type, property_name):
entries = [enum_item_info(item) for item in rna_type.bl_rna.properties[property_name].enum_items]
entries.sort(key=lambda item: item["identifier"])
return entries
def class_properties(rna):
entries = [property_info(prop) for prop in rna.properties if prop.identifier != "rna_type"]
entries.sort(key=lambda prop: prop["identifier"])
return entries
def physics_inventory():
marker = re.compile(r"(Particle|Boid|Cloth|SoftBody|RigidBody|Fluid|DynamicPaint|Effector|Collision|Field|PointCache|BakeSettings)")
entries = []
for class_name in sorted(name for name in dir(bpy.types) if not name.startswith("_")):
cls = getattr(bpy.types, class_name)
if not isinstance(cls, type) or not marker.search(class_name) or re.match(r"[A-Z0-9]+_(?:PT|OT|MT|UL)_", class_name):
continue
rna = getattr(cls, "bl_rna", None)
if not rna or class_name.endswith("Node"):
continue
entries.append({"className": class_name, "rnaIdentifier": text(rna.identifier), "properties": class_properties(rna)})
entries.sort(key=lambda entry: (entry["rnaIdentifier"], entry["className"]))
return entries
def operator_inventory():
entries = []
for module_name in sorted(name for name in dir(bpy.ops) if not name.startswith("_")):
module = getattr(bpy.ops, module_name)
for operator_name in sorted(name for name in dir(module) if not name.startswith("_")):
operator_path = f"{module_name}.{operator_name}"
if not re.search(r"(?:import|export)", operator_path, re.IGNORECASE):
continue
try:
operator = getattr(module, operator_name)
rna = operator.get_rna_type()
properties = class_properties(rna)
try:
poll = bool(operator.poll())
poll_error = None
except (AttributeError, RuntimeError) as error:
poll = None
poll_error = type(error).__name__
entries.append({"operator": operator_path, "rnaIdentifier": text(rna.identifier), "poll": poll, "pollError": poll_error, "properties": properties})
except (AttributeError, KeyError, RuntimeError):
continue
entries.sort(key=lambda entry: entry["operator"])
return entries
def main():
if "--" not in sys.argv or len(sys.argv[sys.argv.index("--") + 1:]) != 1:
raise SystemExit("usage: blender --background --factory-startup --python generate-blender-format-inventory.py -- OUTPUT.json")
output = pathlib.Path(sys.argv[sys.argv.index("--") + 1]).resolve()
version = tuple(int(value) for value in bpy.app.version)
if version != (5, 2, 0):
raise RuntimeError(f"expected Blender 5.2.0, got {version}")
strips = enum_inventory(bpy.types.Strip, "type")
physics = physics_inventory()
io_operators = operator_inventory()
binary_path = pathlib.Path(bpy.app.binary_path).resolve()
inventory = {
"schemaVersion": 1,
"task": "M15-01D",
"operation": "BLENDER_FORMAT_INVENTORY",
"sourceAnchor": "blender-5.2.0/source/blender/makesrna",
"runtime": {
"blenderVersion": text(bpy.app.version_string),
"versionTuple": list(version),
"buildHash": text(bpy.app.build_hash),
"buildBranch": text(bpy.app.build_branch),
"buildPlatform": text(bpy.app.build_platform),
"buildType": text(bpy.app.build_type),
"buildDate": text(bpy.app.build_date),
"buildTime": text(bpy.app.build_time),
"binarySha256": sha256_file(binary_path),
},
"summary": {"stripTypeCount": len(strips), "physicsTypeCount": len(physics), "ioOperatorCount": len(io_operators)},
"stripTypes": strips,
"physicsTypes": physics,
"ioOperators": io_operators,
"nextTask": "M15-01E",
}
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(json.dumps(inventory, indent=2, sort_keys=True) + "\n", encoding="utf-8")
print(f"blender-format-inventory-generated strips={len(strips)} physics={len(physics)} io={len(io_operators)} output={output}")
if __name__ == "__main__":
main()