|
Blender
V2.59
|
00001 #!/usr/bin/env python 00002 00003 # $Id: bpy_introspect_ui.py 34890 2011-02-16 02:51:56Z 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 ui definitions as XML. 00027 # useful for finding bad api usage. 00028 00029 # Example usage: 00030 # python intern/tools/bpy_introspect_ui.py 00031 00032 import sys 00033 ModuleType = type(sys) 00034 00035 00036 def module_add(name): 00037 mod = sys.modules[name] = ModuleType(name) 00038 return mod 00039 00040 00041 class AttributeBuilder(object): 00042 """__slots__ = ( 00043 "_attr", "_attr_list", "_item_set", "_args", 00044 "active", "operator_context", "enabled", "index", "data" 00045 )""" 00046 00047 def _as_py(self): 00048 data = [self._attr_single, self._args, [child._as_py() for child in self._attr_list]] 00049 return data 00050 00051 def _as_xml(self, indent=" "): 00052 00053 def to_xml_str(value): 00054 if type(value) == str: 00055 # quick shoddy clean 00056 value = value.replace("&", " ") 00057 value = value.replace("<", " ") 00058 value = value.replace(">", " ") 00059 00060 return '"' + value + '"' 00061 else: 00062 return '"' + str(value) + '"' 00063 00064 def dict_to_kw(args, dict_args): 00065 args_str = "" 00066 if args: 00067 # args_str += " ".join([to_xml_str(a) for a in args]) 00068 for i, a in enumerate(args): 00069 args_str += "arg" + str(i + 1) + "=" + to_xml_str(a) + " " 00070 00071 if dict_args: 00072 args_str += " ".join(["%s=%s" % (key, to_xml_str(value)) for key, value in sorted(dict_args.items())]) 00073 00074 if args_str: 00075 return " " + args_str 00076 00077 return "" 00078 00079 lines = [] 00080 00081 def py_to_xml(item, indent_ctx): 00082 if item._attr_list: 00083 lines.append("%s<%s%s>" % (indent_ctx, item._attr_single, dict_to_kw(item._args_tuple, item._args))) 00084 for child in item._attr_list: 00085 # print(child._attr) 00086 py_to_xml(child, indent_ctx + indent) 00087 lines.append("%s</%s>" % (indent_ctx, item._attr_single)) 00088 else: 00089 lines.append("%s<%s%s/>" % (indent_ctx, item._attr_single, dict_to_kw(item._args_tuple, item._args))) 00090 00091 py_to_xml(self, indent) 00092 00093 return "\n".join(lines) 00094 00095 def __init__(self, attr, attr_single): 00096 self._attr = attr 00097 self._attr_single = attr_single 00098 self._attr_list = [] 00099 self._item_set = [] 00100 self._args = {} 00101 self._args_tuple = () 00102 00103 def __call__(self, *args, **kwargs): 00104 # print(self._attr, args, kwargs) 00105 self._args_tuple = args 00106 self._args = kwargs 00107 return self 00108 00109 def __getattr__(self, attr): 00110 attr_obj = NewAttr(self._attr + "." + attr, attr) 00111 self._attr_list.append(attr_obj) 00112 return attr_obj 00113 00114 # def __setattr__(self, attr, value): 00115 # setatte 00116 00117 def __getitem__(self, item): 00118 item_obj = NewAttr(self._attr + "[" + repr(item) + "]", item) 00119 self._item_set.append(item_obj) 00120 return item_obj 00121 00122 def __setitem__(self, item, value): 00123 pass # TODO? 00124 00125 def __repr__(self): 00126 return self._attr 00127 00128 def __iter__(self): 00129 return iter([]) 00130 00131 #def __len__(self): 00132 # return 0 00133 00134 def __int__(self): 00135 return 0 00136 00137 def __cmp__(self, other): 00138 return -1 00139 00140 def __lt__(self, other): 00141 return -1 00142 00143 def __gt__(self, other): 00144 return -1 00145 00146 def __le__(self, other): 00147 return -1 00148 00149 def __add__(self, other): 00150 return self 00151 00152 def __sub__(self, other): 00153 return self 00154 00155 # Custom functions 00156 def lower(self): 00157 return "" 00158 00159 def upper(self): 00160 return "" 00161 00162 def keys(self): 00163 return [] 00164 00165 00166 def NewAttr(attr, attr_single): 00167 obj = AttributeBuilder(attr, attr_single) 00168 return obj 00169 00170 00171 class BaseFakeUI(): 00172 def __init__(self): 00173 self.layout = NewAttr("self.layout", "layout") 00174 00175 00176 class Panel(BaseFakeUI): 00177 pass 00178 00179 00180 class Header(BaseFakeUI): 00181 pass 00182 00183 00184 class Menu(BaseFakeUI): 00185 def draw_preset(self, context): 00186 pass 00187 00188 def path_menu(self, a, b, c): 00189 pass 00190 00191 00192 class Operator(BaseFakeUI): 00193 pass 00194 00195 00196 class PropertyGroup(): 00197 pass 00198 00199 00200 # setup fake module 00201 def fake_main(): 00202 bpy = module_add("bpy") 00203 00204 bpy.types = module_add("bpy.types") 00205 bpy.types.Panel = Panel 00206 bpy.types.Header = Header 00207 bpy.types.Menu = Menu 00208 bpy.types.PropertyGroup = PropertyGroup 00209 bpy.types.Operator = Operator 00210 00211 bpy.types.Armature = type("Armature", (), {}) 00212 bpy.types.Bone = type("Bone", (), {}) 00213 bpy.types.EditBone = type("EditBone", (), {}) 00214 bpy.types.PoseBone = type("PoseBone", (), {}) 00215 bpy.types.Material = type("Material", (), {}) 00216 bpy.types.Lamp = type("Lamp", (), {}) 00217 bpy.types.Camera = type("Camera", (), {}) 00218 bpy.types.Curve = type("Curve", (), {}) 00219 bpy.types.Lattice = type("Lattice", (), {}) 00220 bpy.types.Mesh = type("Mesh", (), {}) 00221 bpy.types.MetaBall = type("MetaBall", (), {}) 00222 bpy.types.Object = type("Object", (), {}) 00223 bpy.types.Texture = type("Texture", (), {}) 00224 bpy.types.ParticleSettings = type("ParticleSettings", (), {}) 00225 bpy.types.World = type("World", (), {}) 00226 bpy.types.Brush = type("Brush", (), {}) 00227 bpy.types.WindowManager = type("WindowManager", (), {}) 00228 bpy.types.Scene = type("Scene", (), {}) 00229 bpy.types.Scene.EnumProperty = NewAttr("bpy.types.Scene.EnumProperty", "EnumProperty") 00230 bpy.types.Scene.StringProperty = NewAttr("bpy.types.Scene.StringProperty", "StringProperty") 00231 00232 bpy.props = module_add("bpy.props") 00233 bpy.props.StringProperty = dict 00234 bpy.props.BoolProperty = dict 00235 bpy.props.IntProperty = dict 00236 bpy.props.EnumProperty = dict 00237 00238 bpy.data = module_add("bpy.data") 00239 bpy.data.scenes = () 00240 bpy.data.groups = () 00241 bpy.data.meshes = () 00242 bpy.data.shape_keys = () 00243 bpy.data.materials = () 00244 bpy.data.lamps = () 00245 bpy.data.textures = () 00246 bpy.data.cameras = () 00247 bpy.data.curves = () 00248 bpy.data.metaballs = () 00249 bpy.data.armatures = () 00250 bpy.data.particles = () 00251 00252 bpy.data.file_is_saved = True 00253 00254 bpy.utils = module_add("bpy.utils") 00255 bpy.utils.smpte_from_frame = lambda f: "" 00256 bpy.utils.script_paths = lambda f: [] 00257 00258 bpy.app = module_add("bpy.app") 00259 bpy.app.debug = False 00260 bpy.app.version = 2, 55, 1 00261 00262 bpy.path = module_add("bpy.path") 00263 bpy.path.display_name = lambda f: "" 00264 00265 00266 def fake_helper(): 00267 00268 class PropertyPanel(): 00269 pass 00270 00271 rna_prop_ui = module_add("rna_prop_ui") 00272 rna_prop_ui.PropertyPanel = PropertyPanel 00273 rna_prop_ui.draw = NewAttr("rna_prop_ui.draw", "draw") 00274 00275 rigify = module_add("rigify") 00276 rigify.get_submodule_types = lambda: [] 00277 00278 00279 fake_main() 00280 fake_helper() 00281 00282 import bpy 00283 00284 sys.path.insert(0, "/b/release/scripts/ui/") 00285 00286 00287 def module_classes(mod): 00288 classes = [] 00289 for value in mod.__dict__.values(): 00290 try: 00291 is_subclass = issubclass(value, BaseFakeUI) 00292 except: 00293 is_subclass = False 00294 00295 if is_subclass: 00296 classes.append(value) 00297 00298 return classes 00299 00300 00301 def main(): 00302 import os 00303 00304 base = os.path.join(os.path.dirname(__file__), "..", "..") 00305 base = os.path.normpath(base) 00306 base = os.path.abspath(base) 00307 00308 scripts_dir = os.path.join(base, "release", "scripts", "ui") 00309 for f in sorted(os.listdir(scripts_dir)): 00310 if f.endswith(".py"): 00311 # print(f) 00312 mod = __import__(f[:-3]) 00313 00314 classes = module_classes(mod) 00315 00316 for cls in classes: 00317 setattr(bpy.types, cls.__name__, cls) 00318 00319 # print("running...") 00320 print("<ui>") 00321 for f in sorted(os.listdir(scripts_dir)): 00322 if f.endswith(".py"): 00323 # print(f) 00324 mod = __import__(f[:-3]) 00325 00326 classes = module_classes(mod) 00327 00328 for cls in classes: 00329 # want to check if the draw function is directly in the class 00330 # print("draw") 00331 if "draw" in cls.__dict__: 00332 self = cls() 00333 self.draw(NewAttr("context", "context")) 00334 # print(self.layout._as_py()) 00335 self.layout._args['id'] = mod.__name__ + "." + cls.__name__ 00336 print(self.layout._as_xml()) 00337 print("</ui>") 00338 00339 00340 if __name__ == "__main__": 00341 main()