Global Scripting Variables (Library Script Top-Level Vars)

I need a global variable that is shared between a Gateway Startup script, a Gateway Timer script, and a project library script. It seems like the Gateway Startup and Gateway Timer script already share the same scope (they can both find the variable and execute fine), but the project library script throws a global name 'var' is not defined error. How do I share the variable with the project library script? (the project the library is in is set as the gateway’s scripting project)

Gateway events sharing the same scope is an artifact of some backwards-compatibility decisions long ago. Generally, you would use a dictionary or similar defined in the top level of your project script. Those you can access by full name from elsewhere. (Elsewhere in the same scope, that is. “project library” isn’t a scope. Project libraries run in the scope they are called from.)

In that case, the script is being called from a Tag Change event script, which executes on the Gateway, no? So shouldn’t it have access to that global variable?

No, because only gateway events themselves have that funky “scope”–it is a python “scope”, not an Ignition “scope”. Everything else in Ignition follows modern python “scope”, where each script module’s top level is independent of other script module’s top levels.

You really should not use that legacy behavior. There be dragons. Use library script top-level named objects instead.

Ok, and how would I do that?

In a project script named myLibraryScript:

mySharedVar = 45

def someFunction():
    print mySharedVar
    # the following is discarded as a function-local assignment
    mySharedVar = 200

def anotherFunction():
    global mySharedVar
    mySharedVar = 300

In some other script:

myLibraryScript.mySharedVar = 100

Thanks Phil. You’re always so helpful. I didn’t even know this was possible and it’s exactly what I needed.

Be aware that the value will be lost if you edit and save the project–that causes a script restart and the project scripts will be re-run from scratch.

If you need a value that will survive that, you will need to use system.util.getGlobals(). Take care with that, though: if you store any custom classes there, you will leak gobs of memory when you edit the origin project. Some more guidance:

Thanks for the heads up. I don’t think I’ll have issues with that with my setup. My library script creates the global var and sets the initial value. This “initialization” script is called from my gateway startup event (which is triggered on a project save) and then the global var is set from within that same startup script and read-only on other scripts.

I was looking into saving a dictionary in a tag but I get many errors.

This solution might also be a good approach.

mySharedVar will be available forever?

A script that runs on a gateway update could solve that problem?

Yes and no. As long as there are no errors loading the script it is defined in, it will always exist. It may not have the expected value if the script restarts. There are gateway globals from system.util.getGlobals() that can help, but there are memory-leakage pitfalls. Search the forum for “getGlobals” for numerous discussions on this.

Consider experimenting yourself until you understand all of the combinations.