Why can't I execute clear/set inverse of CHILD OF constraints with python?

I have a rig with many child of constraints.

Therefore, whenever I edit the structure of the armature in edit mode, I must click clear inverse and set inverse of the child of constraints.

Since I have done so many iterations so far, I’m now going to automate this with a Python script.

So I tried the code below.

import bpy

name = bpy.context.active_object.name

childOfOwners = bpy.data.armatures[name].bones[:]

for i in childOfOwners :
    bpy.ops.constraint.childof_clear_inverse(constraint="Child Of", owner='BONE')
    bpy.ops.constraint.childof_set_inverse(constraint="Child Of", owner='BONE')

But failed…
The above image is an error message displayed on the system console.

bpy.ops.constraint.childof_clear_inverse(constraint="Child Of", owner='BONE') This code seems to be causing the problem, but I haven’t clearly understood what the problem is.

I actually copied and used the code displayed in the info editor when I manually clicked clear inverse and set inverse in the properties editor.
But why is the error occurring?

Thank you in advance.

first of all, you’re looping through a list just doing the exact same thing over and over again for each item in childOfOwners. bpy.ops rely on the blender context being driven by user input, but since you’re doing this in a script no user input is happening. You can override the context and manually specify which objects are ‘selected’ in order to force the operator to work, but really doing this with bpy.ops is the wrong way to do it, why not just access the constraints directly?

import bpy

for o in bpy.data.objects:
    for c in o.constraints:
        print(f"{c.name}: {c.type}")

Oh, I had no idea that the input for bpy.ops was missing.

OK, on the other hand, I tried to access the constraints directly, but as shown in the image below, I couldn’t find any properties for the clear/set inverse only.
What am i doing wrong?

there’s no property for it because it’s specific functionality handled by the operator that is executed when you press the button- you’ll need to replicate the behavior using the constraint data. the set/clear inverse operator just sets and clears the inverse_matrix property.

clicking set inverse, and then clear inverse:

Thank you.
The answer still feels difficult for me, but there seems to be a lot of hints in it. I hope to get a deeper understanding again later.

Meanwhile,
I wrote the below script via googling and it works fine.

import bpy

# 1 - Set Variables
childOfOwners = bpy.context.selected_pose_bones
activeChildOfOwner = bpy.context.active_object

# 2 - Reset Inverse
for b in childOfOwners:
    for c in b.constraints: 
        if c.type == "CHILD_OF":
            context_py = bpy.context.copy()
            context_py["constraint"] = c
            activeChildOfOwner.data.bones.active = b.bone
            oriValue = c.influence
            c.influence = 1
            bpy.ops.constraint.childof_clear_inverse(context_py, constraint="Child Of", owner='BONE')
            bpy.ops.constraint.childof_set_inverse(context_py, constraint="Child Of", owner='BONE')
            c.influence = oriValue

However, since I’m a beginner in Python, .copy() is new and the way to view api documents is awkward.

As for .copy(), I think I can understand if I study the basics of Python more.

But I’m very curious about the api documentation, so I’d like to ask a question.
If you look at the solution I found through Googling, add a new first parameter to bpy.ops.constraint.childof_clear_inverse(constraint="Child Of", owner='BONE')
You can see that it is used in the form of bpy.ops.constraint.childof_clear_inverse(context_py, constraint="Child Of", owner='BONE').

However, looking at the api document image above, it seems that there are only two parameters.
How can I know that the code works if I insert context_py to the left of the constraint parameter in a formal way?
I’m wondering if this is about python grammar, basics or how to read the documentation.

This is because all operators extend from bpy.types.Operator, where there are actually three additional parameters you can pass: context override, execution context, and undo. The documentation omits these because A) They are optional, and most users will not need to use them, B) if every operator included them it would be really hard to read, and C) the parameters have the same effect on every operator so it’s sufficient to read about it in one place.

1 Like

Thank you. It is a clear explanation.