Perspective script runs flawlessly when on a button but when same script is put in a property script it results in a bunch of new errors

Operator writes in a text field and whatever they wrote is then queried. Here's the code:

bar = currentValue.value
bar = str(bar)
system.db.runNamedQuery('Pack', {'scan': bar})

scan is supposed to be a string and the query works when attached to a button, but now that I have it in the text field property change script, it says data mismatch.

Please provide the full stack trace for the error you are seeing. The config for the named query would also be good.

If this is coming from a text field, then currentValue.value is already a string there is no need for the conversion.

system.db.runNamedQuery('Pack', {'scan':currentValue.value})

Should work just as well (won't get rid of whatever error you're seeing).

It's no longer giving me that error but now it's giving me a completely new error message:

com.inductiveautomation.ignition.common.script.JythonExecException
Traceback (most recent call last):
File "function:valueChanged", line 19, in valueChanged
UnboundLocalError: local variable 'lvalue' referenced before assignment

for this line that also worked just fine on a button:

for row in DATApy:
	 for lvalue in row:
		print lvalue

What is line 19? That error generally means that you've used a variable outside of the scope it is defined for.

Also, in perspective print doesn't do what you might expect. You should use system.perspective.print().

Going to be difficult to troubleshoot this script without the whole thing, or at least all of the relevant lines. If you're concerned about reveling proprietary data then redact it and replace it with a suitable stand in.

Or Call into support who can have a proper NDA agreement.

2 Likes

Here's full code:

previousValue = ''
time = system.date.now()
bar = currentValue.value
DATA = system.db.runNamedQuery('Pack', {'scan':bar})
DATApy= system.dataset.toPyDataSet(DATA)
for row in DATAPY::
	for lvalue in row:
		print lvalue
system.db.runNamedQuery('DATAPack', {'BAR':lvalue})
TOTAL = system.db.runNamedQuery('ASTOTAL', {'pn':lvalue})
TOTALpy = system.dataset.toPyDataSet(TOTAL)
for row in TOTALpy:
	for tvalue in row:
		print tvalue
system.db.runNamedQuery('DATATOTAL', {'TOTAL':tvalue})

self.props.text = previousValue

Okay, well there aren't 19 lines in that script either, even if I add one for the function definition.

I can say a few things though.

  1. You have two :'s in the line with for row in DATAPY: there should only be 1. I suspect this is the culprit for the error you're getting unless its a typo from typing it into the forum
  2. You have DATAPY instead of DATApy.
  3. You can just as easily use a comprehension to print those values. system.perspective.print([lvalue for lvalue in row for row in DATApy]
  4. You should inisialize lvalue prior to using it in the loop if for whatever reason DATApy has no rows, lvalue will not be set and you'll see an error.
  5. I would not use previousValue in this way, there is already an argument in the function definition for a property change and you're blasting it away.

It looks like you're expecting to get a single value back from the named queries, I would suggest that you create custom properties and use a query binding with the return format set to scaler, or you can access the value directly from the dataset.

#Normal Dataset Access
lvalue = DATA.getValueAt(0,0)

#PyDataset Access
lvalue = DATApy[0][0]

In all, here is what I would think the script would look like:

time = system.date.now()
system.db.runNamedQuery('DATAPack', {'BAR': self.custom.lvalue})
system.db.runNamedQuery('DATATOTAL',{'TOTAL':self.custom.tvalue})

self.props.text = ''

Of course I probably don't understand what all of the different queries are doing. If you give some more context, we will be able to better help you develop the best way to approach the problem.

My original code has a bunch of comments in between but I didn't add them here. I'll try your suggestions and if it still gives me those errors i'll just go back to using a button instead

You do you, but note that:

This type of code (code intended for troubleshooting) in any form should never be left in production (Vision or Perspective):

for row in pyDs:
    for col in row:
        print col

Here is some information on how print works in various contexts:

Currently the code as you had it is filling up your wrapper logs with what ever random data is returned in your queries. Of course if you want it to be there out of sight, then have at it, but depending on the size of the datasets you're adding an execution pause that will be seen as poor performance from the User's point of view.

Also, this is not how you initialize a variable. If you wanted to do it this way then the proper way to do it would be to initialize it prior to the loop, and set it inside of the loop.

lvalue = 0
for row in pyDs:
    for col in row:
        lvalue = col

Though that is equivalent to lvalue = pyDs[pyDs.rowCount -1][pyDs.columnCount - 1]

Tip: use print repr(row) to print the values of a pydataset. While the rows __str__ method doesn’t return anything particularly useful, their __repr__ does return the values.

4 Likes

Also, you shouldn't be using all caps for non-constants. This standard exists across most programming languages

2 Likes

And also

lvalue = pyDs[-1][-1]

right?

Yes, but I was attempting to be clear on what was going on. I find that those not accustomed to pythons list indexing find that hard to follow.

For instance it isn't as obvious that [-1] will get you to the end of the list which is equal to the total number of rows/columns. Where [ds.*count -1] is fairly straightforward.

1 Like