function produces 'TypeError' only in frame_change_pre handler

I’ve just started trying my hand at python scripting in Blender 2.77a on Xubuntu 16.04.

I wrote a script to mess about with the ‘frame_change_pre’ handler - the callback function creates a new object every frame.

The problem is that the script fails with the linux terminal displaying ‘TypeError: addBlock() takes 0 positional arguments but 1 was given’ when the frame is changed, but if I call the addBlock() function directly in the script it works without a problem. I have hunted for hours but I can’t see what the problem is. I saw a reference to class methods requiring a ‘self’ parameter in the declaration, but I tried that and it didn’t make any difference.

This is the complete script:


import bpy
import math
from mathutils import Vector
from mathutils import Euler

scn = bpy.context.scene

def createBlock(name='Block', scale=(1,1,1), rotn=(0,0,0), locn=(0,0,0)):

    verts = [(1, 1, 1),
             (1, -1, 1),
             (-1, -1, 1),
             (-1, 1, 1),
             (1, 1, -1),
             (1, -1, -1),
             (-1, -1, -1),
             (-1, 1, -1)]

    faces = [(0, 1, 2, 3), 
             (4, 5, 6, 7), 
             (0, 4, 5, 1), 
             (1, 5, 6, 2), 
             (2, 6, 7, 3), 
             (3, 7, 4, 0)]

    v_len = len(verts)
    
    for v in range(0, v_len):
        if scale != (1,1,1):
            verts[v] = tuple(v1 * v2 for v1, v2 in zip(verts[v], scale))
        if rotn != (0,0,0):
            vec = Vector(verts[v])
            eul = Euler(rotn, 'XYZ')
            vec.rotate(eul)
            t = vec.to_tuple(4)
            verts[v] = t   

    me = bpy.data.meshes.new(name+'Mesh')
    ob = bpy.data.objects.new(name, me)
    ob.location = locn
    ob.show_name = True
 
    # Link object to scene and make active
    scn.objects.link(ob)
    scn.objects.active = ob
    ob.select = True

    me.from_pydata(verts, [], faces)
    me.update(calc_edges=True)

def addBlock():
    frame = scn.frame_current
    angle = math.radians(frame * 30)
    x = frame * math.cos(angle)
    y = frame * math.sin(angle)
    z = frame * 0.5
    name = 'Slab{0:03d}'.format(frame)
    createBlock(name, scale=(1,1,0.1), rotn=(0,0,angle), locn=(x,y,z))

# This produces an error when the frame is changed
bpy.app.handlers.frame_change_pre.append(addBlock)

# This works
addBlock()

Ok, I may have solved this. The handler works if I declare the callback function with a ‘scene’ parameter.

The first example in the ‘Application Handlers’ section of the Blender Python API uses that parameter, but it is not explicitly stated anywhere that it is required, so I assumed it was just an optional variable used for the example.

When I modified the function declaration to be:


def addBlock(scene):
    frame = scene.frame_current
    angle = math.radians(frame * 30)
    x = frame * math.cos(angle)
    y = frame * math.sin(angle)
    z = frame * 0.5
    name = 'Slab{0:03d}'.format(frame)
    createBlock(name, scale=(1,1,0.1), rotn=(0,0,angle), locn=(x,y,z))

the script worked as expected.

Can someone confirm that this is the reason for the error? If so, I’ll mark it as solved.