When do properties types get converted

I want to pass it a single record read from a recordset to a subview, so I generated a dictionary from it and then I assigned this dictionary to the view's param.
Once I did that, I had an hard time trying to understand why a couple of bindings bound to the property didn't work.
The bindings on the param self.view.params.MYPROP were like:

if value is None or len(value)==0:
    return

This failed without even logging anything (I'm still confused whether I could expect that an error appears in the log; I concluded that in general errors in binding don't show up in log).

For the sake of simplicity, the problem can be reproduced without subview but just using a couple of buttons, a TextField and a custom property on the view called MYPROP.

image

The first button contains the following code:

myDictionary = {"A":1}

print "button 1 script: myDictionary type: " + str(type(myDictionary))	
print "button 1 script: myDictionary len:" + str(len(myDictionary))

self.parent.custom.MYPROP =  myDictionary

print "button 1 script: self.parent.custom.MYPROP  type:" + str(type(self.parent.custom.MYPROP))		
print "button 1 script: self.parent.custom.MYPROP  len:" + str(len(self.parent.custom.MYPROP))

The BINDING of text property of TextField contains the following code:

print "binding: value type: " + str(type(value)) 	
return str(type(value)) 

The second button serves only as a confirmation for what is already shown in the log by the first button:

print "button 2 script: self.parent.custom.MYPROP type:" + str(type(self.parent.custom.MYPROP))				
print "button 2 script: self.parent.custom.MYPROP len:" + str(len(self.parent.custom.MYPROP))

Now this is enough to show the problem, that is: the original dictionary gets traslated into something that you can't use as an argoment for the len property.
Actually I want to show that the problem is not that this happen, but when this happens.

I couldn't find documentation on this, but I read that some data types are translated when assigned to properties, but this is not exact.
Infact, if you press the first button you will see:

That is: when TextField text's binding accesses MYPROP, it sees it as a DotRefenceJythonMap, so is that the type of MYPROP type?
No, it's something 'in between' and you can see it in the log:

button 1 script: myDictionary type: <type 'dict'>
button 1 script: myDictionary len:1
binding: value type: <type 'com.inductiveautomation.perspective.gateway.script.DotReferenceJythonMap'>
button 1 script: self.parent.custom.MYPROP  type:<type 'com.inductiveautomation.perspective.gateway.script.PropertyTreeScriptWrapper$ObjectWrapper'>
button 1 script: self.parent.custom.MYPROP  len:1
button 2 script: self.parent.custom.MYPROP type:<type 'com.inductiveautomation.perspective.gateway.script.PropertyTreeScriptWrapper$ObjectWrapper'>
button 2 script: self.parent.custom.MYPROP len:1

So here I show that re-reading MYPROP right after it has been set, the type is PropertyTreeScriptWrapper$ObjectWrapper. And it stays the same type over time, since also button 2 sees it as a PropertyTreeScriptWrapper$ObjectWrapper, that, by the way, can be used as an argument for the len function.

But the binding sees it as DotReferenceJythonMap. (Interestingly, the binding and the originating assignment are interleaved) That can't be used with len(...).
Since after several months of usage i still run into issues like this, I realized that there is more that I don't know under the hood of types in perspective and I would appreciate some in-depth documentation (or at least some guidelines) on this topic that I couldn't find so far.

This is infact a curious behavior in which the binding sees MYPROP as a certain type while if I put a button and access MYPROP, it will see it as a different type that requires differrent handling.
I ask for documentation because I would like to be able to anticipate this and not just stumble into it as a bug pops up.

Just a wild guess, because I don't actually know:
The biding, when passing {value} to the script transform, casts it to something that's jython-friendly.
When grabbing the property from a script, you get something that's ignition-friendly, without the casting step.

I'd be curious to have more details too.

1 Like