Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'release/scripts/modules/rna_info.py')
-rw-r--r--release/scripts/modules/rna_info.py559
1 files changed, 559 insertions, 0 deletions
diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py
new file mode 100644
index 00000000000..2a70feec9dd
--- /dev/null
+++ b/release/scripts/modules/rna_info.py
@@ -0,0 +1,559 @@
+# ##### 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
+
+# use to strip python paths
+script_paths = bpy.utils.script_paths()
+
+def range_str(val):
+ if val < -10000000: return '-inf'
+ if val > 10000000: return 'inf'
+ if type(val)==float:
+ return '%g' % val
+ else:
+ return str(val)
+
+def float_as_string(f):
+ val_str = "%g" % f
+ if '.' not in val_str and '-' not in val_str: # value could be 1e-05
+ val_str += '.0'
+ return val_str
+
+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_id, rna_prop in rna_type.properties.items() if rna_id != "rna_type"]
+ self.functions[:] = [GetInfoFunctionRNA(rna_prop, parent_id) for rna_prop in rna_type.functions.values()]
+
+ def get_bases(self):
+ bases = []
+ item = self
+
+ while item:
+ item = item.base
+ if item:
+ bases.append(item)
+
+ return bases
+
+ def get_nested_properties(self, ls = None):
+ if not ls:
+ ls = self.properties[:]
+
+ if self.nested:
+ self.nested.get_nested_properties(ls)
+
+ return ls
+
+ def _get_py_visible_attrs(self):
+ attrs = []
+ py_class = getattr(bpy.types, self.identifier)
+ for attr_str in dir(py_class):
+ if attr_str.startswith("_"):
+ continue
+ attrs.append((attr_str, getattr(py_class, attr_str)))
+ return attrs
+
+
+ def get_py_properties(self):
+ properties = []
+ for identifier, attr in self._get_py_visible_attrs():
+ if type(attr) is property:
+ properties.append((identifier, attr))
+ return properties
+
+ def get_py_functions(self):
+ import types
+ functions = []
+ for identifier, attr in self._get_py_visible_attrs():
+ if type(attr) is types.FunctionType:
+ functions.append((identifier, attr))
+ return functions
+
+ 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()
+ self.default_str = "<UNKNOWN>"
+
+ def build(self):
+ rna_prop = self.bl_prop
+
+ self.enum_items = []
+ self.min = getattr(rna_prop, "hard_min", -1)
+ self.max = getattr(rna_prop, "hard_max", -1)
+ self.array_length = getattr(rna_prop, "array_length", 0)
+ self.collection_type = GetInfoStructRNA(rna_prop.srna)
+ self.is_required = rna_prop.is_required
+ self.is_readonly = rna_prop.is_readonly
+ self.is_never_none = rna_prop.is_never_none
+
+ self.type = rna_prop.type.lower()
+ fixed_type = getattr(rna_prop, "fixed_type", "")
+ if fixed_type:
+ self.fixed_type = GetInfoStructRNA(fixed_type) # valid for pointer/collections
+ else:
+ self.fixed_type = None
+
+ if self.type == "enum":
+ self.enum_items[:] = rna_prop.items.keys()
+
+ if self.array_length:
+ self.default = tuple(getattr(rna_prop, "default_array", ()))
+ self.default_str = ''
+ # special case for floats
+ if len(self.default) > 0:
+ if type(self.default[0]) is float:
+ self.default_str = "(%s)" % ", ".join([float_as_string(f) for f in self.default])
+ if not self.default_str:
+ self.default_str = str(self.default)
+ else:
+ self.default = getattr(rna_prop, "default", "")
+ if type(self.default) is float:
+ self.default_str = float_as_string(self.default)
+ else:
+ self.default_str = str(self.default)
+
+ self.srna = GetInfoStructRNA(rna_prop.srna) # valid for pointer/collections
+
+ def get_default_string(self):
+ # pointer has no default, just set as None
+ if self.type == "pointer":
+ return "None"
+ elif self.type == "string":
+ return '"' + self.default_str + '"'
+ elif self.type == "enum":
+ if self.default_str:
+ return "'" + self.default_str + "'"
+ else:
+ return ""
+
+ return self.default_str
+
+ def get_arg_default(self, force=True):
+ default = self.get_default_string()
+ if default and (force or self.is_required == False):
+ return "%s=%s" % (self.identifier, default)
+ return self.identifier
+
+ 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 = []
+ self.return_value = None
+
+ def build(self):
+ rna_func = self.bl_func
+ parent_id = rna_func
+
+ for rna_id, rna_prop in rna_func.parameters.items():
+ prop = GetInfoPropertyRNA(rna_prop, parent_id)
+ if rna_prop.use_return:
+ self.return_value = prop
+ else:
+ self.args.append(prop)
+
+ def __repr__(self):
+ txt = ''
+ txt += ' * ' + self.identifier + '('
+
+ for arg in self.args:
+ txt += arg.identifier + ', '
+ txt += '): ' + self.description
+ return txt
+
+
+class InfoOperatorRNA:
+ global_lookup = {}
+ def __init__(self, rna_op):
+ self.bl_op = rna_op
+ self.identifier = rna_op.identifier
+
+ mod, name = self.identifier.split("_OT_", 1)
+ self.module_name = mod.lower()
+ self.func_name = name
+
+ # self.name = rna_func.name # functions have no name!
+ self.description = rna_op.description.strip()
+
+ self.args = []
+
+ def build(self):
+ rna_op = self.bl_op
+ parent_id = self.identifier
+ for rna_id, rna_prop in rna_op.properties.items():
+ if rna_id == "rna_type":
+ continue
+
+ prop = GetInfoPropertyRNA(rna_prop, parent_id)
+ self.args.append(prop)
+
+ def get_location(self):
+ op_class = getattr(bpy.types, self.identifier)
+ op_func = getattr(op_class, "execute", None)
+ if op_func is None:
+ op_func = getattr(op_class, "invoke", None)
+ if op_func is None:
+ op_func = getattr(op_class, "poll", None)
+
+ if op_func:
+ op_code = op_func.__code__
+ source_path = op_code.co_filename
+
+ # clear the prefix
+ for p in script_paths:
+ source_path = source_path.split(p)[-1]
+
+ if source_path[0] in "/\\":
+ source_path= source_path[1:]
+
+ return source_path, op_code.co_firstlineno
+ else:
+ return None, None
+
+'''
+ 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 GetInfoOperatorRNA(bl_rna):
+ return _GetInfoRNA(bl_rna, InfoOperatorRNA)
+
+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
+ if "_HT_" 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 prop in rna_info.properties:
+ prop.build()
+ for func in rna_info.functions:
+ func.build()
+ for prop in func.args:
+ prop.build()
+ if func.return_value:
+ func.return_value.build()
+
+ # now for operators
+ op_mods = dir(bpy.ops)
+
+ for op_mod_name in sorted(op_mods):
+ if op_mod_name.startswith('__') or op_mod_name in ("add", "remove"):
+ continue
+
+ op_mod = getattr(bpy.ops, op_mod_name)
+ operators = dir(op_mod)
+ for op in sorted(operators):
+ try:
+ rna_prop = getattr(op_mod, op).get_rna()
+ except AttributeError:
+ rna_prop = None
+ except TypeError:
+ rna_prop = None
+
+ if rna_prop:
+ GetInfoOperatorRNA(rna_prop.bl_rna)
+
+ for rna_info in InfoOperatorRNA.global_lookup.values():
+ rna_info.build()
+ for rna_prop in rna_info.args:
+ rna_prop.build()
+
+
+ #for rna_info in InfoStructRNA.global_lookup.values():
+ # print(rna_info)
+
+ return InfoStructRNA.global_lookup, InfoFunctionRNA.global_lookup, InfoOperatorRNA.global_lookup, InfoPropertyRNA.global_lookup
+