Attribute Error in Component Custom Method

The script (below) when residing in a Project Library works when I call it from a button script. To implement best practices I put placed the script as a custom method in my button component.

def incrementVerNum4th(self, projectArea, topic, notes):
	newVerNum = system.tag.readBlocking('[gw1]_Project Version Information/verNum4th')[0].value + 1
	system.tag.writeBlocking('[gw1]_Project Version Information/verNum4th', newVerNum)
	addVersionNote(projectArea, topic, notes)

My button actionPerformed event script calling the custom method is (line 39 in the image):

event.source.incrementVerNum4th(projectArea, topic, notes)

And the result is this error message:

AttributeError: 'com.inductiveautomation.ignition.common.script.Imm' object has no attribute 'tag'

I donā€™t get itā€¦I thought custom method scripts were just like any other script. I check the manual (Custom Component Methods - Ignition User Manual 8.1 - Ignition Documentation and Extension Functions - Ignition User Manual 8.1 - Ignition Documentation) but didnā€™t see any restrictions or entries in the forum that match. I even tried it with an import system statement (as seen in the extension functions document) but I get the same error. Any ideas?

Thank you and regards,
Ted.

This might helpā€¦

Traceback (most recent call last):
File ā€œevent:actionPerformedā€, line 77, in
File ā€œā€, line 6, in addVersionNote
AttributeError: ā€˜com.inductiveautomation.ignition.common.script.Immā€™ object has no attribute ā€˜tagā€™

at org.python.core.Py.AttributeError(Py.java:207)
at org.python.core.PyObject.noAttributeError(PyObject.java:1032)
at org.python.core.PyObject.__getattr__(PyObject.java:1027)
at org.python.pycode._pyx136.addVersionNote$1(<custom-function addVersionNote>:16)
at org.python.pycode._pyx136.call_function(<custom-function addVersionNote>)
at org.python.core.PyTableCode.call(PyTableCode.java:171)
at org.python.core.PyBaseCode.call(PyBaseCode.java:189)
at org.python.core.PyFunction.__call__(PyFunction.java:446)
at org.python.core.PyMethod.__call__(PyMethod.java:171)
at org.python.pycode._pyx134.f$0(<event:actionPerformed>:77)
at org.python.pycode._pyx134.call_function(<event:actionPerformed>)

You need to call it with self.addVersionNote.
Oh waitā€¦
Nvm

A few things:

1.) Screen shots are really unhelpful, using the preformatted text is much better
2.) The stack trace you posted is incomplete
3.) The error occurs on Line 77 which isnā€™t visible in your screen shot.
4.) There is no need to import system

Edit: 5.) The error occurs in the function addVersionNote which you havenā€™t shown

1 Like

Found an almost identical reference in "system" functions not available from client that refers to Using system.* inside a custom function? - #9 by systemparadox

No sure how the work-arounds apply to my issueā€¦trying to find out the status of ticket # 44974.

@lrose Hi, thanks for replying.
Oh yeah, wrong stack trace, no matter though as it gives the same error calling system.tag.readBlocking.

From memory the only time you need to import system is when you define a function within a gateway scoped event with legacy scoping, or something.. Im probably completely wrong... @PGriffith?

The complete correct stack trace may still be helpful, as well as the script where the error is occurring.

@nminchin Hi Nick,
Yeah, the import didnā€™t help, found that out (lol)

Btw readBlocking takes an array of tags, not a string

I would modify that slightly by saying tagPaths, but yeah.

And writeBlocking takes an array of tagPaths, and values as well.

Yes, more precisely a list of qualified values where each qualified value has three attributes (value, quality and timestamp) hence my suffix [0].value in the read instruction. I donā€™t think my script is an issueā€¦the exact script works properly when I call it from the Project script libraryā€¦just not in the component customer methods.

No,

read and write blocking need a list of tagPaths. readBlocking returns a list of qualified values.

https://docs.inductiveautomation.com/display/DOC81/system.tag.readBlocking

Same as my reply to Nickā€¦
ā€œYes, more precisely a list of qualified values where each qualified value has three attributes (value, quality and timestamp) hence my suffix [0].value in the read instruction. I donā€™t think my script is an issueā€¦the exact script works properly when I call it from the Project script libraryā€¦just not in the component customer methods.ā€ so it must be something elseā€¦similar to what I found in "system" functions not available from client ?

Fairly recently we made a sneaky change to the read and write functions to allow single elements to be passed, since it's a common 'papercut' issue for new users and our training department. The preferred syntax is still to call it with a list, but single values are accepted - that explains the syntax in the OP working.

Basically correct - gateway event scripts are the only system that still uses 'legacy' scripting, and therefore needs you to reimport system inside any defined functions.

1 Like

:thinking: Perhaps a note in the documentation?

Good to know though

Please, edward, when you paste errors or code, highlight what youā€™ve pasted and click the preformatted text button in the comment editorā€™s toolbar. You can edit your comments above to do this retro-actively. Not doing this makes it hard for us volunteers to help you. ):

Hello All,

The custom method definitely (seems at least anyway) canā€™t reference system.tag but I found a solution (more like a work-around?) thanks to @silverbacknet (post Using system.* inside a custom function? - #9 by systemparadox) where a reference to system.tag must be passed as an argument to the custom method. It works and is not messy.

This is my buttons actionPerformed script, see line 5 (import system.tag as sysTag) and the last line.

# ==========================================================================
# Commit the version notes and increment the version number...only after everything is validated.
# ==========================================================================
# The import is needed for the custom methods...refer to line 42.
import system.tag as sysTag
# The three user input fields must be validated.
projectArea = event.source.parent.getComponent('dd_projectArea').selectedStringValue
topic = event.source.parent.getComponent('ta_topic').text
notes = event.source.parent.getComponent('ta_versionNotes').text

if (projectArea == ''):
	system.gui.messageBox("You must select a project area.")
elif (topic == ''):
	system.gui.messageBox("You must enter a topic.")
elif (notes == ''):
	system.gui.messageBox("You must enter notes.")
else:
	if system.gui.confirm(
		"Are you sure you want to commit these notes and increment the version?",
		"Commit"):
			selectedVersion = event.source.parent.versionNumber
			if (selectedVersion == 0):
				event.source.forgetVersionInfo()
				system.nav.closeParentWindow(event)
				event.source.resetAllVerNums(projectArea, topic, notes)
			elif (selectedVersion == 1):
				event.source.forgetVersionInfo()
				system.nav.closeParentWindow(event)
				event.source.incrementVerNum1st(projectArea, topic, notes)
			elif (selectedVersion == 2):
				event.source.forgetVersionInfo()
				system.nav.closeParentWindow(event)
				event.source.incrementVerNum2nd(projectArea, topic, notes)
			elif (selectedVersion == 3):
				event.source.forgetVersionInfo()
				system.nav.closeParentWindow(event)
				event.source.incrementVerNum3rd(projectArea, topic, notes)
			else:
				event.source.forgetVersionInfo()
				system.nav.closeParentWindow(event)
				event.source.incrementVerNum4th(projectArea, topic, notes, sysTag)

This is the custom method where I was getting the error, but with a system.tag reference argument it works nicely.

def incrementVerNum4th(projectArea, topic, notes, sysTag):
	# =====================================================================
	# Increments the 4th version number (work in progress).
	# <major> . <feature> . <bug fix> . <work in progress>
	# =====================================================================
	newVerNum = sysTag.readBlocking('[gw1]_Project Version Information/verNum4th')[0].value + 1
	sysTag.writeBlocking('[gw1]_Project Version Information/verNum4th', newVerNum)
	self.addVersionNote(projectArea, topic, notes, sysTag)

Thank you everyone for you assistance, it so nice to have volunteers like yourselves. Iā€™ve been Ignitionā€™ing for about a monthā€¦maybe after 12 months Iā€™ll have enough experience to help others :slight_smile:
Regards,
Ted.