Correct invocation of runScript?

OK I admit it, I’m getting confused over how to specify the script to run during the Startup event on an object.

I have a View that has:

  • a script attached to the root object called “testMethod” (with no parameters)
  • A Startup event on the root object that attempts to call testMethod

In the startup event I try to invoke it like

runScript(“self.testMethod”,0)

But I am getting a jython exception of “NameError”
I don’t think that I am doing anything wrong, or misspelling anything.

My complete scripts are:

def runAction(self):
	"""
	Method that will run whenever the selected event fires.

	Arguments:
		self: A reference to the component that is invoking this function.
	"""
	#import java.lang.Exception
	
	try:
		myEvent = "onStartUp"
		myMethod = "self.testMethod"
		runScript(myMethod,0)
	except:
		print "### except: " + myEvent + " Failed to run " + myMethod 
		print "### except: " + str(sys.exc_info()[0])

and

def testMethod(self):
	"""
	Custom method that can be invoked directly on this component.

	Arguments:
		self: A reference to the component that is invoking this function.
	"""
	print "### testMethod()"

and the wrapper log entry is simply

INFO   | jvm 1    | 2022/05/13 15:37:06 | ### except: onStartUp Failed to run self.testMethod
INFO   | jvm 1    | 2022/05/13 15:37:06 | ### except: <type 'exceptions.NameError'>

What am I doing wrong?!?!?

What kind of object are you doing this on?

It is on the co-ordinate root container of a perspective View

Is there a reason you’re doing this via an expression and runscript, vs just invoking your custom method directly?

I’m not sure the expression context automatically brings self into scope; maybe try this? Nevermind, looks like self should be correct.

Based on this I need to resolve the server and path of a tag from its pathname in order to invoke system.opc.writeValue . As this should be constant over the life of a session I should only need to look the info up once and locally cache it. I was trying to do this in the object where the info was needed. I was choosing to do the work in a separate function than the startup event in order to better organize my code.

And what do you mean by?

can I invoke testMethod() directly from the Startup event?

Oh, okay, nevermind. We’re both confused :slight_smile:

runScript is an expression function - it’s designed as a bridge/escape hatch from the limited capabilities of expressions to the power of Jython:
https://docs.inductiveautomation.com/display/DOC81/runScript

If you have a script action already (def runAction above) - you can just call your custom method directly:

	try:
		self.testMethod()
	except:
		print "### except: " + "onStartup" + " Failed to run " + "testMethod" 
		print "### except: " + str(sys.exc_info()[0])

If you really want to make things dynamic, then you would use getattr on self:

def runAction(self):
	"""
	Method that will run whenever the selected event fires.

	Arguments:
		self: A reference to the component that is invoking this function.
	"""
	#import java.lang.Exception
	
	try:
		myEvent = "onStartUp"
		myMethod = "self.testMethod"
		getattr(self, myMethod)() #second parens to invoke
	except:
		print "### except: " + myEvent + " Failed to run " + myMethod 
		print "### except: " + str(sys.exc_info()[0])

That part definitely makes sense - you may also want to consider moving your logic into project level shared scripts so that you can re-use these scripts across multiple views/components more easily.

OK … that worked!!!

I now better understand the use of runScript!

But that leads me to a question.

If I have a hierarchy like

View
   +--root--+
         |  |--ScriptB
         |
         +--Object1
         |  
         +--Object2----+
                       |--EventA
                       |--ScriptA

And I have event EventA on Object2 that uses a runScript to call a function ScriptA on Object2, from within ScriptA, can I now invoke ScriptB via something like:

self.parent.ScriptB()

??

I’ve already partitioned my objects across a handful of mutually exclusive functionality, so while your suggestion is something to keep in mind, it’s going to be more complicated to come up with a simple library that encompasses all the functional that I want.

I think this should work, yes.

I just tested it and it did work!

1 Like