|
Blender
V2.59
|
00001 #!/usr/bin/env python 00002 00003 # $Id: dump_rna2xml.py 35260 2011-02-28 12:05:43Z campbellbarton $ 00004 # ***** BEGIN GPL LICENSE BLOCK ***** 00005 # 00006 # This program is free software; you can redistribute it and/or 00007 # modify it under the terms of the GNU General Public License 00008 # as published by the Free Software Foundation; either version 2 00009 # of the License, or (at your option) any later version. 00010 # 00011 # This program is distributed in the hope that it will be useful, 00012 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 # GNU General Public License for more details. 00015 # 00016 # You should have received a copy of the GNU General Public License 00017 # along with this program; if not, write to the Free Software Foundation, 00018 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 # 00020 # Contributor(s): Campbell Barton 00021 # 00022 # ***** END GPL LICENSE BLOCK ***** 00023 00024 # <pep8 compliant> 00025 00026 # This script dumps rna into xml. 00027 # useful for finding bugs in RNA api. 00028 00029 # Example usage 00030 # blender some.blend -b -P intern/tools/dump_rna2xml.py 00031 00032 import bpy 00033 00034 invalid_classes = (bpy.types.Operator, 00035 bpy.types.Panel, 00036 bpy.types.KeyingSet, 00037 bpy.types.Header) 00038 00039 00040 def build_property_typemap(): 00041 00042 property_typemap = {} 00043 00044 for attr in dir(bpy.types): 00045 cls = getattr(bpy.types, attr) 00046 if issubclass(cls, invalid_classes): 00047 continue 00048 00049 properties = cls.bl_rna.properties.keys() 00050 properties.remove("rna_type") 00051 property_typemap[attr] = properties 00052 00053 return property_typemap 00054 00055 00056 def print_ln(data): 00057 print(data, end="") 00058 00059 00060 def rna2xml(fw=print_ln, ident_val=" "): 00061 from xml.sax.saxutils import quoteattr 00062 property_typemap = build_property_typemap() 00063 00064 def rna2xml_node(ident, value, parent): 00065 ident_next = ident + ident_val 00066 00067 # divide into attrs and nodes. 00068 node_attrs = [] 00069 nodes_items = [] 00070 nodes_lists = [] 00071 00072 value_type = type(value) 00073 00074 if issubclass(value_type, invalid_classes): 00075 return 00076 00077 # XXX, fixme, pointcache has eternal nested pointer to its self. 00078 if value == parent: 00079 return 00080 00081 value_type_name = value_type.__name__ 00082 for prop in property_typemap[value_type_name]: 00083 00084 subvalue = getattr(value, prop) 00085 subvalue_type = type(subvalue) 00086 00087 if subvalue_type == int: 00088 node_attrs.append("%s=\"%d\"" % (prop, subvalue)) 00089 elif subvalue_type == float: 00090 node_attrs.append("%s=\"%.4g\"" % (prop, subvalue)) 00091 elif subvalue_type == bool: 00092 node_attrs.append("%s=\"%s\"" % (prop, "TRUE" if subvalue else "FALSE")) 00093 elif subvalue_type is str: 00094 node_attrs.append("%s=%s" % (prop, quoteattr(subvalue))) 00095 elif subvalue_type == set: 00096 node_attrs.append("%s=%s" % (prop, quoteattr("{" + ",".join(list(subvalue)) + "}"))) 00097 elif subvalue is None: 00098 node_attrs.append("%s=\"NONE\"" % prop) 00099 elif issubclass(subvalue_type, bpy.types.ID): 00100 # special case, ID's are always referenced. 00101 node_attrs.append("%s=%s" % (prop, quoteattr(subvalue_type.__name__ + ":" + subvalue.name))) 00102 else: 00103 try: 00104 subvalue_ls = list(subvalue) 00105 except: 00106 subvalue_ls = None 00107 00108 if subvalue_ls is None: 00109 nodes_items.append((prop, subvalue, subvalue_type)) 00110 else: 00111 # check if the list contains native types 00112 subvalue_rna = value.path_resolve(prop, False) 00113 if type(subvalue_rna).__name__ == "bpy_prop_array": 00114 # TODO, multi-dim! 00115 def str_recursive(s): 00116 if type(s) in (int, float, bool): 00117 return str(s) 00118 else: 00119 return " ".join([str_recursive(si) for si in s]) 00120 00121 node_attrs.append("%s=\"%s\"" % (prop, " ".join(str_recursive(v) for v in subvalue_rna))) 00122 else: 00123 nodes_lists.append((prop, subvalue_ls, subvalue_type)) 00124 00125 # declare + attributes 00126 fw("%s<%s %s>\n" % (ident, value_type_name, " ".join(node_attrs))) 00127 00128 # unique members 00129 for prop, subvalue, subvalue_type in nodes_items: 00130 rna2xml_node(ident_next, subvalue, value) 00131 00132 # list members 00133 for prop, subvalue, subvalue_type in nodes_lists: 00134 fw("%s<%s>\n" % (ident_next, prop)) 00135 for subvalue_item in subvalue: 00136 if subvalue_item is not None: 00137 rna2xml_node(ident_next + ident_val, subvalue_item, value) 00138 fw("%s</%s>\n" % (ident_next, prop)) 00139 00140 fw("%s</%s>\n" % (ident, value_type_name)) 00141 00142 fw("<root>\n") 00143 for attr in dir(bpy.data): 00144 00145 # exceptions 00146 if attr.startswith("_"): 00147 continue 00148 elif attr == "window_managers": 00149 continue 00150 00151 value = getattr(bpy.data, attr) 00152 try: 00153 ls = value[:] 00154 except: 00155 ls = None 00156 00157 if type(ls) == list: 00158 fw("%s<%s>\n" % (ident_val, attr)) 00159 for blend_id in ls: 00160 rna2xml_node(ident_val + ident_val, blend_id, None) 00161 fw("%s</%s>\n" % (ident_val, attr)) 00162 00163 fw("</root>\n") 00164 00165 00166 def main(): 00167 filename = bpy.data.filepath.rstrip(".blend") + ".xml" 00168 file = open(filename, 'w') 00169 rna2xml(file.write) 00170 file.close() 00171 00172 # read back. 00173 from xml.dom.minidom import parse 00174 xml_nodes = parse(filename) 00175 print("Written:", filename) 00176 00177 if __name__ == "__main__": 00178 main()