Blender crashes when using an EnumProperty to set Space

I have a property that I’m trying to use to set the current context.area.type

Using the property as it is now, the set_space function crashes Blender. If I use the property with just an update function it works, but I need the property to also get updated when the context.area.type is changed in another manner by the user (using a get).

Can anyone please help me create this property so that its set method sets the current space? Thank you!

import bpy
from bpy.types import PropertyGroup
from bpy.props import EnumProperty

def set_space(self,value):
    if value == 0:
        bpy.context.area.type = "GRAPH_EDITOR"
    elif value == 1:
        bpy.context.area.type = "DOPESHEET_EDITOR"

class SWITCH_PG_switcher_props(PropertyGroup):
    space: EnumProperty(
        name="Space Target",
        description="Switch to space",
        items=(
            ('GRAPH_EDITOR', "", "Graph Editor", "GRAPH", 0),
            ('DOPESHEET_EDITOR', "", "Dopesheet Editor", "ACTION", 1),
        ),
        default='GRAPH_EDITOR',
        set = set_space
        )

def draw_enum(self, context):
    layout = self.layout
    scene = context.scene
    layout.prop(scene.switcher, "space", icon_only=True, expand=True)

def register():
    bpy.utils.register_class(SWITCH_PG_switcher_props)
    bpy.types.Scene.switcher = bpy.props.PointerProperty(type=SWITCH_PG_switcher_props)
    bpy.types.DOPESHEET_HT_header.append(draw_enum)
    bpy.types.GRAPH_HT_header.append(draw_enum)

def unregister():
    del bpy.types.Scene.switcher
    bpy.types.DOPESHEET_HT_header.remove(draw_enum)
    bpy.types.GRAPH_HT_header.remove(draw_enum)
    bpy.utils.unregister_class(SWITCH_PG_switcher_props)

if __name__ == "__main__":
    register()

@iceythe , I tried your solution here, but passing any arbitrary region still leads to a crash:

Property getter/setters may get called while Blender is redrawing. Using them for side effects is therefore unsafe - especially so when they modify what Blender is currently drawing.

You can’t use the setter to modify context.area.type directly.

But you can register a timer callback that does it.
Timer callbacks are called later in the main loop, after stuff has been drawn.

With the relevant parts changed:


area_types = ('GRAPH_EDITOR',
              'DOPESHEET_EDITOR')

def get_area(self):
    return area_types.index(bpy.context.area.type)


def set_space(self, value):
    def call_later(area=bpy.context.area, value=value):
        area.type = area_types[value]
    bpy.app.timers.register(call_later)


class SWITCH_PG_switcher_props(PropertyGroup):
    space: EnumProperty(
        name="Space Target",
        description="Switch to space",
        items=(
            ('GRAPH_EDITOR', "Graph Editor", "", "GRAPH", 0),
            ('DOPESHEET_EDITOR', "Dopesheet Editor", "", "ACTION", 1),
        ),
        get= get_area,
        set=set_space,
        )
1 Like

You are a genius. Thank you so much!!

1 Like