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()