Change Script cannot see other props?

Hey all,

I have a change script that I would like to check the value of another property before taking action:

if currentValue:
    if custom.prop1 > 0:
          custom.prop2 = custom.prop1
    else:
          run other code

The error message says: object has no attribute prop1

Thanks

Can you prove custom.prop1 exists?

self.custom.prop1

3 Likes

Where are you writing this script?
Depending on the context, the script editor has a browse properties button to the right of the dialog. Selecting properties via the browser ensures that the properties / paths are correct.

3 Likes

The script is on: self.params.pos_1

I was in hurry to type it up last night, I referenced the wrong property in the post.

The above should say:

if currentValue:
     if self.params.prop1 > 0:
          self.custom.prop2 = self.params.prop1
else:
     run other code

I used the property browser, twice to be sure there were no errors.

You should be checking the value of currentValue which is a QualifiedValue.

Also, you should probably just combine the two conditions into one, unless there is other code that you aren't showing.

You should make sure that a previousValue exisits. The first time the change script fires, the previousValue will be None.

if all((previousValue, currentValue.value, self.params.prop1 > 0):
    self.custom.prop2 = self.params.prop1
else:
    #run other code

Is this error happening in the Designer or a Client?

Well, Rose, both Designer and Client, and here's why:

I just restarted the Designer, and guess what? That particular parameter no longer exists! I could select it in the property box, and I've been saving my work all day. To be fair to IA @cmallonee , I did have a lot of dialog boxes open while working on various bindings and scripts. However, I always hit apply, update the project and save.

I may have caused some sort of overload in the Designer - I mean four to eight windows/boxes open for various things. And another Designer window open (separate project, same gateway).

So a restart solved this problem. Perhaps there is a solution during the project update process that can propagate the changes throughout all the open windows which reference the changed objects? (Like a refresh)

Anyhow, case closed. And Merry Christmas to everyone!

Strangely enough, the changes made to the change script (which were made after the parameter was created), those changes were saved, but not the parameter itself!

Is there any possibility that you bound the param as a two-way property, or that you made the param non-persistent?

References to non-persistent properties are prone to this issue as currentValue might be the initial value, and the (non-persistent) param may not have been populated yet.

1 Like

Definitely not a two-way prop. I don't recall setting it to non-persistent, though I have noticed many custom props tend to be non-persistent by default, I think that's because (not verified) they are bi-directionally bound.

I cannot confirm or deny the persistence of said param. Perhaps I'll do it again at some point.

Ideally, the value should be None or Empty, except when a value is returned from the popup form. If previousValue is none, then it would not be greater than 0, correct?

So that should prevent the code from running. But, if I do this:

if all(currentValue.value, self.params.prop1 > 0) and previousValue:
     self.custom.prop2 = self.params.prop1 
else:
   #run other code

what do you think?

Moving previousValue out the all() is doing nothing but making your performance minutely worse. all() is true only if all values resolve to a truthy value.

So the way you wrote your condition is logically equivalent.

Also, all requires that you pass it an iterable, so the values need to be enclosed in a list, set, or tuple. Thus the extra () in my example.

previousValue which is a QualifiedValue object will be None on initialization of the parameter. None is a falsey condition, so the code in that branch would not execute. The next time through the previousValue will not be None, it will have a value, quality, and timestamp component.

I very deliberately put it first in the function, because all() is short circuiting meaning that the first falsey condition will exit the function and return false. This is important in cases where you may need to know the pervious value. It’s also good for performance.

Finally, previousValue once initialized will be the previous value of self.params.pos_1 not self.params.prop1 so, it being None doesn’t have any bearing on you’re script (as you have provided it). You only care in two cases (that I know of).

  1. You don’t want code executing at initial change
  2. You are going to attempt to access the perviousValues value component.