Search code examples
pythoninheritanceblender

AttributeError: object has no attribute 'method'


I'm making a plugin for blender and I have some data types that contain drawing functions. However, when calling these functions on two specific classes, it throws an AttributeError

Traceback (most recent call last):
  File "[REDACTED]/blender/4.2/scripts/addons/manifoldclothing/gen/GenPanel.py", line 17, in draw
    context.active_object.manifoldHuman.maleBody.draw(layout, context)
  File "[REDACTED]/blender/4.2/scripts/addons/manifoldclothing/data/FemaleBodyData.py", line 35, in draw
    self.neck.draw(box, context)
    ^^^^^^^^^^^^^^
AttributeError: 'LongLimbData' object has no attribute 'draw'

LimbData:

import bpy

class LimbData(bpy.types.PropertyGroup):
    length: bpy.props.FloatProperty(name="Length")
    
    def draw(self, layout, context):
        layout.prop(self, "length")

LongLimbData:

import bpy
from .LimbData import *

class LongLimbData(LimbData):
    thickness: bpy.props.FloatProperty(name="Thickness")

    def draw(self, layout, context):
        super().draw(layout, context)
        layout.prop(self, "thickness")

FemaleSpineData:

import bpy
from .LongLimbData import *

class FemaleSpineData(LongLimbData):
    lowerWidth: bpy.props.FloatProperty(name="Lower Width")
    upperWidth: bpy.props.FloatProperty(name="Upper Width")
    
    def draw(self, layout, context):
        super().draw(layout, context)
        layout.prop(self, "lowerWidth")
        layout.prop(self, "upperWidth")

FemaleBodyData:

import bpy
from .BodyData import *
from .FemaleChestData import *
from .FemaleHipData import *
from .FemaleThighData import *

class FemaleBodyData(BodyData):
    hips: bpy.props.PointerProperty(type=FemaleHipData)
    spine: bpy.props.PointerProperty(type=FemaleSpineData)
    chest: bpy.props.PointerProperty(type=FemaleChestData)
    neck: bpy.props.PointerProperty(type=LongLimbData)
    head: bpy.props.PointerProperty(type=WideLimbData)
    
    # OTHER FIELDS OMITTED
    
    def draw(self, layout, context):
        box = layout.box()
        self.hips.draw(box, context)
        self.spine.draw(box, context)
        self.chest.draw(box, context)
        self.neck.draw(box, context)
        self.head.draw(box, context)

        # OTHER DRAW CALLS OMITTED

But FemaleSpineData (which extends LongLimbData) can call super().draw(layout, context) just fine. It shows the extra property that LongLimbData defines.

I've made sure the indents are 4 spaces at least 5 times now. I also tried installing another version of blender to no avail.


Solution

  • Turns out this was an issue with blender. Blender does not play nice when subclassing existing property groups and such. The correct way to use subclassing in this case is to use mix-in classes.

    Example:

    import bpy
    
    class AbstractLimb:
        length: bpy.props.FloatProperty(name="Length", min=0.0)
        
        def Draw(self, layout, context):
            layout.prop(self, "length")
    
    class LongLimb(AbstractLimb, bpy.types.PropertyGroup):
        radius: bpy.props.FloatProperty(name="Radius", min=0.0)
        
        def Draw(self, layout, context):
            super().Draw(layout, context)
            layout.prop(self, "radius")
    
    class WideLimb(AbstractLimb, bpy.types.PropertyGroup):
        width: bpy.props.FloatProperty(name="Width", min=0.0)
        thickness: bpy.props.FloatProperty(name="Thickness", min=0.0)
        
        def Draw(self, layout, context):
            super().Draw(layout, context)
            layout.prop(self, "width")
            layout.prop(self, "thickness")
    

    This threw no errors for me and was properly drawn by the UI.