Poll conditions documentation

Hi !

While working on different scripts, I’m regularly confronted to the famous “context is incorrect” error thrown by the poll() function. If in some cases it can be quite easy to figure what’s wrong, there are some where it can be really hard to understand what’s happening (my last example : bpy.ops.mesh.uv_texture_add() works fine in python console or when running a script from the TextEditor, but fail when called in a custom operator used in a UIPanel)

So, instead of continuously asking for each specific case I’m confronted to, I’m wondering if there is some documentation on the correct contexts expected by the different poll implementations. I tried to find this kind of information in the scripts embedded in Blender but didn’t success.

Any ideas ?

It should work from a panel.

layout = self.layout
col = layout.column()
col.operator("mesh.uv_texture_add")

Make sure youve got an object selected that can use a UV Map. like a mesh.

To check poll, i think you have to look at the definition of the operator.

>>> bpy.ops.mesh.uv_texture_add.get_rna()
<bpy_struct, MESH_OT_uv_texture_add at 0x00000000>

‘MESH_OT_uv_texture_add’

This ones written in c.

// source\blender\editors\mesh\mesh_ops.c
void MESH_OT_uv_texture_add(wmOperatorType *ot)
{
    /* identifiers */
    ot->name = "Add UV Map";
    ot->description = "Add UV Map";
    ot->idname = "MESH_OT_uv_texture_add";
    
    /* api callbacks */
    ot->poll = layers_poll;
    ot->exec = mesh_uv_texture_add_exec;

    /* flags */
    ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}

// source\blender\editors\mesh\mesh_data.c
static int layers_poll(bContext *C)
{
    Object *ob = ED_object_context(C);
    ID *data = (ob) ? ob->data : NULL;
    return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib);
}

return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib);

i dont know if there is documentation or another way to check poll.

OK, so the poll implementations are within the source code.

Unfortunately, it doesn’t work … in my specific case. In fact, I found what the problem is : my panel is created in the scene panel, not the object panel, and the poll function doesn’t like it (I don’t really understand the purpose of such limitation). It really annoys me because I want to build some selection wide control panel, and I thought that the scene panel was the best place to work in. I believe I have to move everything in the object panel.

Thanks for the quick answer !

I tried to set the context for the operator, but it doesn’t seem to work…

    col.context_pointer_set("data", context.scene.objects.active.data)
    col.operator("mesh.uv_texture_add")

So there’s really a limitation in the built-in operator, but you can still write your own:

import bpy
class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "mesh.uv_texture_add_custom"
    bl_label = "UV Texture Add (Custom)"


    @classmethod
    def poll(cls, context):
        return (context.active_object is not None and
                context.active_object.type == 'MESH')


    def execute(self, context):
        context.active_object.data.uv_textures.new()
        return {'FINISHED'}


class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "scene"


    def draw(self, context):


        layout = self.layout
        col = layout.column()
        col.operator("mesh.uv_texture_add_custom")


def register():
    bpy.utils.register_module(__name__)




def unregister():
    bpy.utils.unregister_module(__name__)




if __name__ == "__main__":
    register()

Yes, to use the data module and not the ops module is a good alternative here, but sometimes there are operations you can’t do throught data (baking for example). I understand that the right context is necessary in order to achieve the operation, but if I have to dig in the source code to understand what’s wrong, it will be a bit frustrating. And still, I don’t understand that some context limitations are tied with the UI (like the impossibility to apply the mesh.uv_texture_add operator from the scene panel).

I don’t know if I’m alone here, but I think that this kind of problem can really bother new users and should be documented. Or maybe I’m missing something ?

doesn’t bake op work if added to scene tab? If so, have a look at the console output, sometimes you find hints there (especially when overriding context). Of course, it would be nice if there was a low-level function for every operator action.