forked from bartvdbraak/blender
utility module for introspecting RNA for doc generation.
This commit is contained in:
parent
3e23f002b4
commit
7e8af5868e
355
release/scripts/modules/rna_info.py
Normal file
355
release/scripts/modules/rna_info.py
Normal file
@ -0,0 +1,355 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# classes for extracting info from blenders internal classes
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
class InfoStructRNA:
|
||||
global_lookup = {}
|
||||
def __init__(self, rna_type):
|
||||
self.bl_rna = rna_type
|
||||
|
||||
self.identifier = rna_type.identifier
|
||||
self.name = rna_type.name
|
||||
self.description = rna_type.description.strip()
|
||||
|
||||
# set later
|
||||
self.base = None
|
||||
self.nested = None
|
||||
self.full_path = ""
|
||||
|
||||
self.functions = []
|
||||
self.children = []
|
||||
self.references = []
|
||||
self.properties = []
|
||||
|
||||
def build(self):
|
||||
rna_type = self.bl_rna
|
||||
parent_id = self.identifier
|
||||
self.properties[:] = [GetInfoPropertyRNA(rna_prop, parent_id) for rna_prop in rna_type.properties.values()]
|
||||
self.functions[:] = [GetInfoFunctionRNA(rna_prop, parent_id) for rna_prop in rna_type.functions.values()]
|
||||
|
||||
def getNestedProperties(self, ls = None):
|
||||
if not ls:
|
||||
ls = self.properties[:]
|
||||
|
||||
if self.nested:
|
||||
self.nested.getNestedProperties(ls)
|
||||
|
||||
return ls
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
txt = ''
|
||||
txt += self.identifier
|
||||
if self.base:
|
||||
txt += '(%s)' % self.base.identifier
|
||||
txt += ': ' + self.description + '\n'
|
||||
|
||||
for prop in self.properties:
|
||||
txt += prop.__repr__() + '\n'
|
||||
|
||||
for func in self.functions:
|
||||
txt += func.__repr__() + '\n'
|
||||
|
||||
return txt
|
||||
|
||||
|
||||
class InfoPropertyRNA:
|
||||
global_lookup = {}
|
||||
def __init__(self, rna_prop):
|
||||
self.bl_prop = rna_prop
|
||||
self.identifier = rna_prop.identifier
|
||||
self.name = rna_prop.name
|
||||
self.description = rna_prop.description.strip()
|
||||
|
||||
def build(self):
|
||||
rna_prop = self.bl_prop
|
||||
|
||||
self.enum_items = []
|
||||
self.min = -1
|
||||
self.max = -1
|
||||
self.array_length = getattr(rna_prop, "array_length", 0)
|
||||
|
||||
self.type = rna_prop.type.lower()
|
||||
self.fixed_type = GetInfoStructRNA(rna_prop.fixed_type) # valid for pointer/collections
|
||||
self.srna = GetInfoStructRNA(rna_prop.srna) # valid for pointer/collections
|
||||
|
||||
def __repr__(self):
|
||||
txt = ''
|
||||
txt += ' * ' + self.identifier + ': ' + self.description
|
||||
|
||||
return txt
|
||||
|
||||
class InfoFunctionRNA:
|
||||
global_lookup = {}
|
||||
def __init__(self, rna_func):
|
||||
self.bl_func = rna_func
|
||||
self.identifier = rna_func.identifier
|
||||
# self.name = rna_func.name # functions have no name!
|
||||
self.description = rna_func.description.strip()
|
||||
|
||||
self.args = [] # todo
|
||||
self.return_value = None # todo
|
||||
|
||||
def build(self):
|
||||
rna_prop = self.bl_prop
|
||||
pass
|
||||
|
||||
def __repr__(self):
|
||||
txt = ''
|
||||
txt += ' * ' + self.identifier + '('
|
||||
|
||||
for arg in self.args:
|
||||
txt += arg.identifier + ', '
|
||||
txt += '): ' + self.description
|
||||
return txt
|
||||
|
||||
|
||||
def _GetInfoRNA(bl_rna, cls, parent_id=''):
|
||||
|
||||
if bl_rna == None:
|
||||
return None
|
||||
|
||||
key = parent_id, bl_rna.identifier
|
||||
try:
|
||||
return cls.global_lookup[key]
|
||||
except:
|
||||
instance = cls.global_lookup[key] = cls(bl_rna)
|
||||
return instance
|
||||
|
||||
|
||||
def GetInfoStructRNA(bl_rna):
|
||||
return _GetInfoRNA(bl_rna, InfoStructRNA)
|
||||
|
||||
def GetInfoPropertyRNA(bl_rna, parent_id):
|
||||
return _GetInfoRNA(bl_rna, InfoPropertyRNA, parent_id)
|
||||
|
||||
def GetInfoFunctionRNA(bl_rna, parent_id):
|
||||
return _GetInfoRNA(bl_rna, InfoFunctionRNA, parent_id)
|
||||
|
||||
|
||||
def BuildRNAInfo():
|
||||
# Use for faster lookups
|
||||
# use rna_struct.identifier as the key for each dict
|
||||
rna_struct_dict = {} # store identifier:rna lookups
|
||||
rna_full_path_dict = {} # store the result of full_rna_struct_path(rna_struct)
|
||||
rna_children_dict = {} # store all rna_structs nested from here
|
||||
rna_references_dict = {} # store a list of rna path strings that reference this type
|
||||
rna_functions_dict = {} # store all functions directly in this type (not inherited)
|
||||
rna_words = set()
|
||||
|
||||
def rna_id_ignore(rna_id):
|
||||
if rna_id == "rna_type":
|
||||
return True
|
||||
|
||||
if "_OT_" in rna_id:
|
||||
return True
|
||||
if "_MT_" in rna_id:
|
||||
return True
|
||||
if "_PT_" in rna_id:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def full_rna_struct_path(rna_struct):
|
||||
'''
|
||||
Needed when referencing one struct from another
|
||||
'''
|
||||
nested = rna_struct.nested
|
||||
if nested:
|
||||
return "%s.%s" % (full_rna_struct_path(nested), rna_struct.identifier)
|
||||
else:
|
||||
return rna_struct.identifier
|
||||
|
||||
# def write_func(rna_func, ident):
|
||||
def base_id(rna_struct):
|
||||
try: return rna_struct.base.identifier
|
||||
except: return '' # invalid id
|
||||
|
||||
#structs = [(base_id(rna_struct), rna_struct.identifier, rna_struct) for rna_struct in bpy.doc.structs.values()]
|
||||
'''
|
||||
structs = []
|
||||
for rna_struct in bpy.doc.structs.values():
|
||||
structs.append( (base_id(rna_struct), rna_struct.identifier, rna_struct) )
|
||||
'''
|
||||
structs = []
|
||||
for rna_type_name in dir(bpy.types):
|
||||
rna_type = getattr(bpy.types, rna_type_name)
|
||||
|
||||
try: rna_struct = rna_type.bl_rna
|
||||
except: rna_struct = None
|
||||
|
||||
if rna_struct:
|
||||
#if not rna_type_name.startswith('__'):
|
||||
|
||||
identifier = rna_struct.identifier
|
||||
|
||||
if not rna_id_ignore(identifier):
|
||||
structs.append( (base_id(rna_struct), identifier, rna_struct) )
|
||||
|
||||
# Simple lookup
|
||||
rna_struct_dict[identifier] = rna_struct
|
||||
|
||||
# Store full rna path 'GameObjectSettings' -> 'Object.GameObjectSettings'
|
||||
rna_full_path_dict[identifier] = full_rna_struct_path(rna_struct)
|
||||
|
||||
# Store a list of functions, remove inherited later
|
||||
rna_functions_dict[identifier]= list(rna_struct.functions)
|
||||
|
||||
|
||||
# fill in these later
|
||||
rna_children_dict[identifier]= []
|
||||
rna_references_dict[identifier]= []
|
||||
|
||||
|
||||
else:
|
||||
print("Ignoring", rna_type_name)
|
||||
|
||||
|
||||
# Sucks but we need to copy this so we can check original parent functions
|
||||
rna_functions_dict__copy = {}
|
||||
for key, val in rna_functions_dict.items():
|
||||
rna_functions_dict__copy[key] = val[:]
|
||||
|
||||
|
||||
structs.sort() # not needed but speeds up sort below, setting items without an inheritance first
|
||||
|
||||
# Arrange so classes are always defined in the correct order
|
||||
deps_ok = False
|
||||
while deps_ok == False:
|
||||
deps_ok = True
|
||||
rna_done = set()
|
||||
|
||||
for i, (rna_base, identifier, rna_struct) in enumerate(structs):
|
||||
|
||||
rna_done.add(identifier)
|
||||
|
||||
if rna_base and rna_base not in rna_done:
|
||||
deps_ok = False
|
||||
data = structs.pop(i)
|
||||
ok = False
|
||||
while i < len(structs):
|
||||
if structs[i][1]==rna_base:
|
||||
structs.insert(i+1, data) # insert after the item we depend on.
|
||||
ok = True
|
||||
break
|
||||
i+=1
|
||||
|
||||
if not ok:
|
||||
print('Dependancy "%s" could not be found for "%s"' % (identifier, rna_base))
|
||||
|
||||
break
|
||||
|
||||
# Done ordering structs
|
||||
|
||||
|
||||
# precalc vars to avoid a lot of looping
|
||||
for (rna_base, identifier, rna_struct) in structs:
|
||||
|
||||
if rna_base:
|
||||
rna_base_prop_keys = rna_struct_dict[rna_base].properties.keys() # could cache
|
||||
rna_base_func_keys = [f.identifier for f in rna_struct_dict[rna_base].functions]
|
||||
else:
|
||||
rna_base_prop_keys = []
|
||||
rna_base_func_keys= []
|
||||
|
||||
# rna_struct_path = full_rna_struct_path(rna_struct)
|
||||
rna_struct_path = rna_full_path_dict[identifier]
|
||||
|
||||
for rna_prop_identifier, rna_prop in rna_struct.properties.items():
|
||||
|
||||
if rna_prop_identifier=='RNA': continue
|
||||
if rna_id_ignore(rna_prop_identifier): continue
|
||||
if rna_prop_identifier in rna_base_prop_keys: continue
|
||||
|
||||
|
||||
for rna_prop_ptr in (getattr(rna_prop, "fixed_type", None), getattr(rna_prop, "srna", None)):
|
||||
# Does this property point to me?
|
||||
if rna_prop_ptr:
|
||||
rna_references_dict[rna_prop_ptr.identifier].append( "%s.%s" % (rna_struct_path, rna_prop_identifier) )
|
||||
|
||||
for rna_func in rna_struct.functions:
|
||||
for rna_prop_identifier, rna_prop in rna_func.parameters.items():
|
||||
|
||||
if rna_prop_identifier=='RNA': continue
|
||||
if rna_id_ignore(rna_prop_identifier): continue
|
||||
if rna_prop_identifier in rna_base_func_keys: continue
|
||||
|
||||
|
||||
try: rna_prop_ptr = rna_prop.fixed_type
|
||||
except: rna_prop_ptr = None
|
||||
|
||||
# Does this property point to me?
|
||||
if rna_prop_ptr:
|
||||
rna_references_dict[rna_prop_ptr.identifier].append( "%s.%s" % (rna_struct_path, rna_func.identifier) )
|
||||
|
||||
|
||||
# Store nested children
|
||||
nested = rna_struct.nested
|
||||
if nested:
|
||||
rna_children_dict[nested.identifier].append(rna_struct)
|
||||
|
||||
|
||||
if rna_base:
|
||||
rna_funcs = rna_functions_dict[identifier]
|
||||
if rna_funcs:
|
||||
# Remove inherited functions if we have any
|
||||
rna_base_funcs = rna_functions_dict__copy[rna_base]
|
||||
rna_funcs[:] = [f for f in rna_funcs if f not in rna_base_funcs]
|
||||
|
||||
rna_functions_dict__copy.clear()
|
||||
del rna_functions_dict__copy
|
||||
|
||||
# Sort the refs, just reads nicer
|
||||
for rna_refs in rna_references_dict.values():
|
||||
rna_refs.sort()
|
||||
|
||||
|
||||
info_structs = []
|
||||
for (rna_base, identifier, rna_struct) in structs:
|
||||
#if rna_struct.nested:
|
||||
# continue
|
||||
|
||||
#write_struct(rna_struct, '')
|
||||
info_struct= GetInfoStructRNA(rna_struct)
|
||||
if rna_base:
|
||||
info_struct.base = GetInfoStructRNA(rna_struct_dict[rna_base])
|
||||
info_struct.nested = GetInfoStructRNA(rna_struct.nested)
|
||||
info_struct.children[:] = rna_children_dict[identifier]
|
||||
info_struct.references[:] = rna_references_dict[identifier]
|
||||
info_struct.full_path = rna_full_path_dict[identifier]
|
||||
|
||||
info_structs.append(info_struct)
|
||||
|
||||
for rna_info_prop in InfoPropertyRNA.global_lookup.values():
|
||||
rna_info_prop.build()
|
||||
|
||||
for rna_info_prop in InfoFunctionRNA.global_lookup.values():
|
||||
rna_info_prop.build()
|
||||
|
||||
for rna_info in InfoStructRNA.global_lookup.values():
|
||||
rna_info.build()
|
||||
|
||||
for rna_info in InfoStructRNA.global_lookup.values():
|
||||
print(rna_info)
|
||||
|
||||
return InfoStructRNA.global_lookup, InfoFunctionRNA.global_lookup, InfoPropertyRNA.global_lookup
|
||||
|
Loading…
Reference in New Issue
Block a user