Armature.bone_primitive_add() creates new edit bones without populating pose bone counterparts

In edit mode, I am creating bones using an armature operation. The corresponding pose bone does not immediately get populated in the bpy.data.objects[rig.name].pose.bones[bone.name] collection. I found that the pose bones won’t exist until first switching to pose mode, at which time they sync up.

simplified snippet from my script:

bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.armature.bone_primitive_add(name='newBone', space='OBJECT', align='UP', length=1.0, use_deform=True)

then running the following in the console results in the following:

>>>>bpy.data.objects['myArmature'].pose.bones[1]


Traceback (most recent call last):
File "<blender_console>", line 1, in 
IndexError: bpy_prop_collection[index]: index 1 out of range, size 1

but if I then switch to pose mode (not necessarily remaining in pose mode, I can just switch to it then back to edit mode), and then I run the same command again:

>>>>bpy.data.objects['myArmature'].pose.bones[1]


bpy.data.objects['myArmature'].pose.bones["newBone"]

I want to set bone constraints to the pose bones without switching to pose mode and back to edit mode, since that would break all my references from the context switching. I could pull the pose bone specific logic out into a separate section but that would be unwieldy and gross.

Is there any way to instruct blender to sync up the bone collections without blowing away the current context?

rig.update_from_editmode() does it, and you stay in edit mode. It’s on the Object, not on rig.data.

Tried on seven builds, 3.6 to 5.2. After bone_primitive_add, doing nothing gives 1 pose bone and view_layer.update() gives 1, while update_from_editmode() gives 2 with the mode still 'EDIT', and a COPY_LOCATION added right after it survived leaving edit mode.

Skipping the toggle is right for a worse reason than yours. I held edit_bones['Base'] across one and read .name: six builds gave 'newBone'. Wrong bone, no exception. The seventh raised UnicodeDecodeError on two runs of three, so it’s reading freed memory. After update_from_editmode() that reference still read 'Base'.

That did it.

All I added was

bpy.data.objects[rig.name].update_from_editmode()

and then the following worked as expected:

defBonePose = rig.pose.bones[defBoneEdit.name]
stretchConstraint = defBonePose.constraints.new('STRETCH_TO')
stretchConstraint.target = rig
stretchConstraint.subtarget = endTweakBoneEdit.name