4
$\begingroup$

I want to use the folowing driver:

abs(((frame+45) % 90)-45)

But it does nothing. I tried also #abs and #frame etc. But nothing, the thing is purple as expected. How can I debug this?

$\endgroup$
3
  • $\begingroup$ Can you include a small blend file in your question that shows the problem? (How to add a blend file) Or at least a screenshot of the driver editor showing all of the settings? $\endgroup$ May 17 at 13:47
  • $\begingroup$ Does this answer your question? $\endgroup$ May 17 at 15:03
  • $\begingroup$ I wanted to vote to reopen, but sometimes it's easier to swim with the current so I added another answer to one of the parents as well. Though I think I will be linking to this page on other related questions. BTW I didn't know the duplicte can point to multiple answers... $\endgroup$ May 18 at 13:43

3 Answers 3

5
$\begingroup$

TLDR

Either:

  • Replace % with fmod for a simple (FAST) expression:
radians(abs(fmod(frame+45, 90) -45))
  • Replace abs with fabs for a Python (SLOW) expression:
radians(fabs((frame+45) % 90 - 45))

(In both cases I added radians, because that's probably what you actually intended)

Blender fails to parse the driver expression

When you try your driver: abs(((frame+45) % 90)-45), Blender first tries to tokenize it using its simple evaluator. You can read about it in the Blender docs:

Drivers Panel > Simple Expressions

Source code: source/blender/blenlib/intern/expr_pylike_eval.c

Notice there's no % operator listed in the documentation (or binary modulo opcode in the code), Blender detects it and falls back to allow the expression to be run by much more powerful Python interpreter.

'Slow expression' (Python code) deemed unsafe

Since Python is Turing-complete, its code can do everything, including formatting your hard drive (and worse!). To protect against malicious code in .blend files downloaded from the Internet, Blender checks all names and opcodes (basically operators) used against a whitelist of things that are definitely safe:

names:

  • builtins (basic): all, any, len;
  • builtins (numeric): max, min, pow, round, sum;
  • types: bool, float, int;
  • from bl_math module: clamp, lerp, smoothstep,

Additionally, all functions from math module are added: acos, acosh, asin, asinh, atan, atan2, atanh, ceil, copysign, cos, cosh, degrees, dist, erf, erfc, exp, expm1, fabs, factorial, floor, fmod, frexp, fsum, gamma, gcd, hypot, isclose, isfinite, isinf, isnan, isqrt, lcm, ldexp, lgamma, log, log1p, log10, log2, modf, pow, radians, remainder, sin, sinh, sqrt, tan, tanh, trunc, prod, perm, comb, nextafter, ulp

opcodes:

  • unary operators: +, -, not, ~ (UNARY_POSITIVE, UNARY_NEGATIVE, UNARY_NOT, UNARY_INVERT);
  • binary operators: @, **, *, %, +, -, [x](subscription operator), //, /, <<, >>, &, ^, | (BINARY_MATRIX_MULTIPLY, BINARY_POWER, BINARY_MULTIPLY, BINARY_MODULO, BINARY_ADD, BINARY_SUBTRACT, BINARY_SUBSCR, BINARY_FLOOR_DIVIDE, BINARY_TRUE_DIVIDE, BINARY_LSHIFT, BINARY_RSHIFT, BINARY_AND, BINARY_XOR, BINARY_OR);
  • comparison operators: <, <=, >, >=, ==, != (COMPARE_OP(<), COMPARE_OP(<=) etc.);
  • collection constructors: (1, 2), [1, 2], {1, 2}, {'a': 1, 'b': 2} (BUILD_TUPLE, BUILD_LIST, BUILD_SET, BUILD_MAP);
  • ternary conditional operator: a if c else b (POP_JUMP_IF_FALSE, POP_JUMP_IF_TRUE);

As well as some low-level opcodes you probably don't need to know:

inplace versions of the binary operators - not assignment operators! (INPLACE_MATRIX_MULTIPLY, INPLACE_FLOOR_DIVIDE, INPLACE_TRUE_DIVIDE, INPLACE_ADD, INPLACE_SUBTRACT, INPLACE_MULTIPLY, INPLACE_MODULO, INPLACE_POWER, INPLACE_LSHIFT, INPLACE_RSHIFT, INPLACE_AND, INPLACE_XOR, INPLACE_OR); stack management opcodes: POP_TOP, ROT_TWO, ROT_THREE, DUP_TOP, DUP_TOP_TWO, NOP; code flow opcodes: RETURN_VALUE, JUMP_FORWARD, JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP, JUMP_ABSOLUTE; other low level opcodes: LOAD_GLOBAL, LOAD_FAST, STORE_FAST, DELETE_FAST, LOAD_DEREF, STORE_DEREF; "special cases" (which qualifies really as the same as previous group, but could be dangerous without additional checks done in the Blender code): LOAD_CONST, LOAD_NAME, CALL_FUNCTION, CALL_FUNCTION_KW, CALL_FUNCTION_EX,

Source code: source/blender/python/intern/bpy_driver.c

Notice there's no abs name, so your driver won't pass the security check!

Problem summary

You can see the result in the console (Window > Toggle System Console)

BPY_driver_eval() - restricted access disallows name 'abs', enable auto-execution to support

If your code had only abs name without % operator, it would parse as a simple expression. If it would have only % without abs, it would fail to parse as a simple expression, but would be allowed as a Slow Expression: .

However your code first fails to be parsed as a simple expression due to unsupported % operator, and then fails again at the security check due to abs name not being on a slow expression whitelist.

The solution

Having both % and abs forces you to either disable the security checks, as suggested by Chris - you should read about the security considerations here:

How to randomize any value every frame between specific interval?

Or alternatively you can redesign your formula, which in this case is trivial:

  • first you should consider if you can satisfy the fast expression requirements, by replacing your % operator. Most of the time* a % x works exactly the same as fmod(a, x), therefore the fix is trivial: instead of abs(((frame+45) % 90)-45) do abs(fmod(frame+45, 90)-45).

  • if you can't make the simple expression, forget about all of its requirements altogether, and focus on the slow expression requirements written directly in this post. It's probably a mistake that abs is not allowed and I'll suggest a change. However, there's fabs available.

Side notes

Chris noticed how the values you use are typical angles expressed in degrees, and yet inside drivers (or any other form of scripting) the angle values are interpreted as radians. Therefore what you probably want is radians(value_expressed_in_degrees) to convert the degrees to radians.

* - the differences between fmod and modulo operator %:

>>> vs = lambda a, b: (a % b, fmod(a, b))
>>> vs(5, 2)
(1, 1.0)

>>> vs(5, -2)
(-1, 1.0)

>>> vs(-5, 2)
(1, -1.0)

>>> vs(-5, -2)
(-1, -1.0)

So beware of the sign. % uses the sign of second operand, and fmod uses the sign of first operand. If you really need exactly % functionality, replace a % b with abs(fmod(a, b))*(b/abs(b)) or fmod(-abs(a), b) if b < 0 else fmod(abs(a), b):

>>> vs = lambda a, b: (a % b, abs(fmod(a, b))*(b/abs(b)) ,fmod(-abs(a), b) if b < 0 else fmod(abs(a), b))
>>> vs(5, 2)
(1, 1.0, 1.0)

>>> vs(5, -2)
(-1, -1.0, -1.0)

>>> vs(-5, 2)
(1, 1.0, 1.0)

>>> vs(-5, -2)
(-1, -1.0, -1.0)
$\endgroup$
1
  • 1
    $\begingroup$ Comments are not for extended discussion; this conversation has been moved to chat. $\endgroup$
    – Timaroberts
    May 18 at 6:15
3
$\begingroup$

Make sure you have this checked: "Auto run python scripts" in your preferences.

enter image description here

Note: i assume you want to drive a rotation? be aware that you have to work with radians, not degrees, so just change your formula so that it calculates in radians, then it should work

$\endgroup$
10
  • 1
    $\begingroup$ It's a driver. You don't need to do that for drivers. $\endgroup$ May 17 at 13:45
  • $\begingroup$ and again, Marty you are wrong. Just try it out, read the logging and you will see: Error in Driver: The following Python expression failed: 'abs(((frame+45) % 90)-45)' BPY_driver_eval() - restricted access disallows name 'abs', enable auto-execution to support $\endgroup$
    – Chris
    May 17 at 13:46
  • $\begingroup$ i just wonder who upvotes your wrong (again and again) comments.... $\endgroup$
    – Chris
    May 17 at 13:47
  • $\begingroup$ @MartyFouts: Please, open up a new blend file where auto run is off, then copy his statement in the driver of rotation -> you will get that error and the driver won't work. But...after checking and then it works, i have to admit, if i uncheck the auto run, it still works. i have no idea why. i tested with 3.3. alpha $\endgroup$
    – Chris
    May 17 at 13:57
  • 1
    $\begingroup$ I am the one who upvoted, because i genuinely though I had this very option disabled at all times myself and didn't encountered the issue. This discussion doesn't need to get personal, doesn't it? Though now I am even more confused because, this expression was working on my side before i restarted Blender, but now it says it's an invalid expression... $\endgroup$
    – L0Lock
    May 17 at 14:02
2
$\begingroup$

To sum up the discussion in the comments of the two existing answers:

There are two approaches you can take:

  • You can follow the recommendation in this answer and enable Auto-Run. But that produces a different problem: you've decreased the security of your Blender usage because now anytime you download a Blender file and open it your vulnerable to Python scripting attacks.

  • You can follow the recommendation in this answer, ignore the actual text of the error message, and find a scripted expression that doesn't trigger the warning. But that's not well documented and as you can see by the confusion in the comments might not be easy to do.

I would recommend, and have upvoted the second answer, ie, use radians(abs(fmod(frame+45, 90) -45)) in your driver to avoid the error. But I would not be honest if I did not admit that most Blender users never see this kind of problem simply because we ignore the security implication and enable auto-run.

You have to decide how much security risk you are willing to tolerate. Select one of those two approaches, accept that answer, and good luck.

$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.