tools / utils /generate_bpy_doc.py
Germano Cavalcante
Add Utils for generate documentantion
91ad34e
raw
history blame
6.38 kB
import bpy
import inspect
import time
import pickle
import mathutils
import os
import bpy_types
import addon_utils
import sys
INFO_MEMBER = "__info"
def get_info(name="", descr="", bases=None):
return {"name": name,
"descr": descr,
"bases": bases}
##################################################################
g_bpy_types = {}
def doc_from_bpy_struct(bl_rna):
bases = []
try:
base = bl_rna.base
while base:
bases.append(type(base).__name__)
base = base.base
except:
if not bases:
bases = None
return get_info(name=bl_rna.name, descr=bl_rna.description, bases=bases)
def bpy_type_first_step(bpy_type):
def is_member_from_base_class(bpy_type, identifier):
if identifier in bpy.types.ID.bl_rna.properties:
return True
bases = bpy_type.mro()[1:]
for base in bases:
if not hasattr(base, "bl_rna"):
continue
if identifier in base.bl_rna.properties:
return True
return False
info = doc_from_bpy_struct(bpy_type.bl_rna)
data = {INFO_MEMBER: info}
for prop in bpy_type.bl_rna.properties:
identifier = prop.identifier
if is_member_from_base_class(bpy_type, identifier):
continue
if prop.type == 'POINTER':
srna_type = prop.fixed_type.identifier
try:
pointer_type = getattr(bpy.types, srna_type)
data[identifier] = pointer_type
except Exception:
pass
continue
if prop.type == 'COLLECTION':
if prop.srna:
srna_type = prop.srna.identifier
pointer_type = getattr(bpy.types, srna_type)
data[identifier] = pointer_type
elif srna_type := prop.fixed_type.identifier:
pointer_type = getattr(bpy.types, srna_type)
data[identifier] = [pointer_type]
continue
info_member = doc_from_bpy_struct(prop)
data[identifier] = {INFO_MEMBER: info_member}
return data
def bpy_types_first_step():
global g_bpy_types
for bpy_type_name in dir(bpy.types):
bpy_type = getattr(bpy.types, bpy_type_name)
if not hasattr(bpy_type, "bl_rna"):
continue
g_bpy_types[bpy_type] = bpy_type_first_step(bpy_type)
def bpy_types_second_step():
global g_bpy_types
for bpy_type, map in g_bpy_types.items():
for key, val in map.items():
if hasattr(val, "bl_rna"):
map[key] = g_bpy_types[val]
elif isinstance(val, list):
val[0] = g_bpy_types[val[0]]
##################################################################
bases_builtin = {int, bool, float, str, bytes, tuple, list,
set, dict, mathutils.Vector, mathutils.Color, type(None)}
def is_member_inherited(obj, member):
mro_bases = inspect.getmro(type(obj))
mro_bases_set = set(mro_bases)
intersection = mro_bases_set.intersection(bases_builtin)
for base in intersection:
if hasattr(base, member):
return True
return False
def get_doc_recursive(parent, member):
ob = getattr(parent, member)
member_info = getattr(type(parent), member, ob)
if type(member_info) in bases_builtin or member == "bpy_func":
descr = type(member_info).__name__
return {INFO_MEMBER: get_info(descr=descr)}
if hasattr(type(ob), "bl_rna"):
return g_bpy_types[type(ob)]
if "bl_rna" in dir(ob):
return g_bpy_types[ob]
result = {}
descr = member_info.__doc__ if member_info.__doc__ else type(ob).__name__
result[INFO_MEMBER] = get_info(descr=descr)
for name in dir(ob):
if name.startswith("_"):
continue
if is_member_inherited(ob, name):
continue
ob_member = getattr(ob, name, None)
if ob_member == parent:
descr = type(parent).__name__
result[name] = {INFO_MEMBER: get_info(descr=descr)}
continue
if ob_member == os:
continue
if ob_member == bpy:
continue
if ob_member == bpy_types:
continue
if ob_member == addon_utils:
continue
if ob_member == sys:
continue
if name == "addon_install":
# This raises a Error
continue
result[name] = get_doc_recursive(ob, name)
return result
##################################################################
def print_doc_recursive(map, indent, name, max_step=3):
time.sleep(.5)
prefix = indent * '|'
print(prefix + name)
for key, val in map.items():
if key == INFO_MEMBER:
print(prefix + val.replace('\n', '\n' + prefix) + '\n' + prefix)
elif indent < max_step:
name_next = name + '.' + key
if isinstance(val, list):
print_doc_recursive(val[0], indent + 1,
name_next + "[0]", max_step=max_step)
else:
print_doc_recursive(
val, indent + 1, name_next, max_step=max_step)
def main():
print("-------------------------------------------------------------")
bpy_types_first_step()
bpy_types_second_step()
members = (
"app",
"context",
"data",
"msgbus",
"ops",
"path",
"props",
"types",
"utils",
)
result = {
"bpy": {INFO_MEMBER: get_info(descr=bpy.__doc__)},
"__info": {"bases": None},
}
for member in members:
result["bpy"][member] = get_doc_recursive(bpy, member)
# Reference some types at the beginning
result["bpy_struct"] = result["bpy"]["types"]["bpy_struct"]
result["bpy_types"] = result["bpy"]["types"]
if False:
print(result["bpy"]["props"]["BoolProperty"])
return
# print_doc_recursive(result, 1, "bpy")
bpy_doc_dir = "D:/Dev/function-calling/routersbpy_doc_v41.pkl"
with open(bpy_doc_dir, "wb") as file:
# print(result["types"]["bpy_func"])
pickle.dump(result, file, protocol=pickle.HIGHEST_PROTOCOL)
print(f"File '{bpy_doc_dir}' has been updated.")
if __name__ == '__main__':
main()