Search This Blog

Labels

Sunday, December 19, 2010

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>')

No comments:

Post a Comment