1
$\begingroup$

I have the following test code that I am getting the infamous:

"RuntimeError: Operator bpy.ops.paint.weight_paint.poll() failed, context is incorrect".  

I cannot figure out what the context issue is related to, is it the values for the stroke that I am trying to use, or selection, or something else. Any help would be greatly appreciated!

Setup: a single plane that is subdivided multiple times it contains a single vertex group with all vertexes included called 'test'

Code:

strokes = []
brushOp = {
  "is_start":True, 
  "location":(0.0, 0.0, 0.0),
  "size": 1.0,
  "time":0.0,
  "pressure": 0.0,
  "pen_flip":False,
  "mouse":(0.0, 0.0) 
}
strokes.append(brushOp)
strokes.append({
   "is_start":False, 
   "location":(1.0, 1.0, 0.0),
   "size": 1.0,
   "time":0.0,
   "pressure": 0.0,
   "pen_flip":False,
   "mouse":(0.0, 0.0) 
})

bpy.ops.paint.weight_paint_toggle()
bpy.ops.object.vertex_group_set_active(group='test')
bpy.data.brushes['Draw'].stroke_method = 'LINE'
bpy.ops.paint.weight_paint(stroke=strokes, mode='NORMAL')
$\endgroup$
6
  • $\begingroup$ are you running this from a text editor or in the context of an addon? $\endgroup$
    – aliasguru
    Jul 30, 2016 at 6:43
  • 2
    $\begingroup$ Related blender.stackexchange.com/questions/6101/… Make up a context override dictionary (prob: "window", "space_data", "area", "region") and pass it to the operators. $\endgroup$
    – batFINGER
    Jul 30, 2016 at 7:40
  • $\begingroup$ @aliasguru: I am running it from the text editor. What I would ultimately like is to run it from the command line with no UI at all. Maybe this just isn't possible for all ops.paint methods. $\endgroup$
    – jasowill
    Jul 30, 2016 at 17:47
  • $\begingroup$ I believe it is possible, the link batFINGER posted before contains methods to create a 'fake' context and pass it to the operators. So in essence, you pretend that the function was run from 3D View, even though it was run from the console. $\endgroup$
    – aliasguru
    Jul 30, 2016 at 18:02
  • $\begingroup$ @aliasguru: Yes, that was a great link and good information regarding how to override the context (certainly a piece that I was missing). Unfortunately, when I override the context with what I think makes sense, it crashes blender. Grateful to you both for the insight you have given me. $\endgroup$
    – jasowill
    Jul 30, 2016 at 22:24

2 Answers 2

1
$\begingroup$

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 > Tools > 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()
$\endgroup$
1
$\begingroup$

When making your stroke list via python you will need to add a name key to your StrokeElement dictionary.

Also override context for area, space_data and region.

import bpy

strokes = []
brushOp = {
  "name": "Bob",
  "is_start":True, 
  "location":(0.0, 0.0, 0.0),
  "size": 1.0,
  "time":0.0,
  "pressure": 0.0,
  "pen_flip":False,
  "mouse":(0.0, 0.0) 
}
strokes.append(brushOp)
strokes.append({
   "name": "Bob",
   "is_start":False, 
   "location":(1.0, 1.0, 0.0),
   "size": 1.0,
   "time":0.0,
   "pressure": 0.0,
   "pen_flip":False,
   "mouse":(0.0, 0.0) 
})
print("-" * 72)
context = bpy.context
screen = context.screen
c = context.copy()
for a in screen.areas:
    if a.type == 'VIEW_3D':
        c["area"] = a
        c["space_data"] = a.spaces.active
        c["region"] = a.regions[-1]

if context.object.mode != 'WEIGHT_PAINT':
    bpy.ops.object.mode_set(mode='WEIGHT_PAINT')
bpy.ops.object.vertex_group_set_active(group='Group')
bpy.data.brushes['Draw'].stroke_method = 'LINE'
bpy.ops.paint.weight_paint(c, stroke=strokes, mode='NORMAL')
$\endgroup$
1
  • $\begingroup$ having exactly 6.000 rep points looks very cool, but I just have to upvote this answer, sorry :) $\endgroup$
    – aliasguru
    Aug 4, 2016 at 8:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .