Govern task context and advance execution pointer
This commit is contained in:
116
tools/web/generate-blender-operator-inventory.py
Normal file
116
tools/web/generate-blender-operator-inventory.py
Normal file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate a deterministic operator/RNA inventory from pinned Blender 5.2."""
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
def decode(value):
|
||||
return value.decode("utf-8", errors="replace") if isinstance(value, bytes) else str(value)
|
||||
|
||||
|
||||
def binary_sha256(path):
|
||||
digest = hashlib.sha256()
|
||||
with open(path, "rb") as handle:
|
||||
for block in iter(lambda: handle.read(1024 * 1024), b""):
|
||||
digest.update(block)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def property_info(prop):
|
||||
result = {"identifier": prop.identifier, "type": prop.type}
|
||||
if hasattr(prop, "array_length"):
|
||||
result["arrayLength"] = prop.array_length
|
||||
return result
|
||||
|
||||
|
||||
def operator_info(module_name, operator_name):
|
||||
operator_path = f"{module_name}.{operator_name}"
|
||||
try:
|
||||
operator = getattr(getattr(bpy.ops, module_name), operator_name)
|
||||
rna = operator.get_rna_type()
|
||||
properties = [property_info(prop) for prop in rna.properties if prop.identifier != "rna_type"]
|
||||
properties.sort(key=lambda prop: prop["identifier"])
|
||||
try:
|
||||
poll = bool(operator.poll())
|
||||
poll_error = None
|
||||
except (AttributeError, RuntimeError) as error:
|
||||
poll = None
|
||||
poll_error = type(error).__name__
|
||||
return {
|
||||
"operator": operator_path,
|
||||
"rnaIdentifier": rna.identifier,
|
||||
"registered": True,
|
||||
"poll": poll,
|
||||
"pollError": poll_error,
|
||||
"properties": properties,
|
||||
}
|
||||
except (AttributeError, KeyError, RuntimeError) as error:
|
||||
return {
|
||||
"operator": operator_path,
|
||||
"rnaIdentifier": None,
|
||||
"registered": False,
|
||||
"poll": None,
|
||||
"pollError": type(error).__name__,
|
||||
"properties": [],
|
||||
}
|
||||
|
||||
|
||||
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-operator-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}")
|
||||
operators = []
|
||||
for module_name in sorted(name for name in dir(bpy.ops) if not name.startswith("_")):
|
||||
try:
|
||||
module = getattr(bpy.ops, module_name)
|
||||
names = sorted(name for name in dir(module) if not name.startswith("_"))
|
||||
except (AttributeError, RuntimeError):
|
||||
continue
|
||||
for operator_name in names:
|
||||
try:
|
||||
value = getattr(module, operator_name)
|
||||
if not hasattr(value, "get_rna_type"):
|
||||
continue
|
||||
except (AttributeError, RuntimeError):
|
||||
continue
|
||||
operators.append(operator_info(module_name, operator_name))
|
||||
operators.sort(key=lambda entry: entry["operator"])
|
||||
operator_ids = [entry["operator"] for entry in operators]
|
||||
if len(operator_ids) != len(set(operator_ids)):
|
||||
raise RuntimeError("duplicate Blender operator idname")
|
||||
binary_path = pathlib.Path(bpy.app.binary_path).resolve()
|
||||
inventory = {
|
||||
"schemaVersion": 1,
|
||||
"task": "M15-01B",
|
||||
"operation": "BLENDER_OPERATOR_INVENTORY",
|
||||
"sourceAnchor": "blender-5.2.0/source/blender/editors",
|
||||
"runtime": {
|
||||
"blenderVersion": decode(bpy.app.version_string),
|
||||
"versionTuple": list(version),
|
||||
"buildHash": decode(bpy.app.build_hash),
|
||||
"buildBranch": decode(bpy.app.build_branch),
|
||||
"buildPlatform": decode(bpy.app.build_platform),
|
||||
"buildType": decode(bpy.app.build_type),
|
||||
"buildDate": decode(bpy.app.build_date),
|
||||
"buildTime": decode(bpy.app.build_time),
|
||||
"binarySha256": binary_sha256(binary_path),
|
||||
},
|
||||
"summary": {"count": len(operators), "registered": sum(1 for entry in operators if entry["registered"]), "pollTrue": sum(1 for entry in operators if entry["poll"] is True), "pollFalse": sum(1 for entry in operators if entry["poll"] is False), "pollUnknown": sum(1 for entry in operators if entry["poll"] is None)},
|
||||
"operators": operators,
|
||||
"nextTask": "M15-01C",
|
||||
}
|
||||
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-operator-inventory-generated count={len(operators)} blender={bpy.app.version_string} output={output}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user