1
$\begingroup$

I was trying to go along with a 2.80 scripting tutorial.. But property names cannot be defined.

Invoke works as intended but no idea why this is failing.

import bpy
from bpy.types import (
    Operator,
    Panel,
    PropertyGroup,
)
from bpy.props import (
    BoolProperty,
    IntProperty,
    )


class Subdivide_operator(bpy.types.Operator):
    """Subdivide"""
    bl_idname = "object.subdivide_operator"
    bl_label = "Subdivide"
    bl_options = {'REGISTER', 'UNDO'}

    sub_visible: bpy.props.BoolProperty()
    sub_levels: bpy.props.IntProperty()

    def invoke(self,context,event):
        return bpy.context.window_manager.invoke_props_dialog(self)

    def execute(self, context):
        subdivide = bpy.context.object.modifiers.new(type="SUBSURF",name="Qsubd_subdv")
        subdivide.show_viewport = sub_visible
        subdivide.levels = sub_levels
        bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Qsubd_subdv")

        return {'FINISHED'}   


class A_Panel(bpy.types.Panel):
    bl_label = "Layout Demo"
    bl_space_type = 'PROPERTIES'
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"


    def draw(self, context):
        layout = self.layout
        layout.operator("object.subdivide_operator")


def register():
    bpy.utils.register_class(A_Panel)    
    bpy.utils.register_class(Subdivide_operator)    

def unregister():
    bpy.utils.unregister_class(A_Panel)
    bpy.utils.unregister_class(Subdivide_operator)    

if __name__ == "__main__":
    register()

Invoked Popup menu

Error

$\endgroup$
0

1 Answer 1

2
$\begingroup$

Annotations are properties of the class instance

Bold question title, for what in the end is a python syntax error.

The error is because the property annotations of the operator need to be referenced from the instance (self)

subdivide.show_viewport = self.sub_visible

Without, the script is looking for a local variable sub_visible that is not defined. Error message in question

Recommend looking at the templates that come with blender Text Editor > Templates > Python and reading the documentation.

A clean up... spot the difference between this and question code. I use the nvim editor. It does a lot of clean up for me, or flags unused imports etc.

  • If imported, use the imported types and props.
  • Use the recommended naming convention for operator and panel types. See Docs.
  • When context is passed, use it. Don't get into the habit of bpy. everything.

Added min and max for subdivision property value. 0 and below will produce an error, trying to set to 12 could produce a meltdown.

A poll method as it requires an object and object mode and a mesh context.object.type == 'MESH'

import bpy
from bpy.types import (
    Operator,
    Panel,
)
from bpy.props import (
    BoolProperty,
    IntProperty,
)


class OBJECT_OT_subdivide(Operator):
    """Subdivide"""
    bl_idname = "object.subdivide"
    bl_label = "Subdivide"
    bl_options = {'REGISTER', 'UNDO'}

    sub_visible: BoolProperty()
    sub_levels: IntProperty(
        min=1,
        soft_max=6)

    @classmethod
    def poll(self, context):
        ob = context.object
        return ob and ob.mode == 'OBJECT' and ob.type == 'MESH'

    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self)

    def execute(self, context):
        subdivide = context.object.modifiers.new(
            type='SUBSURF',
            name="Qsubd_subdv")
        subdivide.show_viewport = self.sub_visible
        subdivide.levels = self.sub_levels
        bpy.ops.object.modifier_apply(
            apply_as='DATA',
            modifier=subdivide.name)

        return {'FINISHED'}


class OBJECT_PT_subdivide(Panel):
    bl_label = "Layout Demo"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'

    def draw(self, context):
        layout = self.layout
        layout.operator("object.subdivide")


classes = (OBJECT_PT_subdivide,
           OBJECT_OT_subdivide,
           )


def register():
    for cls in classes:
        bpy.utils.register_class(cls)


def unregister():
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)


if __name__ == "__main__":
    register()
$\endgroup$
1
  • $\begingroup$ Thank you for the detailed response! I can't believe I forgot self lol. $\endgroup$ Commented Feb 23, 2020 at 14:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .