Help for fast path script - bone issue

Hi,

I’m working on the new version of my addon fast path, and I have trouble with setting the path target in the bone constraint panel.
Please, could you help me with ?

I already did it for object, but i can’t for bone.
Visually, this is what I want to achieve in python

[ATTACH=CONFIG]485859[/ATTACH]

and this is the error I get
Traceback (most recent call last):
file"\fast_path.py", line 154, in invoke
attributeerror:‘bpy_prop_collection’ object has no attribute ‘constraints’

[ATTACH=CONFIG]485860[/ATTACH]

The problem is in the line 154.
The point is that I can’t access this operator :
bpy.context.object.pose.bones.constraints[“Follow Path”].target = pathname

the selected bone has its own variable “bonename” defined previously as
bonename = bpy.context.active_bone
and pathname is the variable dealing with the path object.

I tried things like
bpy.context.object.pose.bones[bonename].constraints[“Follow Path”].target = bpy.data.objects[“Path”]
but it makes a loop interpreted as double bpy.context obviously.

also tried
bonename.pose.bones.constraints[“Follow Path”].target = pathname

I think it may be just a syntax issue, but I have not found it

Here is the full code, the ends are in comments because i do step by step debug.
The new bone stuff begins at the #class fastpath_bone

# -*- coding: utf-8 -*-

# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

bl_info = {
    "name": "fast_path",
    "author": "Laurent Laget",
    "version": (0, 5),
    "blender": (2, 78, 5),
    "location": "Add",
    "description": "Create fast_path",
    "warning": "",
    "wiki_url": "",
    "category": "Add",
    }

import bpy

def main(context):
    for ob in context.scene.objects:
        print(ob)

#Declaration of variables
forwardaxe = 'TRACK_NEGATIVE_Y'
upaxe = 'UP_Z'

def pathcreation(forwardaxe,upaxe):
    
        #Get duration
        duration = bpy.context.scene.frame_end
        
        #Get the name of the selected object and add a follow path constrain to it
        objectname = bpy.context.active_object
        bpy.ops.object.constraint_add(type='FOLLOW_PATH')
            
        # Add a curve object , name it, delete vertices and make it ready for shift + right click draw
        bpy.ops.curve.primitive_nurbs_path_add()
        bpy.context.object.name = "Path"
        pathname= bpy.context.active_object
        bpy.ops.object.editmode_toggle()
        bpy.ops.curve.delete(type='VERT')
        
        #Go back to object mode , set origin and reselect the selected  object , push the name of the path in the follow path constraint and  animate it 
        bpy.ops.object.editmode_toggle()
        bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
        
        bpy.context.scene.objects.active = objectname
        bpy.context.object.constraints["Follow Path"].target = pathname
        bpy.context.object.constraints["Follow Path"].use_curve_follow = True
        
        #Test if the selected object is different from a camera, and set variables accordingly 
        if objectname.type != 'CAMERA':
            forwardaxe = 'TRACK_NEGATIVE_Y'
            upaxe = 'UP_Z'
        else:
            forwardaxe = 'TRACK_NEGATIVE_Z'
            upaxe = 'UP_Y'
            
        #Get specific orientations
        bpy.context.object.constraints["Follow Path"].forward_axis = forwardaxe
        bpy.context.object.constraints["Follow Path"].up_axis = upaxe
        
        override={'constraint':objectname.constraints["Follow Path"]}
        bpy.ops.constraint.followpath_path_animate(override,constraint='Follow Path')
        
        #reselect the path
        bpy.context.scene.objects.active = pathname
        bpy.context.object.data.path_duration = duration
        bpy.ops.object.editmode_toggle()   
        
        objectname.location[0] = 0
        objectname.location[1] = 0
        objectname.location[2] = 0
        
        objectname.rotation_euler[0] = 0
        objectname.rotation_euler[1] = 0
        objectname.rotation_euler[2] = 0

#Class fastpath
class fastpath(bpy.types.Operator):
    """Create a path for the selected object"""
    bl_idname = "object.fastpath"
    bl_label = "fastpath"
    bl_options = {'REGISTER', 'UNDO'}
   
    def invoke(self, context, event):
        
        pathcreation(forwardaxe,upaxe)
        
        return {'FINISHED'}

