In the spirit of EAFP (Easier to Ask Forgiveness than Permission), I’ve copied my post here from the “properties and inheritance” topic where it hadn’t gotten any replies. I’m new to the forum, so please forgive me if reposting a question breaks any rules.
I am part of a team working on a fairly complex Blender addon and we’d like to use inheritance in our design. Here’s one of the simplest “regular python” inheritance examples:
########################################################
class Base(object):
s = "ABC"
class Child(Base):
pass
class App:
b = Base()
c = Child()
def print_self(self):
print ( "App Members:" )
print ( " b.s = " + self.b.s )
print ( " c.s = " + self.c.s )
########################################################
if __name__ == "__main__":
app = App()
app.print_self()
This works fine and prints out:
App Members:b.s = ABC
c.s = ABC
In other words, the “Child” class inherits the string “s” from its parent (“Base”) as expected.
Here’s an attempt to do the same thing using Blender Properties (full addon included below):
########################################################
class Base(bpy.types.PropertyGroup):
s = StringProperty(name="s",default="ABC")
class Child(Base):
pass
class AppPropertyGroup(bpy.types.PropertyGroup):
b = PointerProperty(name="b", type=Base)
c = PointerProperty(name="c", type=Child)
def print_self (self, context):
print ( "App Members:" )
print ( " b.s = " + self.b.s ) # OK
print ( " c.s = " + self.c.s ) # Fails
########################################################
As the comments indicates, the reference to self.b.s works, but the reference to self.c.s fails. Here’s the output:
App Members:b.s = ABC
Traceback (most recent call last):
File “/home/user/.config/blender/2.68/scripts/addons/InheritBlender_forum.py”, line 45, in execute
context.scene.app.print_self(context)
File “/home/user/.config/blender/2.68/scripts/addons/InheritBlender_forum.py”, line 34, in print_self
print ( " c.s = " + self.c.s ) # Fails
TypeError: Can’t convert ‘tuple’ object to str implicitly
If I wrap self.c.s in the print statement with a string conversion ( str(self.c.s) ), it prints out this:
App Members:b.s = ABC
c.s = (<built-in function StringProperty>, {‘attr’: ‘s’, ‘default’: ‘ABC’, ‘name’: ‘s’})
It appears that using inheritance has somehow removed Blender’s ability to treat a StringProperty as a string (lost it’s “RNA” wrapper?). Is this a bug?
Finally, I apologize in advance that I’m relatively new to both Blender and Python, so please forgive any beginner misconceptions in my post … but please feel free to point them out!!
Full Addon Example:
"""
This program demonstrates a potential bug
in Blender's Property inheritance.
"""
bl_info = {
"version": "0.1",
"name": "Inherit Blender",
"author": "BlenderHawk",
"location": "Properties > Scene",
"category": "Blender Experiments"
}
import bpy
from bpy.props import *
########################################################
class Base(bpy.types.PropertyGroup):
s = StringProperty(name="s",default="ABC")
class Child(Base):
pass
class AppPropertyGroup(bpy.types.PropertyGroup):
b = PointerProperty(name="b", type=Base)
c = PointerProperty(name="c", type=Child)
def print_self (self, context):
print ( "App Members:" )
print ( " b.s = " + self.b.s ) # OK
print ( " c.s = " + self.c.s ) # Fails
########################################################
class APP_OT_print_operator(bpy.types.Operator):
bl_idname = "app.run_example"
bl_label = "Run Example"
bl_description = "Run Example"
bl_options = {'REGISTER'}
def execute(self, context):
context.scene.app.print_self(context)
return {'FINISHED'}
class APP_PT_Inheritance(bpy.types.Panel):
bl_label = "Property Inheritance"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
def draw(self, context):
row = self.layout.row()
row.operator("app.run_example", text="Run Example")
def register():
print ("Registering ", __name__)
bpy.utils.register_module(__name__)
bpy.types.Scene.app = bpy.props.PointerProperty(type=AppPropertyGroup)
def unregister():
print ("Unregistering ", __name__)
del bpy.types.Scene.app
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
Thanks in advance for any help.