update rna_info and rna_rna for better introspection

This commit is contained in:
Campbell Barton 2009-12-25 14:42:00 +00:00
parent 4f3c477a85
commit 4c5a314fef
4 changed files with 215 additions and 29 deletions

@ -42,25 +42,27 @@ class Object(bpy_types.ID):
@property
def children(self):
"""All the children of this object"""
import bpy
return [child for child in bpy.data.objects if child.parent == self]
class _GenericBone:
'''
"""
functions for bones, common between Armature/Pose/Edit bones.
internal subclassing use only.
'''
"""
__slots__ = ()
def translate(self, vec):
"""Utility function to add *vec* to the head and tail of this bone."""
self.head += vec
self.tail += vec
def parent_index(self, parent_test):
'''
"""
The same as 'bone in other_bone.parent_recursive' but saved generating a list.
'''
"""
# use the name so different types can be tested.
name = parent_test.name
@ -76,11 +78,13 @@ class _GenericBone:
@property
def basename(self):
"""The name of this bone before any '.' character"""
#return self.name.rsplit(".", 1)[0]
return self.name.split(".")[0]
@property
def parent_recursive(self):
"""A list of parents, starting with the immediate parent"""
parent_list = []
parent = self.parent
@ -94,23 +98,26 @@ class _GenericBone:
@property
def length(self):
"""The distance from head to tail, when set the head is moved to fit the length."""
return self.vector.length
@length.setter
def length(self, value):
"""The distance from head to tail"""
self.tail = self.head + ((self.tail - self.head).normalize() * value)
@property
def vector(self):
"""The direction this bone is pointing. Utility function for (tail - head)"""
return (self.tail - self.head)
@property
def children(self):
"""A list of all the bones children."""
return [child for child in self._other_bones if child.parent == self]
@property
def children_recursive(self):
"""a list of all children from this bone."""
bones_children = []
for bone in self._other_bones:
index = bone.parent_index(self)
@ -123,10 +130,11 @@ class _GenericBone:
@property
def children_recursive_basename(self):
'''
"""
Returns a chain of children with the same base name as this bone
Only direct chains are supported, forks caused by multiple children with matching basenames will.
'''
Only direct chains are supported, forks caused by multiple children with matching basenames will
terminate the function and not be returned.
"""
basename = self.basename
chain = []
@ -177,10 +185,10 @@ class EditBone(StructRNA, _GenericBone):
__slots__ = ()
def align_orientation(self, other):
'''
"""
Align this bone to another by moving its tail and settings its roll
the length of the other bone is not used.
'''
"""
vec = other.vector.normalize() * self.length
self.tail = self.head + vec
self.roll = other.roll
@ -196,10 +204,10 @@ class Mesh(bpy_types.ID):
__slots__ = ()
def from_pydata(self, verts, edges, faces):
'''
"""
Make a mesh from a list of verts/edges/faces
Until we have a nicer way to make geometry, use this.
'''
"""
self.add_geometry(len(verts), len(edges), len(faces))
verts_flat = [f for v in verts for f in v]
@ -244,7 +252,7 @@ class Mesh(bpy_types.ID):
return [edge_face_count_dict.get(ed.key, 0) for ed in mesh.edges]
def edge_loops(self, faces=None, seams=()):
'''
"""
Edge loops defined by faces
Takes me.faces or a list of faces and returns the edge loops
@ -255,7 +263,7 @@ class Mesh(bpy_types.ID):
[ [(0,1), (4, 8), (3,8)], ...]
optionaly, seams are edge keys that will be removed
'''
"""
OTHER_INDEX = 2,3,0,1 # opposite face index
@ -396,9 +404,9 @@ class Menu(StructRNA):
layout.operator(operator, text=bpy.utils.display_name(f)).path = path
def draw_preset(self, context):
'''Define these on the subclass
"""Define these on the subclass
- preset_operator
- preset_subdir
'''
"""
import bpy
self.path_menu(bpy.utils.preset_paths(self.preset_subdir), self.preset_operator)

@ -20,6 +20,9 @@
import bpy
# use to strip python paths
script_paths = bpy.utils.script_paths()
def range_str(val):
if val < -10000000: return '-inf'
if val > 10000000: return 'inf'
@ -28,6 +31,12 @@ def range_str(val):
else:
return str(val)
def float_as_string(f):
val_str = "%g" % f
if '.' not in val_str and '-' not in val_str: # value could be 1e-05
val_str += '.0'
return val_str
class InfoStructRNA:
global_lookup = {}
def __init__(self, rna_type):
@ -73,6 +82,31 @@ class InfoStructRNA:
return ls
def _get_py_visible_attrs(self):
attrs = []
py_class = getattr(bpy.types, self.identifier)
for attr_str in dir(py_class):
if attr_str.startswith("_"):
continue
attrs.append((attr_str, getattr(py_class, attr_str)))
return attrs
def get_py_properties(self):
properties = []
for identifier, attr in self._get_py_visible_attrs():
if type(attr) is property:
properties.append((identifier, attr))
return properties
def get_py_functions(self):
import types
functions = []
for identifier, attr in self._get_py_visible_attrs():
if type(attr) is types.FunctionType:
functions.append((identifier, attr))
return functions
def __repr__(self):
txt = ''
@ -106,6 +140,10 @@ class InfoPropertyRNA:
self.min = getattr(rna_prop, "hard_min", -1)
self.max = getattr(rna_prop, "hard_max", -1)
self.array_length = getattr(rna_prop, "array_length", 0)
self.collection_type = GetInfoStructRNA(rna_prop.srna)
self.is_required = rna_prop.is_required
self.is_readonly = rna_prop.is_readonly
self.is_never_none = rna_prop.is_never_none
self.type = rna_prop.type.lower()
fixed_type = getattr(rna_prop, "fixed_type", "")
@ -118,12 +156,43 @@ class InfoPropertyRNA:
self.enum_items[:] = rna_prop.items.keys()
if self.array_length:
self.default_str = str(getattr(rna_prop, "default_array", ""))
self.default = tuple(getattr(rna_prop, "default_array", ()))
self.default_str = ''
# special case for floats
if len(self.default) > 0:
if type(self.default[0]) is float:
self.default_str = "(%s)" % ", ".join([float_as_string(f) for f in self.default])
if not self.default_str:
self.default_str = str(self.default)
else:
self.default_str = str(getattr(rna_prop, "default", ""))
self.default = getattr(rna_prop, "default", "")
if type(self.default) is float:
self.default_str = float_as_string(self.default)
else:
self.default_str = str(self.default)
self.srna = GetInfoStructRNA(rna_prop.srna) # valid for pointer/collections
def get_default_string(self):
# pointer has no default, just set as None
if self.type == "pointer":
return "None"
elif self.type == "string":
return '"' + self.default_str + '"'
elif self.type == "enum":
if self.default_str:
return "'" + self.default_str + "'"
else:
return ""
return self.default_str
def get_arg_default(self, force=True):
default = self.get_default_string()
if default and (force or self.is_required == False):
return "%s=%s" % (self.identifier, default)
return self.identifier
def __repr__(self):
txt = ''
txt += ' * ' + self.identifier + ': ' + self.description
@ -162,6 +231,65 @@ class InfoFunctionRNA:
return txt
class InfoOperatorRNA:
global_lookup = {}
def __init__(self, rna_op):
self.bl_op = rna_op
self.identifier = rna_op.identifier
mod, name = self.identifier.split("_OT_", 1)
self.module_name = mod.lower()
self.func_name = name
# self.name = rna_func.name # functions have no name!
self.description = rna_op.description.strip()
self.args = []
def build(self):
rna_op = self.bl_op
parent_id = self.identifier
for rna_id, rna_prop in rna_op.properties.items():
if rna_id == "rna_type":
continue
prop = GetInfoPropertyRNA(rna_prop, parent_id)
self.args.append(prop)
def get_location(self):
op_class = getattr(bpy.types, self.identifier)
op_func = getattr(op_class, "execute", None)
if op_func is None:
op_func = getattr(op_class, "invoke", None)
if op_func is None:
op_func = getattr(op_class, "poll", None)
if op_func:
op_code = op_func.__code__
source_path = op_code.co_filename
# clear the prefix
for p in script_paths:
source_path = source_path.split(p)[-1]
if source_path[0] in "/\\":
source_path= source_path[1:]
return source_path, op_code.co_firstlineno
else:
return None, None
'''
def __repr__(self):
txt = ''
txt += ' * ' + self.identifier + '('
for arg in self.args:
txt += arg.identifier + ', '
txt += '): ' + self.description
return txt
'''
def _GetInfoRNA(bl_rna, cls, parent_id=''):
if bl_rna == None:
@ -184,6 +312,8 @@ def GetInfoPropertyRNA(bl_rna, parent_id):
def GetInfoFunctionRNA(bl_rna, parent_id):
return _GetInfoRNA(bl_rna, InfoFunctionRNA, parent_id)
def GetInfoOperatorRNA(bl_rna):
return _GetInfoRNA(bl_rna, InfoOperatorRNA)
def BuildRNAInfo():
# Use for faster lookups
@ -205,7 +335,8 @@ def BuildRNAInfo():
return True
if "_PT_" in rna_id:
return True
if "_HT_" in rna_id:
return True
return False
def full_rna_struct_path(rna_struct):
@ -395,9 +526,34 @@ def BuildRNAInfo():
if func.return_value:
func.return_value.build()
# now for operators
op_mods = dir(bpy.ops)
for op_mod_name in sorted(op_mods):
if op_mod_name.startswith('__') or op_mod_name in ("add", "remove"):
continue
op_mod = getattr(bpy.ops, op_mod_name)
operators = dir(op_mod)
for op in sorted(operators):
try:
rna_prop = getattr(op_mod, op).get_rna()
except AttributeError:
rna_prop = None
except TypeError:
rna_prop = None
if rna_prop:
GetInfoOperatorRNA(rna_prop.bl_rna)
for rna_info in InfoOperatorRNA.global_lookup.values():
rna_info.build()
for rna_prop in rna_info.args:
rna_prop.build()
#for rna_info in InfoStructRNA.global_lookup.values():
# print(rna_info)
return InfoStructRNA.global_lookup, InfoFunctionRNA.global_lookup, InfoPropertyRNA.global_lookup
return InfoStructRNA.global_lookup, InfoFunctionRNA.global_lookup, InfoOperatorRNA.global_lookup, InfoPropertyRNA.global_lookup

@ -425,7 +425,7 @@ static int rna_Property_unit_get(PointerRNA *ptr)
return RNA_SUBTYPE_UNIT(prop->subtype);
}
static int rna_Property_editable_get(PointerRNA *ptr)
static int rna_Property_readonly_get(PointerRNA *ptr)
{
PropertyRNA *prop= (PropertyRNA*)ptr->data;
@ -433,7 +433,7 @@ static int rna_Property_editable_get(PointerRNA *ptr)
* data for introspection we only need to know if it can be edited so the
* flag is better for this */
// return RNA_property_editable(ptr, prop);
return prop->flag & PROP_EDITABLE ? 1:0;
return prop->flag & PROP_EDITABLE ? 0:1;
}
static int rna_Property_use_return_get(PointerRNA *ptr)
@ -442,6 +442,18 @@ static int rna_Property_use_return_get(PointerRNA *ptr)
return prop->flag & PROP_RETURN ? 1:0;
}
static int rna_Property_is_required_get(PointerRNA *ptr)
{
PropertyRNA *prop= (PropertyRNA*)ptr->data;
return prop->flag & PROP_REQUIRED ? 1:0;
}
static int rna_Property_is_never_none_get(PointerRNA *ptr)
{
PropertyRNA *prop= (PropertyRNA*)ptr->data;
return prop->flag & PROP_NEVER_NULL ? 1:0;
}
static int rna_Property_array_length_get(PointerRNA *ptr)
{
PropertyRNA *prop= (PropertyRNA*)ptr->data;
@ -934,15 +946,25 @@ static void rna_def_property(BlenderRNA *brna)
RNA_def_property_enum_funcs(prop, "rna_Property_unit_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Unit", "Type of units for this property.");
prop= RNA_def_property(srna, "editable", PROP_BOOLEAN, PROP_NONE);
prop= RNA_def_property(srna, "is_readonly", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Property_editable_get", NULL);
RNA_def_property_ui_text(prop, "Editable", "Property is editable through RNA.");
RNA_def_property_boolean_funcs(prop, "rna_Property_readonly_get", NULL);
RNA_def_property_ui_text(prop, "Read Only", "Property is editable through RNA.");
prop= RNA_def_property(srna, "is_required", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Property_is_required_get", NULL);
RNA_def_property_ui_text(prop, "Required", "False when this property is an optional argument in an rna function.");
prop= RNA_def_property(srna, "is_never_none", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Property_is_never_none_get", NULL);
RNA_def_property_ui_text(prop, "Never None", "True when this value can't be set to None.");
prop= RNA_def_property(srna, "use_return", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Property_use_return_get", NULL);
RNA_def_property_ui_text(prop, "Return", "True when this property is a return value from an rna function..");
RNA_def_property_ui_text(prop, "Return", "True when this property is a return value from an rna function.");
prop= RNA_def_property(srna, "registered", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);

@ -397,8 +397,8 @@ def rna2epy(BASEPATH):
array_str = get_array_str(length)
if rna_prop.editable: readonly_str = ''
else: readonly_str = ' (readonly)'
if rna_prop.is_readonly: readonly_str = ' (readonly)'
else: readonly_str = ''
if rna_prop_ptr: # Use the pointer type
out.write(ident+ '\t@ivar %s: %s\n' % (rna_prop_identifier, rna_desc))