Wait for an object property to be set in squish - python

I am using Squish 6.3 Qt. The application i am testing contains a QLabel whose content changes dynamically.
Is it possible to wait for the label to be set to a particular value?
I can't use waitForObject as the object always exists and only its text value keeps changing.

This example is from Example - Testing or waiting for an expected property value:
def main():
# Register squish_dir/examples/qt/addressbook
# for this example code:
startApplication("addressbook")
# This will fail, unless you create a new
# address book and add a single entry to it,
# but it demonstrates how to use this
# function:
if not waitForPropertyValue("{type='QTableWidget' visible='1'}", "rowCount", 1, 20000):
test.fail("Property did not have the expected value")
else:
test.passes("Property had the expected value")
def waitForPropertyValue(objectName, propertyName, expectedValue, timeoutInMilliseconds):
"""Waits for property value of an already existing object"""
condition = "findObject(objectName)." + propertyName + " == expectedValue";
return waitFor(condition, timeoutInMilliseconds));

Adding TimeoutMilliseconds did not work, so I added time.sleep(Seconds) and this worked for me better.

From frog.ca answer, the correct condition implementation is:
condition = "findObject('{}').".format(objectName) + propertyName + "==" + str(expectedValue);

Related

How to destroy comboboxes if they are available in python gui?

I have a function, which based on the count generates the comboboxes. I want to destroy any combobox which is available already whenever my count variable changes. I used winfo_exists to do this...but it throws an attribute error every time. Please help me with this.
Here is the code of that function:
def create(event):
count = combo.current()
print ("count")
print(count)
for i in range(1,count+2):
if (create_combo[i].winfo_exists()):
create_combo[i].destroy()
for i in range (1,count+2):
create = tk.StringVar()
create_combo[i]= ttk.Combobox(new_window_2,width = 15,textvariable = create, values = sheets)
#create_combo.set("Sheet " + str(i))
create_combo[i].grid(column = i, row =4, padx=10,pady=10)
To delete the widgets which are created in loop, can be deleted by using the method available in this link
Python Tkinter :removing widgets that were created using a for loop
This worked for me... I dont understand why winfo_exists didn't work.
Anyway Thanks!!
list_of_owner_widgets = []
def create(event):
count = combo.current()
print(count)
for widget in list_of_owner_widgets:
widget.destroy()
for i in range (1,count+2):
create = tk.StringVar()
create_combo[i]= ttk.Combobox(new_window_2,width = 15,textvariable = create, values = sheets)
list_of_owner_widgets.append(create_combo[i])
create_combo[i].grid(column = i, row =4, padx=10,pady=10)
If you wish to destroy a Python widget, be it a Checkbox in your case, you use the following code.
It is a lot easier to remove and show widgets using the .grid method!
Your code:
create_combo[i].destroy()
I assume (as I can see further down the code file) that you used the grid method. In which case I would simply change the code to:
create_combo[i].grid_forget()
Hope This Helps!
From your post:
for i in range(1,count+2):
if (create_combo[i].winfo_exists()):
create_combo[i].destroy()
And the error:
AttributeError: 'str' object has no attribute 'winfo_exists'
I can infer that:Your create_combo must be a list full of string(Instead of Combobox widget).
You could add print(create_combo) before the first for loop to check the value in create_combo.It must be a list full of string.
And it seems that your problem is not here,you should check the way how you create the create_combo.
lets assume create_combo = ['a','b','c']. So I am creating three comboboxes create_combo[0...2]. So name of the comboboxes(widgets) is a, b, c.
No,you couldn't.
If really want to get a list of comboboxes you create,you should use:
create_combo = []
for i in range(3):
t = ttk.Combobox(xxxxx)
t.grid(xxxxxx)
create_combo.append(t) # append it to your create_combo
And then,you could use:
for i in create_combo:
if i.winfo_exists(): # i should be a widget,not string
xxxxxxx # your job

Updating different dictionaries based on the value of a raidoButton?

