Unable to get custom orientation+bpy.ops.transform to work during Operator Redo

I’m running into a wall trying to get an operator to work correctly during Redo when it uses a custom orientation + bpy.ops.transform.transform on a newly added mesh object.

The operator functions correctly when it’s initially invoked. However, as soon as I modify a setting in the Redo panel, the custom transform is lost. Is there something that needs to be handled during Redo that I’m missing?

To test out:

  • Start with default .blend
  • Execute the python below
  • Go into edit mode for the Cube, use Face select, and select 1 of the side faces
  • Execute the below operator
    • Works fine - new cylinder has proper orientation
  • Modify the “Vertices” setting in the redo panel
    • Fails - new cylinder has incorrect, default orientation
import bpy


class DCONFIG_OT_test_redo(bpy.types.Operator):
    bl_idname = "dconfig.test_redo"
    bl_label = "DC Test Redo"
    bl_description = "Test Redo"
    bl_options = {'REGISTER', 'UNDO'}

    radius: bpy.props.FloatProperty(name="Radius", default=0.5, step=1)
    depth: bpy.props.FloatProperty(name="Depth", default=0.5, step=1)
    vertices: bpy.props.IntProperty(name="Vertices", default=8)

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

        layout.prop(self, "radius")
        layout.prop(self, "depth")
        layout.prop(self, "vertices")

    def add_primitive(self, context):
        bpy.ops.mesh.primitive_cylinder_add(radius=self.radius, depth=self.depth, vertices=self.vertices)

    def execute(self, context):
        prev_cursor_location = tuple(context.scene.cursor.location)
        is_edit_mode = context.mode == 'EDIT_MESH'

        if context.active_object.type == 'MESH' and is_edit_mode and tuple(context.scene.tool_settings.mesh_select_mode) == (False, False, True):
            prev_active = context.active_object
            prev_orientation = context.scene.transform_orientation_slots[0].type

            bpy.ops.view3d.snap_cursor_to_selected()  # snap cursor to selected set of faces
            bpy.ops.transform.create_orientation(name="AddAxis", use=True, overwrite=True)  # create custom transform for the selection
            bpy.ops.mesh.select_all(action='DESELECT')
            bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

            self.add_primitive(context)
            bpy.ops.transform.transform(mode='ALIGN', value=(0, 0, 0, 0), constraint_axis=(False, False, False))

            context.view_layer.objects.active = prev_active
            context.view_layer.objects.active.select_set(True)
            bpy.ops.object.join()
            bpy.ops.object.mode_set(mode='EDIT', toggle=False)

            context.scene.transform_orientation_slots[0].type = prev_orientation

        context.scene.cursor.location = prev_cursor_location
        return {'FINISHED'}

def register():
    bpy.utils.register_class(DCONFIG_OT_test_redo)
    
def unregister():
    bpy.utils.unregister_class(DCONFIG_OT_test_redo)
    
if __name__ == '__main__':
    register()

Another day’s worth of debugging has got me no closer to determining the cause here.

Stepping through the operator during execution shows that things are set correctly. The create_orientation call properly updates transform_orientation_slots[0]. Additionally, the call to bpy.ops.transform.transform is ok as far as I could understand in the code – debugging shows that transform_exec -> transformApply seems to use the correct orientation matrix. That’s as far as I got though.

@ideasman42 any ideas? Is there something about operator REDO that would prevent a custom orientation from taking effect?

A workaround was provided over at BA: https://blenderartists.org/t/operator-redo-when-using-a-custom-orientation-bpy-ops-transform-transform/1153308

It’s not ideal since it means having to manually transform each vert in python so I’ll file a bug later this weekend for more formal investigation.