pyWinAuto: c:\.projects\py_pywinauto\pywinauto\application.py
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021"""The application module is the main one that users will user first.
0022
0023When starting to automate and application you must initialize an instance
0024of the Application class. Then you must `start_()`_ that application or
0025`Connect_()`_ to a running instance of that application.
0026
0027Once you have an Application instance you can access dialogs in that
0028application either by using one of the methods below. ::
0029
0030 dlg = app.YourDialogTitle
0031 dlg = app.Window_(title = "your title", classname = "your class", ...)
0032 dlg = app['Your Dialog Title']
0033
0034Similarly once you have a dialog you can get a control from that dialog
0035in almost exactly the same ways. ::
0036
0037 ctrl = dlg.YourControlTitle
0038 ctrl = dlg.Window_(title = "Your control", classname = "Button", ...)
0039 ctrl = dlg["Your control"]
0040
0041**Note:** For attribute access of controls and dialogs you do not have to
0042have the title of the control exactly, it does a best match of the
0043avialable dialogs or controls.
0044
0045**See also:**
0046 `findwindows.find_windows()`_ for the keyword arguments that can be
0047 passed to both `Application.window_()`_ and `WindowSpecification.Window_()`_
0048
0049.. _Start_(): class-pywinauto.application.Application.html#start_
0050.. _Connect_(): class-pywinauto.application.Application.html#connect_
0051.. _findwindows.find_windows(): module-pywinauto.findwindows.html#find_windows
0052.. _Application.Window_(): class-pywinauto.application.Application.html#window_
0053.. _WindowSpecification.Window_(): class-pywinauto.application.WindowSpecification.html#control_
0054
0055"""
0056
0057__revision__ = "$Revision: 607 $"
0058
0059import time
0060import os.path
0061
0062import warnings
0063import pickle
0064
0065import ctypes
0066
0067import win32structures
0068import win32functions
0069import win32defines
0070import controls
0071import findbestmatch
0072import findwindows
0073import handleprops
0074
0075from timings import Timings, WaitUntil, TimeoutError, WaitUntilPasses
0076
0077
0078class AppStartError(Exception):
0079 "There was a problem starting the Application"
0080 pass
0081
0082class ProcessNotFoundError(Exception):
0083 "Could not find that process"
0084 pass
0085
0086class AppNotConnected(Exception):
0087 "Application has been connected to a process yet"
0088 pass
0089
0090
0091
0092
0093
0094
0095class WindowSpecification(object):
0096 """A specificiation for finding a window or control
0097
0098 Windows are resolved when used.
0099 You can also wait for existance or non existance of a window
0100 """
0101
0102 def __init__(self, app, search_criteria):
0103 """Initailize the class
0104
0105 * **search_criteria** the criteria to match a dialog
0106 """
0107 self.app = app
0108
0109
0110 self.criteria = [search_criteria, ]
0111
0112
0113 def __call__(self, *args, **kwargs):
0114 "No __call__ so return a usefull error"
0115
0116 if "best_match" in self.criteria[-1]:
0117 raise AttributeError(
0118 "WindowSpecification class has no '%s' method" %
0119 self.criteria[-1]['best_match'])
0120
0121 message = "You tried to execute a function call on a WindowSpecification " "instance. You probably have a typo for one of the methods of this " "class.\n" "The criteria leading up to this is: " + str(self.criteria)
0126
0127 raise AttributeError(message)
0128
0129
0130 def WrapperObject(self):
0131 "Allow the calling code to get the HwndWrapper object"
0132
0133 if self.app.use_history:
0134 ctrls = _resolve_from_appdata(self.criteria, self.app)
0135 else:
0136 ctrls = _resolve_control(self.criteria)
0137
0138
0139
0140
0141 return ctrls[-1]
0142
0143 def ctrl_(self):
0144 "Allow the calling code to get the HwndWrapper object"
0145 message = "ctrl_() has been renamed to WrapperObject() please use " "that method in the future. ctrl_() will be removed at some " "future time."
0148 warnings.warn(message, DeprecationWarning)
0149 return self.WrapperObject()
0150
0151 def Window_(self, **criteria):
0152 """Add criteria for a control
0153
0154 When this window specification is resolved then this will be used
0155 to match against a control."""
0156
0157 new_item = WindowSpecification(self.app, self.criteria[0])
0158 new_item.criteria.append(criteria)
0159
0160 return new_item
0161 window_ = Window_
0162
0163 def __getitem__(self, key):
0164 """Allow access to dialogs/controls through item access
0165
0166 This allows::
0167
0168 app.['DialogTitle']['ControlTextClass']
0169
0170 to be used to access dialogs and controls.
0171
0172 Both this and __getattr__ use the rules outlined in the
0173 HowTo document.
0174 """
0175
0176
0177
0178 if len(self.criteria) == 2:
0179
0180 if self.app.use_history:
0181 ctrls = _resolve_from_appdata(
0182 self.criteria,
0183 self.app)
0184 else:
0185 ctrls = _resolve_control(
0186 self.criteria)
0187
0188
0189
0190
0191
0192 if hasattr(ctrls[-1], '__getitem__'):
0193 return ctrls[-1][key]
0194 else:
0195 message = "The control does not have a __getitem__ method " "for item access (i.e. ctrl[key]) so maybe you have " "requested this in error?"
0198
0199 raise AttributeError(message)
0200
0201
0202
0203 new_item = WindowSpecification(self.app, self.criteria[0])
0204
0205
0206 new_item.criteria.append({"best_match" : key})
0207
0208 return new_item
0209
0210
0211 def __getattr__(self, attr):
0212 """Attribute access for this class
0213
0214 If we already have criteria for both dialog and control then
0215 resolve the control and return the requested attribute.
0216
0217 If we have only criteria for the dialog but the attribute
0218 requested is an attribute of DialogWrapper then resolve the
0219 dialog and return the requested attribute.
0220
0221 Otherwise delegate functionality to __getitem__() - which
0222 sets the appropriate criteria for the control.
0223 """
0224
0225 from pywinauto.controls.win32_controls import DialogWrapper
0226
0227
0228
0229
0230 if len(self.criteria) == 2:
0231
0232 if self.app.use_history:
0233 ctrls = _resolve_from_appdata(
0234 self.criteria,
0235 self.app)
0236 else:
0237 ctrls = _resolve_control(
0238 self.criteria)
0239
0240
0241 return getattr(ctrls[-1], attr)
0242
0243 else:
0244
0245
0246 if len(self.criteria) == 1 and hasattr(DialogWrapper, attr):
0247
0248 if self.app.use_history:
0249 ctrls = _resolve_from_appdata(
0250 self.criteria,
0251 self.app)
0252 else:
0253 ctrls = _resolve_control(
0254 self.criteria)
0255
0256
0257 return getattr(ctrls[-1], attr)
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269 return self[attr]
0270
0271
0272 def Exists(self, timeout = None, retry_interval = None):
0273 "Check if the window exists"
0274
0275
0276
0277 if timeout is None:
0278 timeout = Timings.exists_timeout
0279 if retry_interval is None:
0280 retry_interval = Timings.exists_retry
0281
0282
0283
0284
0285 exists_criteria = self.criteria[:]
0286 for criterion in exists_criteria:
0287 criterion['enabled_only'] = False
0288 criterion['visible_only'] = False
0289
0290 try:
0291 _resolve_control(
0292 exists_criteria, timeout, retry_interval)
0293
0294 return True
0295 except (findwindows.WindowNotFoundError, findbestmatch.MatchError):
0296 return False
0297
0298
0299 def Wait(self,
0300 wait_for,
0301 timeout = None,
0302 retry_interval = None):
0303
0304 """Wait for the window to be in a particular state
0305
0306 * **wait_for** The state to wait for the window to be in. It can be any
0307 of the following states
0308
0309 * 'exists' means that the window is a valid handle
0310 * 'visible' means that the window is not hidden
0311 * 'enabled' means that the window is not disabled
0312 * 'ready' means that the window is visible and enabled
0313 * 'active' means that the window is visible and enabled
0314
0315 * **timeout** Raise an error if the window is not in the appropriate
0316 state after this number of seconds.
0317
0318 * **retry_interval** How long to sleep between each retry
0319
0320 e.g. self.Dlg.Wait("exists enabled visible ready")
0321
0322 See also: ``Application.WaitNot()``
0323 """
0324
0325
0326
0327 if timeout is None:
0328 timeout = Timings.exists_timeout
0329 if retry_interval is None:
0330 retry_interval = Timings.window_find_retry
0331
0332
0333 waitfor = wait_for.lower()
0334
0335
0336 wait_criteria = self.criteria[:]
0337
0338
0339
0340
0341 for criterion in wait_criteria:
0342 if 'exists' in waitfor:
0343 criterion['enabled_only'] = False
0344 criterion['visible_only'] = False
0345
0346 if 'visible' in waitfor:
0347 criterion['enabled_only'] = False
0348 criterion['visible_only'] = True
0349
0350 if 'enabled' in waitfor:
0351 criterion['enabled_only'] = True
0352 criterion['visible_only'] = False
0353
0354 if 'ready' in waitfor:
0355 criterion['visible_only'] = True
0356 criterion['enabled_only'] = True
0357
0358 if 'active' in waitfor:
0359 criterion['active_only'] = True
0360
0361 if self.app.use_history:
0362 ctrls = _resolve_from_appdata(
0363 wait_criteria,
0364 self.app,
0365 timeout,
0366 retry_interval)
0367 else:
0368 ctrls = _resolve_control(
0369 wait_criteria,
0370 timeout,
0371 retry_interval)
0372
0373
0374
0375 return ctrls[-1]
0376
0377 def WaitNot(self,
0378 wait_for_not,
0379 timeout = None,
0380 retry_interval = None):
0381
0382 """Wait for the window to not be in a particular state
0383
0384 * **wait_for** The state to wait for the window to not be in. It can be any
0385 of the following states
0386
0387 * 'exists' means that the window is a valid handle
0388 * 'visible' means that the window is not hidden
0389 * 'enabled' means that the window is not disabled
0390 * 'ready' means that the window is visible and enabled
0391 * 'active' means that the window is visible and enabled
0392
0393 * **timeout** Raise an error if the window is sill in the
0394 state after this number of seconds.(Optional)
0395 * **wiat_interval** How long to sleep between each retry (Optional)
0396
0397 e.g. self.Dlg.WaitNot("exists enabled visible ready")
0398
0399 See also: ``Application.WaitNot("exists enabled visible ready")``
0400 """
0401
0402
0403
0404 if timeout is None:
0405 timeout = Timings.window_find_timeout
0406 if retry_interval is None:
0407 retry_interval = Timings.window_find_retry
0408
0409
0410
0411
0412 waitnot_criteria = self.criteria[:]
0413 for criterion in waitnot_criteria:
0414 criterion['enabled_only'] = False
0415 criterion['visible_only'] = False
0416
0417 wait_for_not = wait_for_not.lower()
0418
0419
0420
0421
0422
0423 def WindowIsNotXXX():
0424 """Local function that returns False if the window is not
0425 Visible, etc. Otherwise returns the best matching control"""
0426
0427
0428
0429 try:
0430 if self.app.use_history:
0431 ctrls = _resolve_from_appdata(
0432 waitnot_criteria, self.app, 0, .01)
0433 else:
0434 ctrls = _resolve_control(waitnot_criteria, 0, .01)
0435
0436
0437
0438 except (findwindows.WindowNotFoundError, findbestmatch.MatchError):
0439
0440 return True
0441
0442 if 'exists' in wait_for_not:
0443
0444
0445
0446 return ctrls
0447
0448 if 'ready' in wait_for_not:
0449 if ctrls[-1].IsVisible() and ctrls[-1].IsEnabled():
0450 return ctrls
0451
0452 if 'enabled' in wait_for_not:
0453 if ctrls[-1].IsEnabled():
0454 return ctrls
0455
0456 if 'visible' in wait_for_not:
0457 if ctrls[-1].IsVisible():
0458 return ctrls
0459
0460 return True
0461
0462 try:
0463 wait_val = WaitUntil(timeout, retry_interval, WindowIsNotXXX)
0464 except TimeoutError, e:
0465 raise RuntimeError(
0466 "Timed out while waiting for window (%s - '%s') "
0467 "to not be in '%s' state"% (
0468 e.function_value[-1].Class(),
0469 e.function_value[-1].WindowText(),
0470 "', '".join( wait_for_not.split() ) )
0471 )
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581 def _ctrl_identifiers(self):
0582
0583 ctrls = _resolve_control(
0584 self.criteria)
0585
0586 if ctrls[-1].IsDialog(