I am trying to append different dictionaries based on what raidoButton is selected in the GUI.
Currently I can append a select dictionary however I am trying to create something that will check the value of the selected raidButton ( 0,1, or 2)
and then with that value check another dict for the name of the dictionaries that need to be append.
Note: My dictionaries are stored on files outside of the program in the same directory as the script.
Here is my code.
thislib = IntVar() # thislib is the variable for the raidoButtons
def append_notes(event=None):
buttonValue = thislib.get()
list_of_dicts = {0:vzt_notes, 1:rms_notes, 2:nsr_notes}
dict_to_be_updated = list_of_dicts[buttonValue]
e1Current = keywordEntry.get().lower()
e1Upper = keywordEntry.get().upper()
e2Current = root.text.get(1.0, END)
answer = tkinter.messagebox.askquestion("Update Notes!","Are you sure you want update your Notes for "+e1Upper+" This cannot be undone!")
if answer == "yes":
dict_to_be_updated[e1Current] = e2Current
with open("%s" %dict_to_be_updated, "r+" ) as working_temp_var:
json.dump(dict_to_be_updated, working_temp_var, indent = "")
else:
tkinter.messagebox.showinfo('...','That was close!')
When I get the below error I think its saying that during my with open statement it is trying to pass the content of the dictionary as a filename/path. I am not sure how to get around this. I just want to get the file name from list_of_dicts by using the raidoButton value as the index value.
with open("%s" %dict_to_be_updated, "r+" ) as working_temp_var:
FileNotFoundError: [Errno 2] No such file or directory: '{\'dss\': \'# DSS: Decision Support Systems\\n# U
Maybe I cant do it like this but it would be nice to know if I can do something simaler. Otherwise I have to create a long if: elif: elif: else: kind of statement for each dictionary I add as a note storage location.
Thanks to the advise of Daniel Roseman, I was able to use a separate list to perform the function I was looking for.
Below is the solution to my question if anyone is interested.
# This is the variable that stores the value of the selected radioButton
thislib = intVar()
def append_notes(event=None):
# This is getting the current value of the radooButton selected. Currently the posible values are 0,1, and 2.
buttonValue = thislib.get()
# This list is used during out "with open" statement below.
list_of_current_keys=["vzt_keys","rms_keys","nsr_keys"]
# This list is used during out "with open" statement below.
list_of_current_dicts=["vzt_notes","rms_notes","nsr_notes"]
# The two dictionaries and lists below are used in the below if statement in order to
# update the correct dictionary and list based of the returned radioButton value.
list_of_dicts = {0:vzt_notes, 1:rms_notes, 2:nsr_notes}
list_of_keys = {0:vzt_keys, 1:rms_keys, 2:nsr_keys}
dict_to_be_updated = list_of_dicts[buttonValue]
keys_to_be_updated = list_of_keys[buttonValue]
# This variable is getting the lower case version of the typed keyword in the keyword
# search box. This lets us search the key value of the dictionary without
# having to worry about case being an issue to see if the keyword already exist
e1Current = keywordEntry.get().lower()
# This is used to store the keyword in the format typed by the used.
# So the user can decide on the case they want displayed in the keyword list.
e1allcase = keywordEntry.get()
# e2Current is where all the notes are displayed or typed. we get the notes that are
# in the textbox to update or add to the selected dictionary as the keys : string value.
e2Current = root.text.get(1.0, END)
# This is a simple pop up window that will ask if you are sure you wish to update your notes.
# currently I have not written a way to undo the last update so for now this message is to
# warn you there is no going back if you hit the "yes" button.
answer = tkinter.messagebox.askquestion("Update Notes!","Are you sure you want update your Notes for "+e1allcase+" This cannot be undone!")
# This if statement will check take the currently selected dictionary & list and update them.
# If the keyword does not exist in the selected dictionary then It will add the keyword:"notes".
if answer == "yes":
current_library = list_of_dicts[buttonValue]
selected_dict = list_of_current_dicts[buttonValue]
selected_libkey = list_of_current_keys[buttonValue]
if e1Current in current_library:
statusW.config(text = "Updating Keyword & Notes for the "+selected_dict+" Library!")
dict_to_be_updated[e1Current] = e2Current
with open(selected_dict, "r+" ) as working_temp_var:
json.dump(dict_to_be_updated, working_temp_var, indent = "")
statusW.config(text = "Update Complete")
else:
statusW.config(text= "Creating New Keyword & Notes for the "+selected_dict+" Library!")
dict_to_be_updated[e1Current] = e2Current
with open(selected_dict, "r+" ) as working_temp_var:
json.dump(dict_to_be_updated, working_temp_var, indent = "")
keys_to_be_updated.append(e1allcase)
with open(selected_libkey, "r+" ) as working_temp_keys:
json.dump(keys_to_be_updated, working_temp_keys, indent = "")
statusW.config(text = "Update Complete")
# This calles a function that will update the display
update_kw_display()
else:
tkinter.messagebox.showinfo('...','That was close!')

