From BlenderWiki
Python RNA API
- Matches the C/RNA api structure
- Thin wrapper ~(3000 lines)
- No functions specific to any blender object type.
- Defines 2 types, BPy_StructRNA and BPy_PropertyRNA.
- Python 3.1 target
- Write access to data
- Subclasses are used for adding extra functionality through python.
- Collection iterators
- Call RNA functions
Collections
Collections may have their own functions and attributes, here is a list which should be used as a bases when extending collections for the RNA api.
- seq.active --> item or None active member of the collection.
- data = seq.new(name, type) / seq.remove(item)
Type optional when it can be changed after adding. - seq.link(data) / seq.unlink(data)
Exception if already linked or not linked when unlinking.
Todo
- Solve the "Python keeping invalid blender pointers" problem.
This cant just be solved in the py api - we need blender to notify when ID's are removed
Examples
Here are some examples that work with the current implementation of the api. Examples:
bpy.lamps["Lamp.006"].energy -> (1.0)
bpy.lamps["Lamp.007"].shadow -> ("NOSHADOW")
bpy.meshes["MyObject"]
bpy.materials.keys() -> ['flyingsquirrel_eye', 'frankie_skin', 'frankie_theeth']
bpy.meshes["mymesh"].uv_layers.keys() -> ['UVTex', 'UVTex']
bpy.scenes["hud"].objects["num_text_p2_4"].data.novnormalflip -> False
Notes
- "bpy" is as an arbitrary pytype, we can change it to anything.
- At the moment enum types are converted into python strings (as seen above with the lamps "NOSHADOW")
Dumping a blendfile with PyRNA
Here's a script that prints out all RNA data
PRINT_DATA = True VERBOSE = False VERBOSE_TYPE = False VERBOSE_DOCS = True SKIP_RECURSIVE = False def seek(r, txt): print(txt) newtxt = '' if len(txt) > 200: print ("Something is wrong") print (txt) return # basic types if type(r) in (float, int, bool, type(None)): if PRINT_DATA: print(txt + ' -> ' + str(r)) return if type(r) == str: if PRINT_DATA: print(txt + ' -> "' + str(r) + '"') return if VERBOSE_DOCS and PRINT_DATA: try: print(r.__doc__) except: pass try: keys = r.keys() except: keys = None if keys != None: if PRINT_DATA: print(txt + '.keys() - ' + str(r.keys())) try: __members__ = r.__members__ except: __members__ = [] for item in __members__: if PRINT_DATA: newtxt = txt + '.' + item if item == 'rna_type' and not VERBOSE_TYPE: # just avoid because it spits out loads of data continue if SKIP_RECURSIVE: if item in txt: if PRINT_DATA: print(newtxt + ' - (skipping to avoid recursive search)') continue seek( getattr(r, item), newtxt) if keys: for k in keys: if PRINT_DATA: newtxt = txt + '["' + k + '"]' seek(r[k], newtxt) else: try: length = len( r ) except: length = 0 if not VERBOSE and length >= 4: for i in (0, length-1): if i>0: if PRINT_DATA: print((' '*len(txt)) + ' ... skipping '+str(length-2)+' items ...') if PRINT_DATA: newtxt = txt + '[' + str(i) + ']' seek(r[i], newtxt) else: for i in range(length): if PRINT_DATA: newtxt = txt + '[' + str(i) + ']' seek(r[i], newtxt) seek(bpy, 'bpy') import sys sys.exit()
Extract of a file dump, see yo-frankie level dump here [1]
bpy.lamps["Lamp.004"].name -> "Lamp.004" bpy.lamps["Lamp.004"].color[0] -> 1.0 bpy.lamps["Lamp.004"].color[1] -> 1.0 bpy.lamps["Lamp.004"].color[2] -> 1.0 bpy.lamps["Lamp.004"].dist -> 20.0 bpy.lamps["Lamp.004"].energy -> 1.0 bpy.lamps["Lamp.004"].shadow -> "NOSHADOW" bpy.lamps["Lamp.004"].type -> "LOCAL" bpy.lamps["Lamp.006"].rna_type.rna_type - (skipping to avoid recursive search) bpy.lamps["Lamp.006"].rna_type.name -> "Lamp" bpy.lamps["Lamp.006"].rna_type.identifier -> "Lamp" bpy.lamps["Lamp.006"].rna_type.name_property.rna_type - (skipping to avoid recursive search) bpy.lamps["Lamp.006"].rna_type.name_property.name - (skipping to avoid recursive search) bpy.lamps["Lamp.006"].rna_type.name_property.description -> "Object ID name." bpy.lamps["Lamp.006"].rna_type.name_property.identifier -> "name" bpy.lamps["Lamp.006"].rna_type.name_property.max_length -> 22 bpy.lamps["Lamp.006"].rna_type.name_property.subtype -> "NONE" bpy.lamps["Lamp.006"].rna_type.name_property.type - (skipping to avoid recursive search) bpy.lamps["Lamp.006"].rna_type.properties.keys() - ['RNA', 'Name', 'Color', 'Distance', 'Energy', 'Shadow', 'Type'] bpy.lamps["Lamp.006"].rna_type.properties["RNA"].rna_type - (skipping to avoid recursive search) bpy.lamps["Lamp.006"].rna_type.properties["RNA"].name -> "RNA"
rna2xml.py
VERBOSE = True VERBOSE_TYPE = False VERBOSE_DOCS = False SKIP_RECURSIVE = False common_types = float, int, bool, type(None), str def seek(r, txt, end = '\n'): newtxt = '' if type(r) in (float, int, type(None)): # basic types print('%s%s' % (txt, r), end=end) return if type(r) in (str, bool): print('%s"%s"' % (txt, r), end=end) return try: keys = r.keys() except: keys = None try: __members__ = r.__members__ except: __members__ = [] for item in __members__: newtxt = txt + '\t' if item == 'rna_type' and not VERBOSE_TYPE: # just avoid because it spits out loads of data continue if SKIP_RECURSIVE: if item in txt: continue attr = getattr(r, item) if type(attr) in common_types: print('%s<%s>' % (txt, item), end='') seek( attr, '', ''), print('</%s>' % (item)) else: print('%s<%s>' % (txt, item)) seek( attr, txt, '') print('%s</%s>' % (txt, item)) if keys: for k in keys: newtxt = txt + '\t' print('%s<item key="%s">' % (txt, k)) seek(r[k], newtxt) print('%s</item>' % (txt)) else: try: length = len( r ) except: length = 0 for i in range(length): newtxt = txt + '\t' attr = r[i] if type(attr) in common_types: print('%s<item index="%d">' % (newtxt, i), end = '') seek(attr, '', '') print('</item>') else: print('%s<item index=%d>' % (newtxt, i)) seek(attr, newtxt+'\t') print('%s</item>' % (newtxt)) print('<root>') seek(bpy, '\t') print('</root>')