3
$\begingroup$

I'm trying to use a python script as an expression in a driver. It was working fine at first and then all of a sudden I get the error message ERROR: Invalid Python expression.

ERROR: Invalid Python Expression

I've tried running the script in the text editor multiple times with no errors, but I get an error in the driver section. Anyone know how to solve this?

Scrip in text

import bpy

prevTime = 0

###
# Rotates the object with the rotSpeed value in radians/s
###
def rotate(rotSpeed, curRot):
    scn = bpy.context.scene
    curFrame = scn.frame_current
    fps = scn.render.fps

    # Calculate total playtime
    time = curFrame / fps

    # Get delta time
    dt = time - prevTime

    # This will set the current rotation value of the object!!
    newRot = curRot + rotSpeed * dt

    # Set new previous time
    prevTime = time

    return newRot


# Add to driver namaespece to make it accessable     
bpy.app.driver_namespace['RotWithSpeed'] = rotate

EDIT: The error occurs when I add the line "prevTime = time".

$\endgroup$
6
  • $\begingroup$ It looks ok. (preferable if you post code as code rather than image to test) Have you tried the "update dependencies" button? $\endgroup$
    – batFINGER
    Jan 21, 2017 at 13:25
  • $\begingroup$ Added the code as text in my question. Yes I've tried that, didn't make any difference. $\endgroup$
    – Sandsten
    Jan 21, 2017 at 13:35
  • 1
    $\begingroup$ You need to declare prevtime as a global. (although not sure you really need that anyhow since it (frame - 1) eqtn. One issue is that jumps out now I look closer is that you are using the object property you are driving as an input to the driver as well, might cause issues too. $\endgroup$
    – batFINGER
    Jan 21, 2017 at 13:42
  • $\begingroup$ Isn't prevTime global by default when it's declared outside the function? I need the prevTime since it has to work in both directions in time. Tried to use something else as the input rather than the object property itself, the error stays. Also tried to remove the driver and then apply a new one, no difference. $\endgroup$
    – Sandsten
    Jan 21, 2017 at 14:03
  • 1
    $\begingroup$ Did you put global prevTime in the rotate method? $\endgroup$
    – batFINGER
    Jan 21, 2017 at 15:37

2 Answers 2

1
$\begingroup$

I found a solution after a while. Seems like global functions don't work the same way in Blender as in raw Python.

I used mini3d's solution found on the blender forum.

Here's a summary of the solution:

import bpy

# Define global variables
bpy.types.Scene.prevTime = bpy.props.FloatProperty()

def getSettings():
    settings = bpy.data.scenes.get("Settings")
    if settings is None:
        settings = bpy.data.scenes.new("Settings")
    
    return settings

def rotate(rotSpeed, curRot):
    .
    .
    getSettings().prevTime = time
    .
    .

EDIT: Global variables do in fact work the same way. The following solution is much cleaner as suggested by batFINGER

The problem was that I tried to edit a global variable in a function without using the keyword "global".

import bpy

# Define global variables
prevTime = 0

def rotate(rotSpeed, curRot):
    # This will give us the ability to edit the global variable
    global prevTime  
    .
    .
$\endgroup$
2
  • 1
    $\begingroup$ Disagree, globals work the same in blender. Example set up a driver with x(0, 1) as a driver expression ( using pasteall.org/210634/python ). Every time the driver is called the global variable c is updated, and will be by any prop that has f(..) as a driver expression. $\endgroup$
    – batFINGER
    Jan 22, 2017 at 14:40
  • $\begingroup$ No idea why that didn't work when I tried it previously. Your solution is much cleaner. Will update the solution. $\endgroup$
    – Sandsten
    Jan 23, 2017 at 22:50
0
$\begingroup$

This error seems to occur whenever the driver's function raises an exception. It's a shame the error message doesn't contain the stack trace. In your case I think batFINGER is right: prevTime is being written to as a global, so it must be declared at the top of the function as global prevTime. Variables that you only read from don't need to be declared as global.

$\endgroup$

You must log in to answer this question.

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