Importing Common Scope From Designer/Client/Gateway in Script

I’m trying to import stuff from the common scope of a module in the script playground:

import com.company.mymodule.common

I get the following error:

Traceback (most recent call last):
  File "<buffer>", line 1, in <module>
ImportError: No module named common

The designer and client projects have common as a dependency in their pom files.
Also, the build pom has common listed in all scopes:

                        <projectScope>
                            <name>mymodule-common</name>
                            <scope>CDG</scope>
                        </projectScope>

The java console says it has downloaded the common jar and it appears in my .ignition cache directory.
Doing ‘import com.company.mymodule.designer’ works with no problem.
Why am I unable to import things from the common package in the designer’s script playground?

You’ve done a good job trying to provide information but there’s not enough to answer your question.

Can you maybe attach a build of your module? Or email it if you feel it’s sensitive?

SNMP-unsigned.modl (7.3 KB)

I have attached the module. There’s very little content. I’m just trying to verify that I can import stuff from common and common’s dependencies across scopes.

I’m not sure what to tell you… it works for me in both the script playground and a button press in preview mode.

import com.kasacompanies.snmp.common.Nothing

print 'hello'
1 Like

I think maybe it’s because I tried to import the package instead of one of its classes.
If I import Nothing it works, but not with just ‘import com.kasacompanies.snmp.common’ (at least if you try it before importing Nothing just after opening designer). :weary:

Thanks, Kevin.

I seem to be having a similar problem except in gateway scope. I tried to run the import statement in a gateway timer script:

import com.kasacompanies.snmp.common.Nothing

But I get the following error:

com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last): File "", line 1, in ImportError: No module named kasacompanies

at org.python.core.Py.ImportError(Py.java:304)

at org.python.core.imp.import_logic(imp.java:790)

at org.python.core.imp.import_module_level(imp.java:842)

at org.python.core.imp.importName(imp.java:917)

at org.python.core.ImportFunction.__call__(__builtin__.java:1220)

at org.python.core.PyObject.__call__(PyObject.java:357)

at org.python.core.__builtin__.__import__(__builtin__.java:1173)

at org.python.core.imp.importOne(imp.java:936)

at org.python.pycode._pyx8.f$0(:1)

at org.python.pycode._pyx8.call_function()

at org.python.core.PyTableCode.call(PyTableCode.java:165)

at org.python.core.PyCode.call(PyCode.java:18)

at org.python.core.Py.runCode(Py.java:1275)

at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:636)

at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:603)

at com.inductiveautomation.ignition.common.script.TimerScriptTask.run(TimerScriptTask.java:88)

at java.util.TimerThread.mainLoop(Timer.java:555)

at java.util.TimerThread.run(Timer.java:505)

Caused by: org.python.core.PyException: Traceback (most recent call last): File "", line 1, in ImportError: No module named kasacompanies

... 18 common frames omitted

Seems to be fine in the designer so long as you make the classes explicit. It doesn’t seem to be able to use the syntax ‘from com.kasacompanies.snmp.common import *’ in designer.
What am I doing wrong that won’t find package at all in the gateway?
I’ve attached an updated version of my module. There shouldn’t be changes that affect this issue, but I’ll include just in case.
SNMP-unsigned.modl (613.4 KB)

Classes in jars provided by your module aren’t loaded in a ClassLoader that scripts can access (in gateway scope). That it works in the designer and client is a quirk of the architecture - there’s only one ClassLoader so everything is accessible. In the gateway there is a strict hierarchy and modules are at the bottom, each in their own ClassLoader.

When you want to add functionality from Java libraries and make it available in scripting the recommended approach is to use the SDK to add your own system.whatever.doSomeStuff() functions, the implementation of which will come from your module and can access any libraries your module adds.

Alternatively, you can skip the module approach and just drop jar files into the lib/core/gateway and other folders in your Ignition installation. Some people do this. It’s not portable or officially supported though.

1 Like

Hmmm. It doesn’t seem like there are good options. I want to expose snmp4j functionality without creating a bunch of overhead work. It would be a lot of unnecessary work to wrap it into scripting functions and you pointed out the downsides of the other option.
Any way for a script to explicitly load those files? Or import by proxy through module somehow?
How likely is it that the lib/core/gateway method will get broken quickly? In 8.0?

We're not planning to break it for 8.0. Those directories aren't backed up though, so one common thing that can go wrong would be you restore your gateway backup to a new machine and none of your SNMP stuff works for mysterious reasons until someone remembers to go put these jar files in their magic locations.

It looks like I’ll probably go with the lib/core/gateway approach.

Thanks for your help, Kevin.

1 Like

One trick I use in a module to expose a bunch of functionality is to have the script module I load into the script manager expose classes as static public final Class<?> variables. If you load such a script under the expected package name (only in gateway scope), you get the appearance of having those classes in the same classloader. You don’t have to register your script modules under system.*. {That’s where you need them if you don’t want to import, though.}

2 Likes