Package dogtail :: Module predicate
[hide private]
[frames] | no frames]

Source Code for Module dogtail.predicate

  1  """Predicates that can be used when searching for nodes. 
  2   
  3  Author: David Malcolm <dmalcolm@redhat.com>""" 
  4  __author__ = 'David Malcolm <dmalcolm@redhat.com>' 
  5   
  6  import unittest 
  7   
  8  from i18n import TranslatableString 
  9   
10 -def stringMatches(scriptName, reportedName):
11 assert isinstance(scriptName, TranslatableString) 12 13 return scriptName.matchedBy(reportedName)
14
15 -def makeScriptRecursiveArgument(isRecursive, defaultValue):
16 if isRecursive==defaultValue: 17 return "" 18 else: 19 return ", recursive=%s"%isRecursive
20
21 -def makeCamel(string):
22 """ 23 Convert string to camelCaps 24 """ 25 string = str(string) 26 # FIXME: this function is probably really fragile, lots of difficult cases here 27 28 # Sanitize string, replacing bad characters with spaces: 29 for char in ":;!@#$%^&*()-+=_~`\\/?|[]{}<>,.\t\n\r\"'": 30 string = string.replace(char, " ") 31 words = string.strip().split(" ") 32 for word in words: 33 word.strip 34 result = "" 35 firstWord=True 36 for word in words: 37 lowercaseWord = word.lower() 38 if firstWord: 39 result += lowercaseWord 40 firstWord=False 41 else: 42 result += lowercaseWord.capitalize() 43 return result
44
45 -class Predicate:
46 """Abstract base class representing a predicate function on nodes. 47 48 It's more than just a function in that it has data and can describe itself"""
49 - def satisfiedByNode(self, node):
50 """Pure virtual method returning a boolean if the predicate is satisfied by the node""" 51 raise NotImplementedError
52
53 - def describeSearchResult(self, node):
54 raise NotImplementedError
55
56 - def makeScriptMethodCall(self, isRecursive):
57 """ 58 Method to generate a string containing a (hopefully) readable search 59 method call on a node (to be used when generating Python source code in 60 the event recorder) 61 """ 62 raise NotImplementedError
63
64 - def makeScriptVariableName(self):
65 """ 66 Method to generate a string containing a (hopefully) readable name 67 for a Node instance variable that would be the result of a search on 68 this predicate (to be used when generating Python source code in the 69 event recorder). 70 """ 71 raise NotImplementedError
72
73 - def __eq__(self, other):
74 """ 75 Predicates are considered equal if they are of the same subclass and 76 have the same data 77 """ 78 # print "predeq: self:%s"%self 79 # print " other:%s"%other 80 # print "predeq: selfdict:%s"%self.__dict__ 81 # print " otherdict:%s"%other.__dict__ 82 83 if type(self)!=type(other): 84 return False 85 else: 86 return self.__dict__ == other.__dict__
87 88
89 -class IsAnApplicationNamed(Predicate):
90 """Search subclass that looks for an application by name"""
91 - def __init__(self, appName):
92 self.appName = TranslatableString(appName) 93 self.debugName = self.describeSearchResult() 94 self.satisfiedByNode = self._genCompareFunc()
95
96 - def _genCompareFunc(self):
97 def satisfiedByNode(node): 98 return node.roleName=='application' and stringMatches(self.appName, node.name)
99 return satisfiedByNode
100
101 - def describeSearchResult(self):
102 return '%s application'%self.appName
103
104 - def makeScriptMethodCall(self, isRecursive):
105 # ignores the isRecursive parameter 106 return "application(%s)"%self.appName
107
108 - def makeScriptVariableName(self):
109 return makeCamel(self.appName)+"App"
110
111 -class GenericPredicate(Predicate):
112 """SubtreePredicate subclass that takes various optional search fields""" 113
114 - def __init__(self, name = None, roleName = None, description= None, label = None, debugName=None):
115 if name: 116 self.name = TranslatableString(name) 117 else: 118 self.name = None 119 self.roleName = roleName 120 self.description = description 121 if label: 122 self.label = TranslatableString(label) 123 else: 124 self.label = None 125 126 if debugName: 127 self.debugName = debugName 128 else: 129 if label: 130 self.debugName = "labelled '%s'"%self.label 131 else: 132 self.debugName = "child with" 133 if name: 134 self.debugName += " name=%s" % self.name 135 if roleName: 136 self.debugName += " roleName='%s'"%roleName 137 if description: 138 self.debugName += " description='%s'"%description 139 assert self.debugName 140 141 self.satisfiedByNode = self._genCompareFunc()
142 143
144 - def _genCompareFunc(self):
145 def satisfiedByNode(node): 146 # labelled nodes are handled specially: 147 if self.label: 148 # this reverses the search; we're looking for a node with LABELLED_BY 149 # and then checking the label, rather than looking for a label and 150 # then returning whatever LABEL_FOR targets 151 if node.labeller: 152 return stringMatches(self.label, node.labeller.name) 153 else: return False 154 else: 155 # Ensure the node matches any criteria that were set: 156 if self.name: 157 if not stringMatches(self.name,node.name): return False 158 if self.roleName: 159 if self.roleName!=node.roleName: return False 160 if self.description: 161 if self.description!=node.description: return False 162 return True
163 return satisfiedByNode
164
165 - def describeSearchResult(self):
166 return self.debugName
167
168 - def makeScriptMethodCall(self, isRecursive):
169 if self.label: 170 args = "label=%s"%label 171 else: 172 args = "" 173 if self.name: 174 args += " name=%s"%self.name 175 if self.roleName: 176 args += " roleName=%s"%self.roleName 177 if self.description: 178 args += " description=%s"%self.description 179 return "child(%s%s)"%(args, makeScriptRecursiveArgument(isRecursive, True))
180
181 - def makeScriptVariableName(self):
182 if self.label: 183 return makeCamel(self.label)+"Node" 184 else: 185 if self.name: 186 return makeCamel(self.name)+"Node" 187 if self.roleName: 188 return makeCamel(self.roleName)+"Node" 189 if self.description: 190 return makeCamel(self.description)+"Node"
191
192 -class IsNamed(Predicate):
193 """Predicate subclass that looks simply by name""" 194
195 - def __init__(self, name):
199
200 - def _genCompareFunc(self):
201 def satisfiedByNode(node): 202 return stringMatches(self.name, node.name)
203 return satisfiedByNode
204
205 - def describeSearchResult(self):
206 return "named %s"%self.name
207
208 - def makeScriptMethodCall(self, isRecursive):
209 return "child(name=%s%s)"%(self.name, makeScriptRecursiveArgument(isRecursive, True))
210 - def makeScriptVariableName(self):
211 return makeCamel(self.name)+"Node"
212
213 -class IsAWindowNamed(Predicate):
214 """Predicate subclass that looks for a top-level window by name"""
215 - def __init__(self, windowName):
216 self.windowName = TranslatableString(windowName) 217 self.debugName = self.describeSearchResult() 218 self.satisfiedByNode = self._genCompareFunc()
219
220 - def _genCompareFunc(self):
221 def satisfiedByNode(node): 222 return node.roleName=='frame' and stringMatches(self.windowName, node.name)
223 return satisfiedByNode
224
225 - def describeSearchResult(self):
226 return "%s window"%self.windowName
227
228 - def makeScriptMethodCall(self, isRecursive):
229 return "window(%s%s)"%(self.windowName, makeScriptRecursiveArgument(isRecursive, False))
230
231 - def makeScriptVariableName(self):
232 return makeCamel(self.windowName)+"Win"
233
234 -class IsAWindow(Predicate):
235 """Predicate subclass that looks for top-level windows"""
236 - def __init__(self):
237 self.satisfiedByNode = lambda node: node.roleName == 'frame'
238
239 - def describeSearchResult(self):
240 return "window"
241
242 -class IsADialogNamed(Predicate):
243 """Predicate subclass that looks for a top-level dialog by name"""
244 - def __init__(self, dialogName):
245 self.dialogName = TranslatableString(dialogName) 246 self.debugName = self.describeSearchResult() 247 self.satisfiedByNode = self._genCompareFunc()
248
249 - def _genCompareFunc(self):
250 def satisfiedByNode(node): 251 return node.roleName=='dialog' and stringMatches(self.dialogName, node.name)
252 return satisfiedByNode
253
254 - def describeSearchResult(self):
255 return '%s dialog'%self.dialogName
256
257 - def makeScriptMethodCall(self, isRecursive):
258 return "dialog(%s%s)"%(self.dialogName, makeScriptRecursiveArgument(isRecursive, False))
259
260 - def makeScriptVariableName(self):
261 return makeCamel(self.dialogName)+"Dlg"
262
263 -class IsLabelledBy(Predicate):
264 """Predicate: is this node labelled by another node""" 265 pass
266
267 -class IsLabelledAs(Predicate):
268 """Predicate: is this node labelled with the text string (i.e. by another node with that as a name)"""
269 - def __init__(self, labelText):
270 self.labelText = TranslatableString(labelText) 271 self.debugName = self.describeSearchResult() 272 self.satisfiedByNode = self._genCompareFunc()
273
274 - def _genCompareFunc(self):
275 def satisfiedByNode(node): 276 # FIXME 277 if node.labeller: 278 return stringMatches(self.labelText, node.labeller.name) 279 else: return False
280 return satisfiedByNode
281
282 - def describeSearchResult(self):
283 return 'labelled %s'%self.labelText
284
285 - def makeScriptMethodCall(self, isRecursive):
286 return "child(label=%s%s)"%(self.labelText, makeScriptRecursiveArgument(isRecursive, True))
287
288 - def makeScriptVariableName(self):
289 return makeCamel(self.labelText)+"Node"
290
291 -class IsAMenuNamed(Predicate):
292 """Predicate subclass that looks for a menu by name"""
293 - def __init__(self, menuName):
294 self.menuName = TranslatableString(menuName) 295 self.debugName = self.describeSearchResult() 296 self.satisfiedByNode = lambda node: node.roleName=='menu' and \ 297 stringMatches(self.menuName, node.name)
298
299 - def describeSearchResult(self):
300 return '%s menu'%(self.menuName)
301
302 - def makeScriptMethodCall(self, isRecursive):
303 return "menu(%s%s)"%(self.menuName, makeScriptRecursiveArgument(isRecursive, True))
304
305 - def makeScriptVariableName(self):
306 return makeCamel(self.menuName)+"Menu"
307
308 -class IsAMenuItemNamed(Predicate):
309 """Predicate subclass that looks for a menu item by name"""
310 - def __init__(self, menuItemName):
311 self.menuItemName = TranslatableString(menuItemName) 312 self.debugName = self.describeSearchResult() 313 self.satisfiedByNode = lambda node: \ 314 node.roleName.endswith('menu item') and \ 315 stringMatches(self.menuItemName, node.name)
316
317 - def describeSearchResult(self):
318 return '%s menuitem'%(self.menuItemName)
319
320 - def makeScriptMethodCall(self, isRecursive):
321 return "menuItem(%s%s)"%(self.menuItemName, makeScriptRecursiveArgument(isRecursive, True))
322
323 - def makeScriptVariableName(self):
324 return makeCamel(self.menuItemName)+"MenuItem"
325
326 -class IsATextEntryNamed(Predicate):
327 """Predicate subclass that looks for a text entry by name"""
328 - def __init__(self, textEntryName):
329 self.textEntryName = TranslatableString(textEntryName) 330 self.debugName = self.describeSearchResult() 331 self.satisfiedByNode = lambda node: node.roleName == 'text' and \ 332 stringMatches(self.textEntryName, node.name)
333
334 - def describeSearchResult(self):
335 return '%s textentry'%(self.textEntryName)
336
337 - def makeScriptMethodCall(self, isRecursive):
338 return "textentry(%s%s)"%(self.textEntryName, makeScriptRecursiveArgument(isRecursive, True))
339
340 - def makeScriptVariableName(self):
341 return makeCamel(self.textEntryName)+"Entry"
342
343 -class IsAButtonNamed(Predicate):
344 """Predicate subclass that looks for a button by name"""
345 - def __init__(self, buttonName):
346 self.buttonName = TranslatableString(buttonName) 347 self.debugName = self.describeSearchResult() 348 self.satisfiedByNode = lambda node: node.roleName == 'push button' \ 349 and stringMatches(self.buttonName, node.name)
350
351 - def describeSearchResult(self):
352 return '%s button'%(self.buttonName)
353
354 - def makeScriptMethodCall(self, isRecursive):
355 return "button(%s%s)"%(self.buttonName, makeScriptRecursiveArgument(isRecursive, True))
356
357 - def makeScriptVariableName(self):
358 return makeCamel(self.buttonName)+"Button"
359
360 -class IsATabNamed(Predicate):
361 """Predicate subclass that looks for a tab by name"""
362 - def __init__(self, tabName):
363 self.tabName = TranslatableString(tabName) 364 self.debugName = self.describeSearchResult() 365 self.satisfiedByNode = lambda node: node.roleName=='page tab' and \ 366 stringMatches(self.tabName, node.name)
367
368 - def describeSearchResult(self):
369 return '%s tab'%(self.tabName)
370
371 - def makeScriptMethodCall(self, isRecursive):
372 return "tab(%s%s)"%(self.tabName, makeScriptRecursiveArgument(isRecursive, True))
373
374 - def makeScriptVariableName(self):
375 return makeCamel(self.tabName)+"Tab"
376
377 -class PredicateTests(unittest.TestCase):
378 - def testCapitalization(self):
379 self.assertEquals(makeCamel("gnome-terminal"),"gnomeTerminal") 380 self.assertEquals(makeCamel("Evolution - Mail"), "evolutionMail") 381 self.assertEquals(makeCamel('self.assertEquals(makeCamel("Evolution - Mail"), "evolutionMail")'), "selfAssertequalsMakecamelEvolutionMailEvolutionmail")
382
383 - def testPredicates(self):
384 class DummyNode: 385 def __init__(self, name = '', roleName = '', description = ''): 386 self.name = name 387 self.roleName = roleName 388 self.description = description 389 self.labeller = None
390 391 dn1 = DummyNode('dummy name 1', 'dummy role 1', 'dummy desc 1') 392 dn2 = DummyNode('dummy name 2', 'dummy role 2', 'dummy desc 2') 393 394 dummyApp = DummyNode('dummy', 'application') 395 self.assertTrue(IsAnApplicationNamed(dummyApp.name).satisfiedByNode(dummyApp)) 396 397 self.assertTrue(IsNamed(dn1.name).satisfiedByNode(dn1)) 398 399 dummyWin = DummyNode('dummy', 'frame') 400 self.assertTrue(IsAWindowNamed(dummyWin.name).satisfiedByNode(dummyWin)) 401 self.assertTrue(IsAWindow().satisfiedByNode(dummyWin)) 402 403 dummyDlg = DummyNode('dummy', 'dialog') 404 self.assertTrue(IsADialogNamed(dummyDlg.name).satisfiedByNode(dummyDlg)) 405 406 dn2.labeller = dn1 407 #IsLabelledBy 408 self.assertTrue(IsLabelledAs(dn1.name).satisfiedByNode(dn2)) 409 410 dummyMenu = DummyNode('dummy', 'menu') 411 self.assertTrue(IsAMenuNamed(dummyMenu.name).satisfiedByNode(dummyMenu)) 412 413 dummyMenuItem = DummyNode('dummy', 'menu item') 414 self.assertTrue(IsAMenuItemNamed(dummyMenuItem.name).satisfiedByNode(dummyMenuItem)) 415 416 dummyText = DummyNode('dummy', 'text') 417 self.assertTrue(IsATextEntryNamed(dummyText.name).satisfiedByNode(dummyText)) 418 419 dummyButton = DummyNode('dummy', 'push button') 420 self.assertTrue(IsAButtonNamed(dummyButton.name).satisfiedByNode(dummyButton)) 421 422 dummyTab = DummyNode('dummy', 'page tab') 423 self.assertTrue(IsATabNamed(dummyTab.name).satisfiedByNode(dummyTab)) 424 425 if __name__ == "__main__": 426 unittest.main() 427