Set existing animation start frame with script
You're right. Since frame_range is read-only, you can't modify it directly. It gives you the range over which all fcurves of that action are defined. AFAIK you'll have to change fcurve values of that action. Here's a small snippet of how to do that:

&gt;&gt;&gt; for f in line.animation_data.action.fcurves:
...     for k in f.keyframe_points:
...         k.co[0] += frame
...         k.handle_left[0] += frame
...         k.handle_right[0] += frame


...where I assume you have predefined value for frame (e.g. frame = 10)

Here each of k.co, k.handle_left, k.handle_right, have 2 components: frame number and value. We have incremented the frame number of each keyframe (to translate all keyframes by constant amount). You can also play around with advanced things such as scaling or resampling.

Happy PyBlendering! :)



PS: Please note that if inside your duplicateObject(...) function if you're calling bpy.ops.object.duplicate(...), then you don't need to separately create animation data or action, since it is done automatically by the operator.