Scripting -- Can't figure out how to use correct contexts? I'm trying to write a script to create some objects along and around a curve object, set up for a generative modeling thing, to make randomized "tentacles" out of paths.

Anyways! I'm approaching this by creating an empty at the root of any selected curve, putting a "follow path" constraint on the empty, targeting the curve, animating the path, and then creating objects relative to the empty's location and orientation on different frames, staggering some objects like that.

What I've got so far looks like this:

for curve in operable:
    print("Doing curve")
    rootLoc = curve.data.splines[0].points[0].co
    emptyLoc = (curve.matrix_world * rootLoc)
    bpy.ops.object.empty_add(type='ARROWS')
    bpy.context.object.name = "empty_" + curve.name
    bpy.ops.object.constraint_add(type='FOLLOW_PATH')
    bpy.context.object.constraints['Follow Path'].target = curve
    old_area = bpy.context.area.type
    bpy.context.area.type = 'PROPERTIES'
    bpy.context.space_data.context = 'CONSTRAINT'
    bpy.ops.constraint.followpath_path_animate(constraint='Follow Path', length=frame_steps)
    bpy.context.object.constraints['Follow Path'].use_curve_follow = True
    bpy.context.area.type = old_area
    bpy.data.objects['empty_' + curve.name].location = emptyLoc.xyz


However, in the "followpath_path_animate" line, I get an error from that function's "poll()" saying only that "the context is incorrect".

For one, if someone could tell me what context I need to be in and how to get there, that would be great.

It would also be great if someone could explain to me how in the world I'm supposed to figure out what context to be in to run these functions! You'd think this would be at least vaguely documented...

I found the code related to this function in the source code, found that this is the poll() function used:

static int edit_constraint_poll_generic(bContext *C, StructRNA *rna_type)
{
    PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", rna_type);
    Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C);

    if (!ptr.data) {
        CTX_wm_operator_poll_msg_set(C, "Context missing 'constraint'");
        return 0;
    }

    if (!ob) {
        CTX_wm_operator_poll_msg_set(C, "Context missing active object");
        return 0;
    }

    if (ob-&gt;id.lib || (ptr.id.data &amp;&amp; ((ID *)ptr.id.data)-&gt;lib)) {
        CTX_wm_operator_poll_msg_set(C, "Cannot edit library data");
        return 0;
    }

    return 1;
}


This is pretty cryptic to me, seems to check whether the active context is of type "constraint", but I thought I'd done that. Not sure how to resolve that.
I encountered a similar error recently, and thought of adding another solution in addition to the one from @sambler , for the sake of posterity.

The line of code that caused the exception was:

bpy.ops.constraint.followpath_path_animate(constraint='Follow Path')


and, the exception was as follows:

Traceback (most recent call last):
  File "/Users/xxxxxxx/Workspace/blender/moveAlongPath.py", line 30, in &lt;module&gt;
    bpy.ops.constraint.followpath_path_animate(constraint='Follow Path')
  File "/Applications/Blender/blender.app/Contents/MacOS/../Resources/2.76/scripts/modules/bpy/ops.py", line 189, in __call__
    ret = op_call(self.idname_py(), None, kw)
RuntimeError: Operator bpy.ops.constraint.followpath_path_animate.poll() Context missing 'constraint'


Digging into the source code of ops.py that's mentioned in the exception, I ended up at the documentation for bpy.ops and noticed the section on "Overriding Context". The exception's indication of Context missing 'constraint' seemed to ring a bell, and I changed the above line of code to the following:

override={'constraint':mycube.constraints["Follow Path"]}
bpy.ops.constraint.followpath_path_animate(override,constraint='Follow Path')


and, voila! it worked. So, it seemed that somehow the data on the constraint was missing in the context, and injecting the constraint information using the override helped the engine find the constraint where it expected. 

Full working code:

import bpy
import math

"""
blender -b template.blend -P moveAlongPath.py
"""

scene = bpy.data.scenes["Scene"]
mycube = bpy.data.objects["Cube"]

scene.frame_start = 1
scene.frame_end = 100

# Add a nurbs curve
bpy.ops.object.select_all(action = "DESELECT") # Deselect all objects
bpy.ops.curve.primitive_nurbs_circle_add() # Adds a Nurbs Circle and sets it to selected object
bpy.ops.transform.resize(value=(3,3,3)) # Increase the size of the circle
path = bpy.context.selected_objects[0] # Get the currently selected object and get a handle

# Select the cube, and set it to the active object
mycube.select = True
bpy.context.scene.objects.active = mycube

# Add the follow path constraint to the cube, and set target as the Nurbs Circle we just added
mycube.constraints.new('FOLLOW_PATH')
mycube.constraints["Follow Path"].target = path
mycube.constraints["Follow Path"].forward_axis = 'FORWARD_X'
mycube.constraints["Follow Path"].use_curve_follow = True
override={'constraint':mycube.constraints["Follow Path"]}
bpy.ops.constraint.followpath_path_animate(override,constraint='Follow Path')

# Render the animation
scene.render.filepath = "render/anim"
scene.render.image_settings.file_format = "AVI_JPEG"
bpy.ops.wm.save_as_mainfile(filepath="moveAlongPath.blend")
bpy.ops.render.render(animation=True)