Skip to content

SCR307: redefined-event-handler

Event script file that rebinds its handler to something Ignition cannot call

Code SCR307
Name redefined-event-handler
Category Scripts (SCR)
Default severity error
Enabled by default yes
Fix available no
ign-lint equivalent none

Checks the module-level code after the function of a gateway timer, tag change, message handler, startup, shutdown or update script file, or of a WebDev handler. Ignition compiles the file under its canonical header (def handleTimerEvent():, def handleMessage(payload):, ...), runs the module code, then looks the handler up by name and calls it with the canonical arguments, by position. So the last module-level binding of the name is what runs. The rule reports when that binding is certainly one Ignition cannot call:

  • a def (or lambda) that cannot take the canonical number of positional arguments, such as def handleTimerEvent(event): after the header: every event fails with TypeError: handleTimerEvent() takes exactly 1 argument (0 given);
  • a value that is not callable (handleTimerEvent = None, a number, a string, a list, tuple, dict or set display or comprehension): Ignition reports The function 'handleTimerEvent' is not defined. A comparison, an operator, a call or a backquote is not followed: each runs code that may return a function (__eq__ may return a lambda, and Jython then calls it). True, False and None count only where they are Jython's builtins: all three are names a module can rebind (True = lambda: 7, import x as None);
  • del handleTimerEvent: the same.

Only bindings at module level that always run are followed: one inside an if, a loop, a try or a with, an import, a class, any other value, exec or import * make the outcome unknown, and nothing is reported. So does any binding of the name that the module-level statements do not show, found from every scope: a global declaration of the name in a function or class (also in the handler itself, which module code may call), a list comprehension at module level whose variable is the name (Python 2 comprehensions leak it), exec, import * or a write through globals() or vars() in any scope, and code that reaches a frame or the interpreter. Bindings that stay in their scope (a local of a function, a class attribute, the variable of a generator expression or of a comprehension inside a function) do not matter. Parameter names do not matter (Ignition passes the arguments by position), and defaults or *args that make the call fit are fine.

Verified on an Ignition 8.3.3 gateway for timer, tag change, message, startup, shutdown and update scripts and WebDev handlers. Scheduled scripts run their first definition whatever is bound later, so for them only del is reported (the script then fails to load with a NameError). Perspective session and page events and Vision client events are not checked.

The handler never runs. The error is logged on the gateway (for timers only the first time; later ones are logged at debug level), and for a message handler the caller of system.util.sendRequest gets the error.

def handleTimerEvent():
poll()
def handleTimerEvent(event):
poll()

Use instead:

def handleTimerEvent():
poll()

Generated from the rule metadata by iglint generate-docs; iglint rule SCR307 prints the same page in the terminal. Source: docs/rules/SCR307.md.