Maya Python skinCluster return type not string?

I'm trying to check if an object has a skinCluster on it. My code is pretty basic. Here's an example:
cmds.select(d=True)
joint = cmds.joint()
skinnedSphere = cmds.polySphere(r=2)
notSkinnedSphere = cmds.polySphere(r=2)
skinTestList = [skinnedSphere, notSkinnedSphere]
# Bind the joint chain that contains joint1 to pPlane1
# and assign a dropoff of 4.5 to all the joints
#
cmds.skinCluster( joint, skinnedSphere, dr=4.5)
for obj in skinTestList:
objHist = cmds.listHistory(obj, pdo=True)
skinCluster = cmds.ls(objHist, type="skinCluster")
if skinCluster == "":
print(obj + " has NO skinCluster, skipping.")
else:
print obj, skinCluster
#cmds.select(obj, d=True)
My issue is that even if it can't find a skincluster, it still prints out the "obj, skincluster" rather than the error that it can't find a skinCluster.
I thought a skinCluster returns a string. So if the string is empty, it should print out the error rather than "obj, skincluster".
Any help would be appreciated!
This is a classic Maya issue -- the problem is that Maya frequently wants to give you lists, not single items, even when you know the result ought to be a single item. This means you end up writing a bunch of code to either get one item from a one-item list or to avoid errors that come from trying to get an index into an empty list.
You've got the basics, it's the == "" which is messing you up:
for obj in skinTestList:
objHist = cmds.listHistory(obj, pdo=True)
skinCluster = cmds.ls(objHist, type="skinCluster") or [None]
cluster = skinCluster[0]
print obj, cluster
The or [None] guarantees that you'll always get a list with something in it so it's safe to use the [0] to get the single value. None is a good return value here because (as pointed out in the comments) you can if cluster: and skip empty values.

How to check whether script input param is among list of acceptable values?

I have a simple case here, but it made me realize I don't have a good strategy for handling more interesting input. How can I check (ideally in O(1) time), that the input is among a list of whitelisted values?
import time
global wait_time_secs
def validateUsage(arg_list):
"""Validates that the user called this program correctly and teaches the
expected usage otherwise"""
global wait_time_secs
# Discard the first argument which is always the script name
arg_list.pop(0)
# Ensure the next argument exists and is valid
if len(arg_list) < 1:
teachUsage()
sys.exit(0)
wait_time_secs = int(arg_list.pop(0))
# My hard-coded list of acceptable values. How to do for non-trivial input?
if ((10 == wait_time_secs) or (20 == wait_time_secs)) is not True:
print "invalid parameter"
teachUsage()
sys.exit(0)
def main():
validateUsage(list(sys.argv))
time.sleep(wait_time_secs)
if __name__ == '__main__':
main()
One way is to use a set to include all the acceptable values like this:
acceptable_values = set([10, 20])
and then change your condition to:
if wait_time_secs not in acceptable_values:
teachUsage()
A set will ensure O(1) lookup.

QCombo box to set layer (for Python QGIS plugin)

