Force Undo if create object with script from mesh edit mode and then use "Adjust last operation" panel

To the point:
Bug report Creating Lattice object with script with {“REGISTER”, “UNDO”} if parameters was changed in Undo window and mesh was in Edit mode - undo last changes to the mesh or last action
This could be the known issue, but I need a workaround.

Video from bugreport

The code (as I can't upload file)
import bpy


class TEST_OT_register_undo(bpy.types.Operator):
    bl_idname = "test.register_undo"
    bl_label = "Register Undo"
    bl_description = "Some description."
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_options = {"REGISTER", "UNDO"}


    orientation_types = (('GLOBAL', 'Global', ''),
                         ('LOCAL', 'Local', ''),
                         ('CURSOR', 'Cursor', ''))
                         
    orientation: bpy.props.EnumProperty(
        name="Orientation", items=orientation_types, default='LOCAL')


    def draw(self, context):
        layout = self.layout

        row = layout.row()
        row.prop(self, "orientation", text="Orientation", expand=True)

    @classmethod
    def poll(self, context):
        # Checks for mesh in edit mode
        active_object = context.active_object
        return active_object is not None and active_object.type == 'MESH' and active_object.mode == "EDIT"

    def execute(self, context): 
        self.createLattice(context)
        if self.orientation == 'GLOBAL':            
            bpy.context.scene.transform_orientation_slots[0].type = 'GLOBAL'

        elif self.orientation == 'LOCAL':
            bpy.context.scene.transform_orientation_slots[0].type = 'LOCAL'

        elif self.orientation == 'CURSOR':
            bpy.context.scene.transform_orientation_slots[0].type = 'CURSOR'
        
        return {'FINISHED'}
    
    def createLattice(self, context):
        object_active = bpy.context.view_layer.objects.active
        lattice_data = bpy.data.lattices.new('SimpleLattice')
        lattice_obj = bpy.data.objects.new(object_active.name + '_SimpleLattice', lattice_data)

        context.scene.collection.objects.link(lattice_obj)

        return lattice_obj
    

classes = (
            TEST_OT_register_undo,
)

def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)
        
def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)
        
if __name__ == "__main__":
    register()

For now I only have a “solution” how to force it by copying selected objects and deleting them, and then selecting originals with bpy.ops.ed.undo_push() at the end, and only after this actions, mesh data stay untouched.
See def for_edit_mode (self, context):

Updated code
import bpy


class TEST_OT_register_undo(bpy.types.Operator):
    bl_idname = "test.register_undo"
    bl_label = "Register Undo"
    bl_description = "Some description."
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_options = {"REGISTER", "UNDO"}


    orientation_types = (('GLOBAL', 'Global', ''),
                         ('LOCAL', 'Local', ''),
                         ('CURSOR', 'Cursor', ''))
                         
    orientation: bpy.props.EnumProperty(
        name="Orientation", items=orientation_types, default='LOCAL')


    def draw(self, context):
        layout = self.layout

        row = layout.row()
        row.prop(self, "orientation", text="Orientation", expand=True)

    @classmethod
    def poll(self, context):
        # Checks for mesh in edit mode
        active_object = context.active_object
        return active_object is not None and active_object.type == 'MESH' and active_object.mode == "EDIT"
        
    def execute(self, context):
        self.for_edit_mode(context)            
        self.createLattice(context)
        if self.orientation == 'GLOBAL':            
            bpy.context.scene.transform_orientation_slots[0].type = 'GLOBAL'

        elif self.orientation == 'LOCAL':
            bpy.context.scene.transform_orientation_slots[0].type = 'LOCAL'

        elif self.orientation == 'CURSOR':
            bpy.context.scene.transform_orientation_slots[0].type = 'CURSOR'
        
        return {'FINISHED'}
    
    def createLattice(self, context):
        object_active = bpy.context.view_layer.objects.active
        lattice_data = bpy.data.lattices.new('SimpleLattice')
        lattice_obj = bpy.data.objects.new(object_active.name + '_SimpleLattice', lattice_data)

        context.scene.collection.objects.link(lattice_obj)

        return lattice_obj
    
    def for_edit_mode (self, context):
        active_object = context.view_layer.objects.active
        if active_object.mode == "EDIT":

            objects_originals = context.selected_objects

            bpy.ops.object.mode_set(mode = 'OBJECT')
            bpy.ops.object.duplicate()

            objects_duplicated = context.selected_objects

            # removing objects with its data
            for obj in objects_duplicated:       
                purge_data = [o.data for o in context.selected_objects if o.data]
                bpy.data.batch_remove(context.selected_objects)
                bpy.data.batch_remove([o for o in purge_data if not o.users])

            for obj in objects_originals:
                obj.select_set(True)
                context.view_layer.objects.active = active_object

            bpy.ops.object.mode_set(mode = 'EDIT')
            
        bpy.ops.ed.undo_push()
    

classes = (
            TEST_OT_register_undo,
)

def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)
        
def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)
        
if __name__ == "__main__":
    register()

My skills and knowledge do not allow me to think globally,
so maybe some one have a better idea how to do this?

1 Like