#Class fastpath_bone
class fastpath_bone(bpy.types.Operator):
    """Create a path for the selected object"""
    bl_idname = "object.fastpath"
    bl_label = "fastpath"
    bl_options = {'REGISTER', 'UNDO'}
   
    def invoke(self, context, event):
        
       
       #Get duration
        duration = bpy.context.scene.frame_end
        
        #Get the name of the selected object and add a follow path constrain to it
        bpy.ops.object.posemode_toggle()
        objectname = bpy.context.active_object
        bpy.ops.object.posemode_toggle()
        print(objectname)
        #bpy.ops.object.posemode_toggle()
        bonename = bpy.context.active_bone
        print(bonename)
        bpy.ops.pose.constraint_add(type='FOLLOW_PATH')
        bpy.ops.object.posemode_toggle()
        
        # Add a curve object , name it, delete vertices and make it ready for shift + right click draw
        bpy.ops.curve.primitive_nurbs_path_add()
        bpy.context.object.name = "Path"
        pathname= bpy.context.active_object
        bpy.ops.object.editmode_toggle()
        bpy.ops.curve.delete(type='VERT')
        
        #Go back to object mode , set origin and reselect the selected  object , push the name of the path in the follow path constraint and  animate it 
        bpy.ops.object.editmode_toggle()
        bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
                
        #select bone and Go to pose mode
        bpy.ops.object.select_all(action='DESELECT')
        bpy.context.scene.objects.active = objectname
        print(objectname)
        
        bpy.ops.object.posemode_toggle()
        bpy.ops.pose.select_all(action='DESELECT')
        bonename.select=True
        
        
        bpy.context.object.pose.bones[bonename].constraints["Follow Path"].target = bpy.data.objects["Path"]
        #bpy.context.object.pose.bones.constraints["Follow Path"].target = pathname
#        bpy.context.object.pose.bones.constraints["Follow Path"].use_curve_follow = True
#        
#        #Test if the selected object is different from a camera, and set variables accordingly 
#        if bonename.type != 'CAMERA':
#            forwardaxe = 'TRACK_NEGATIVE_Y'
#            upaxe = 'UP_Z'
#        else:
#            forwardaxe = 'TRACK_NEGATIVE_Z'
#            upaxe = 'UP_Y'
#            
#        #Get specific orientations
#        bpy.context.object.constraints["Follow Path"].forward_axis = forwardaxe
#        bpy.context.object.constraints["Follow Path"].up_axis = upaxe
#        
#        override={'constraint':bonename.constraints["Follow Path"]}
#        bpy.ops.constraint.followpath_path_animate(override,constraint='Follow Path')
#        
#        #reselect the path
#        bpy.context.scene.objects.active = pathname
#        bpy.context.object.data.path_duration = duration
#        bpy.ops.object.editmode_toggle()   
#        
#        bonename.location[0] = 0
#        bonename.location[1] = 0
#        bonename.location[2] = 0
#        
#        bonename.rotation_euler[0] = 0
#        bonename.rotation_euler[1] = 0
#        bonename.rotation_euler[2] = 0
       
        return {'FINISHED'}


def menu_item(self, context):
       self.layout.operator(fastpath.bl_idname, text="fastpath", icon="PLUGIN")
       self.layout.operator(fastpath_bone.bl_idname, text="fastpath_bone", icon="PLUGIN")
       
def register():
    bpy.utils.register_module(__name__)
    bpy.types.INFO_MT_curve_add.append(menu_item)

    
def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.INFO_MT_curve_add.remove(menu_item)

if __name__ == "__main__":
    register()

Thank you for your help

Earlier in your script, you’ve assigned the armature object and the bone to variables. Using the these variables you could do:


objectname.pose.bones[bonename.name].constraints['Follow Path'].target = pathname

Using the variables you have assigned, you could actually optimize you code by skipping a lot of the bpy.ops and mode switching.

I see, it’s the armaturename then the bone in the syntax. I’ll never figure out the
bonename.name.

Thank you very much Cmomoney, it helps a lot !

I still have to work on the override, then I’ll optimize following your advices.
I didn’t know that you can change things without mode switching.