I'm attempting to create a function to declare a variable in terms of an item chosen in a QComboBox. It's for a plugin for QGIS 2.0 and 2.2. I'm getting a "list index out of range" error, but cannot see why. I'm wondering if my combobox.currentIndex() isn't giving me what I think it is. If this is the case, I wonder if I should find a way set the combo box's index to something by default before the program runs.
#connecting the combo boxes to function
def initGui(self):
QObject.connect(self.dlg.ui.indivCombo,SIGNAL("currentIndexChanged(int)"),self.layerChanged)
QObject.connect(self.dlg.ui.grosCombo,SIGNAL("currentIndexChanged(int)"),self.layerChanged)
QObject.connect(self.dlg.ui.resCombo,SIGNAL("currentIndexChanged(int)"),self.layerChanged)
#function to set my layer parameter to the equal the item at index chosen
def layerChanged(self):
self.layerMap = QgsMapLayerRegistry.instance().mapLayers().values()
self.indivLayer = self.layerMap[self.dlg.ui.indivCombo.currentIndex()]
self.grosLayer = self.layerMap[self.dlg.ui.grosCombo.currentIndex()]
self.resLayer = self.layerMap[self.dlg.ui.resCombo.currentIndex()]
#populating combo box with layers in stack
def run(self):
# show the dialog
self.dlg.show()
for layer in self.iface.legendInterface().layers():
if layer.type() == QgsMapLayer.VectorLayer:
self.dlg.indivCombo.addItem(layer.name())
self.dlg.grosCombo.addItem(layer.name())
self.dlg.resCombo.addItem(layer.name())
# Run the dialog event loop
result = self.dlg.exec_()
# See if OK was pressed
if result == 1:
pass
I've now made some changes to the code thanks to the near-answer below. layerChanged() now uses an identifiers method and run() adds layers to combo box differently based on ideas from thread http://lists.osgeo.org/pipermail/qgis-developer/2010-November/011505.html. Both areas still give me issues however. "None type object has no attribute mapLayer" for the former and "Syntax error" for the latter.
def layerChanged(self, index):
#globals previously initialized as None
global registry, indivID, grosID, resID
registry = QgsMapLayerRegistry.instance()
indivID = self.dlg.ui.indivCombo.data(index).toPyObject()
grosID = self.dlg.ui.grosCombo.data(index).toPyObject()
resID = self.dlg.ui.resCombo.data(index).toPyObject()
self.indivLayer = registry.mapLayer(indivID)
self.grosLayer = registry.mapLayer(grosID)
self.resLayer = registry.mapLayer(resID)
def calculatelength(self):
global registry, resID
self.resLayer = registry.mapLayer(resID)
idx = self.resLayer.fieldNameIndex('Length')
#code continues
def run(self):
# show the dialog
self.dlg.show()
for layer in self.iface.legendInterface().layers():
if layer.type() == QgsMapLayer.VectorLayer:
self.dlg.ui.indivCombo.addItem(layer.name(),QVariant(layer.id())
self.dlg.ui.grosCombo.addItem(layer.name(),QVariant(layer.id())
self.dlg.ui.resCombo.addItem(layer.name(),QVariant(layer.id())
# Run the dialog event loop
result = self.dlg.exec_()
# See if OK was pressed
if result == 1:
pass
#AEPStats()
Taking example code you posted at face-value, I can see several problems.
Firstly, judging by the differences between the initGui and run methods, there may be two sets of combo-boxes in use. The signals are connected to self.dlg.ui.*Combo, whereas the items are added to self.dlg.*Combo.
Secondly, you seem to be populating the combo-boxes over and over again without clearing them beforehand.
Thirdly, you do not seem to be preserving a one-to-one relationship between the combo-box indexes and the list, because you are filtering the layers based on type.
And finally, the list of layers comes from the values of a map, so surely there is no guarantee that they will come out in the same order.
I would suggest you associate a layer id with each combo item, and then retrieve the layer via the mapLayer method. That is, add the combo items like this:
self.dlg.indivCombo.addItem(layer.name(), layer.id())
and then retrieve the layer like this:
def layerChanged(self, index):
registry = QgsMapLayerRegistry.instance()
identifier = self.dlg.ui.indivCombo.itemData(index)
self.indivLayer = registry.mapLayer(identifier)
NB: if you're using Python2, the combo data will be stored as a QVariant so you would need to extract the identifier like this:
identifier = self.dlg.ui.indivCombo.itemData(index).toString()
or this:
identifier = self.dlg.ui.indivCombo.itemData(index).toPyObject()
Thanks to help from #ekhumoro, this now works. Only changes made to answer's suggestions were in layerChanged():
def layerChanged(self):
registry = QgsMapLayerRegistry.instance()
identifier = str(self.dlg.ui.indivCombo.itemData(self.dlg.ui.indivCombo.currentIndex()))
self.indivLayer = registry.mapLayer(identifier)
This solves an issue of the index chosen getting mixed up and incorrect for the multiple combo boxes i have.

Categories