Blender  V2.59
dump_rna2xml.py
Go to the documentation of this file.
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()