diff options
author | Campbell Barton <ideasman42@gmail.com> | 2009-12-25 17:42:00 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2009-12-25 17:42:00 +0300 |
commit | 4c5a314fef8cb15f1a5990180cf5025597afdd01 (patch) | |
tree | 08a233baf408f585be287436aa7a2a76381c385b | |
parent | 4f3c477a85aa9c395f21830ed18e89407e9275db (diff) |
update rna_info and rna_rna for better introspection
-rw-r--r-- | release/scripts/modules/bpy_types.py | 40 | ||||
-rw-r--r-- | release/scripts/modules/rna_info.py | 168 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_rna.c | 34 | ||||
-rw-r--r-- | source/blender/python/epy_doc_gen.py | 4 |
4 files changed, 216 insertions, 30 deletions
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 2351fa8b091..15bf71e017e 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -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) diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py index abb7bb35af0..2a70feec9dd 100644 --- a/release/scripts/modules/rna_info.py +++ b/release/scripts/modules/rna_info.py @@ -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 diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 5fd87728fb8..e6c21d8fede 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -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_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_editable_get", NULL); - RNA_def_property_ui_text(prop, "Editable", "Property is editable through RNA."); + 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); diff --git a/source/blender/python/epy_doc_gen.py b/source/blender/python/epy_doc_gen.py index 8783cec93ab..7e32b29aa1f 100644 --- a/source/blender/python/epy_doc_gen.py +++ b/source/blender/python/epy_doc_gen.py @@ -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)) |