How do I fix the "context invalid" issue when using python method weight_paint()
This most likely needs to be wrapped in an add-on that is in the 3d view (as in the button to call this is in the 3d view so that the last user input before this runs is in the 3d view). An operator class, like when you call bpy.ops.paint.weight_paint(stroke=strokes, mode='NORMAL'), often has a poll function as this one does. A poll function basically checks for certain criteria to be met before running its execute method, and one of the most common checks is if the context is correct. If you are running this from anywhere other than the 3d view in weight-paint mode, the context will likely be incorrect.

Here is an add-on demo (very heavily commented):

# Blank Addon

bl_info = {
    "name": "Blank Addon",
    "author": "Anonymous",
    "version": (1, 0),
    "blender": (2, 76, 0),
    "location": "3D View &gt; Tools &gt; Blank",
    "description": "A completely blank addon ;)",
    "wiki_url": "",
    "category": "3D View",
    }

import bpy
from bpy.types import Scene, Panel, Operator
from bpy.props import IntProperty


# UI...this creates a new panel in the 3D View
class BlankAddonPanel_PT(Panel):
    # name of the panel...
    bl_label = "Blank Addon"
    # used to register panel
    bl_idname = "3D_VIEW_PT_layout_BlankAddon"
    # specifies to make panel in 3D View
    bl_space_type = 'VIEW_3D'
    # it is in the tools not the properties region
    bl_region_type = 'TOOLS'
    # only show panel when in object mode
    bl_context = "objectmode"
    # name of the tab for the panel
    # (if this is 'Tools' it will be on the first tab)
    bl_category = 'Blank'

    # the meat of how to draw the panel
    def draw(self, context):
        scene = context.scene
        layout = self.layout

        # create a new column and label it column
        col = layout.column()
        col.label("Blank Column", icon="COLLAPSEMENU")

        # create a button that is linked to the operator
        col.operator("scene.blank_print_ba", icon="QUESTION")

        # create a property field linked to the prop
        col.prop(scene, "blank_prop", slider=True)


# Operator this is setting up what the "button" executes
class BlankPrint_PT(Operator):
    # the label for the button in the UI (if not overwritten in the panel code)
    bl_label = "Do Nothing"
    # the name of the operator (only used in python ie. for ui)
    bl_idname = "scene.blank_print_ba"
    # tooltip for when user hovers over button in UI
    bl_description = "Prints useless information =)"
    # options: can be registered, support undo (Blender does this for you)
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self,context):
        scene = context.scene

        # this is where the meat of your operator would go :-]

        # send a message to the info bar
        self.report({'INFO'}, "I didn't do anything :-D, but your prop is " + str(scene.blank_prop))

        return {'FINISHED'}

# classes to register/unregister
classes = [BlankAddonPanel_PT, BlankPrint_PT]

def register():
    # register each class
    for i in classes:
        bpy.utils.register_class(i)

    # create props
    Scene.blank_prop = IntProperty(name="Blank Prop",default=1,min=0,max=100)

def unregister():
    # unregister classes
    for i in classes:
        bpy.utils.unregister_class(i)

    # delete props...it's very important to delete each prop
    # you add in register here!
    del Scene.blank_prop

if __name__ == "__main__":
    register()