get selected bone in blender python is inconsistent #53135

Closed
opened 2017-10-23 15:38:17 +02:00 by sarazin jean francois · 6 comments

System Information
Win 7 64 bits

Blender Version
official 2.79
hash 5bd8ac9

Short description of error
When I print the selected bone in python, the result is wrong when a command switch back and force to pose mode.

Exact steps for others to reproduce the error
Based on a (as simple as possible) attached .blend file with minimum amount of steps

New blend file
create a bone, go to edit mode
extrude a few times (let's say 8)
select the first bone.

launch this script a few times :


import bpy
C = bpy.context

selBone = C.selected_bones[0]
print (selBone)
bpy.ops.object.mode_set(mode='POSE')
bpy.ops.object.mode_set(mode='EDIT')
print (selBone)


sometimes console will print "Bone" and sometimes "Bone.008"

I found this bug using the addon "Auto Bone Controller" which crashed when doing funny things in pose mode and edit mode.

**System Information** Win 7 64 bits **Blender Version** official 2.79 hash 5bd8ac9 **Short description of error** When I print the selected bone in python, the result is wrong when a command switch back and force to pose mode. **Exact steps for others to reproduce the error** Based on a (as simple as possible) attached .blend file with minimum amount of steps New blend file create a bone, go to edit mode extrude a few times (let's say 8) select the first bone. launch this script a few times : **** import bpy C = bpy.context selBone = C.selected_bones[0] print (selBone) bpy.ops.object.mode_set(mode='POSE') bpy.ops.object.mode_set(mode='EDIT') print (selBone) **** sometimes console will print "Bone" and sometimes "Bone.008" I found this bug using the addon "Auto Bone Controller" which crashed when doing funny things in pose mode and edit mode.

Changed status to: 'Open'

Changed status to: 'Open'

Added subscriber: @sarazinjean-francois

Added subscriber: @sarazinjean-francois
Member

Added subscriber: @JoshuaLeung

Added subscriber: @JoshuaLeung
Member

Changed status from 'Open' to: 'Archived'

Changed status from 'Open' to: 'Archived'
Joshua Leung self-assigned this 2017-10-24 05:54:46 +02:00
Member

This is an unavoidable dangling pointers/references bug that we cannot ever fully fix:

  • When you enter/exit editmode, the EditBones (i.e. the temporary copies of the bones used in editmode for easier editing) get freed/recreated.
  • In your script, the selBone = C.selected_bones- [x] line grabs a reference to an EditBone. This then gets invalidated on the first mode-change. Python has no way to know this of course, and we can't really do anything about this (at least not without significant slowdowns)
  • By chance, the second print might happen to refer to the intended bone, or another other one of the bones, after the second mode change. However, in some cases (e.g. if other ops run), these pointers may end up being completely invalid (hence the crashes in some cases)

To fix these problems, don't hang on to pointers to data before/after mode changes. Instead, store the name of the bone instead, and look up the new bone instance using that name.

For example, your script should be changed to look more like:

import bpy
C = bpy.context

selBone = C.selected_bones[0]
selBoneName = selBone.name  # <---    grab name of bone
print (selBone)

bpy.ops.object.mode_set(mode='POSE')

selBone = C.active_object.pose.bones[selBoneName]  # <--- grab new instance of the bone (pose mode)
print (selBone)


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

selBone = C.active_object.data.bones[selBoneName]  # <--- grab new instance of the bone (edit mode)
print (selBone)

Hope that helps

This is an unavoidable dangling pointers/references bug that we cannot ever fully fix: * When you enter/exit editmode, the EditBones (i.e. the temporary copies of the bones used in editmode for easier editing) get freed/recreated. * In your script, the `selBone = C.selected_bones- [x]` line grabs a reference to an EditBone. This then gets invalidated on the first mode-change. Python has no way to know this of course, and we can't really do anything about this (at least not without significant slowdowns) * By chance, the second print might happen to refer to the intended bone, or another other one of the bones, after the second mode change. However, in some cases (e.g. if other ops run), these pointers may end up being completely invalid (hence the crashes in some cases) **To fix these problems, don't hang on to pointers to data before/after mode changes. Instead, store the name of the bone instead, and look up the new bone instance using that name.** For example, your script should be changed to look more like: ``` import bpy C = bpy.context selBone = C.selected_bones[0] selBoneName = selBone.name # <--- grab name of bone print (selBone) bpy.ops.object.mode_set(mode='POSE') selBone = C.active_object.pose.bones[selBoneName] # <--- grab new instance of the bone (pose mode) print (selBone) bpy.ops.object.mode_set(mode='EDIT') selBone = C.active_object.data.bones[selBoneName] # <--- grab new instance of the bone (edit mode) print (selBone) ``` Hope that helps

thanks a lot Joshua. I wasn't aware that getting a selection was a pointer. I'll try to propose a change to the addon with the work around you proposed.

thanks a lot Joshua. I wasn't aware that getting a selection was a pointer. I'll try to propose a change to the addon with the work around you proposed.
Sign in to join this conversation.
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender-addons#53135
No description provided.