How do I make multiple objects Make Local at once?

I want to make all the child objects of an object Make Local at once.
And I select the child objects and invoke the bpy.ops.outliner.id_operation(type='LOCAL') operator.

import bpy

class MakeLocalOperator(bpy.types.Operator):
    bl_idname = 'outliner.make_object_id_data_local'
    bl_label = 'Make Object ID Data Local'
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        return (
            context.area.type == 'OUTLINER'
            and context.object.type == 'EMPTY'
        )

    def execute(self, context):
        object_visibilities = dict()

        def force_show_object(obj):
            object_visibilities[obj.name] = {
                'hide': obj.hide_get(),
                'hide_select': obj.hide_select,
                'hide_viewport': obj.hide_viewport,
            }
            obj.hide_select = False
            obj.hide_viewport = False
            obj.hide_set(False)

        def reset_object_visibilities():
            for object_name, visibility in object_visibilities.items():
                obj = bpy.data.objects[object_name]
                obj.hide_set(visibility['hide'])
                obj.hide_viewport = visibility['hide_viewport']
                obj.hide_select = visibility['hide_select']

        bpy.ops.outliner.show_one_level()

        joint_group_object = context.active_object
        force_show_object(joint_group_object)

        for obj in joint_group_object.children:
            if not obj.override_library:
                continue

            print(f'id_operation: {obj.name}')
            force_show_object(obj)
            obj.select_set(True)

        bpy.ops.outliner.object_operation(type='SELECT')
        bpy.ops.outliner.id_operation(type='LOCAL')

        # reset_object_visibilities()

        return {'FINISHED'}


def menu_outliner_object(self, context):
    self.layout.separator()
    self.layout.operator("outliner.make_object_id_data_local")


def register():
    bpy.types.OUTLINER_MT_object.append(menu_outliner_object)


def unregister():
    bpy.types.OUTLINER_MT_object.remove(menu_outliner_object)

Selecting the objects succeed, but Make Local failed.
If I manually Make Local from the outliner, it succeeds.
make_local

How can I do Select and Make Local within one operator?

what blender is doing when you use the menus is looping through all selected objects and making each one local, so you have to do the same.

edit: actually, you can probably skip making them selected if you like since you already have criteria for which you want to make local.

@sirmaxim Thanks for your reply.
bpy.ops.outliner.id_operation(type='LOCAL') will Make Local selected objects in a single call.

I solved the problem with the following code.

-       bpy.ops.outliner.object_operation(type='SELECT')
+       outliner_context = context.copy()
+       bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
-       bpy.ops.outliner.id_operation(type='LOCAL')
+       bpy.ops.outliner.id_operation(outliner_context, type='LOCAL')

make_local_success

I referred to the following URL:
https://docs.blender.org/api/current/info_gotcha.html#can-i-redraw-during-script-execution

However, the document says:

If you insist – yes it’s possible, but scripts that use this hack will not be considered for inclusion in Blender and any issue with using it will not be considered a bug, there is also no guaranteed compatibility in future releases.

Do you know of any workarounds?

They define what’s that is about. The short, short version is blender’s UI is single thread so everything you do ties up the interface so it doesn’t refresh until after your code finishes. The ‘correct’ workaround is also listed, which is to exec your operator in a modal so it has it’s own thread and timer.

Thanks for your suggestion.
I’ll try the modal.

By the way, Is it possible to achieve Make Local without using bpy.ops.outliner.id_operation(type='LOCAL')?

I figured out how to achieve it using modal.

However, I gave up on the implementation for the following reasons:

  • There is no way to close a node in the outliner
  • Make Local caused performance problems