From BlenderWiki

Jump to: navigation, search

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