pyWinAuto: c:\.projects\py_pywinauto\pywinauto\timings.py

0001# GUI Application automation and testing library
0002# Copyright (C) 2006 Mark Mc Mahon
0003#
0004# This library is free software; you can redistribute it and/or
0005# modify it under the terms of the GNU Lesser General Public License
0006# as published by the Free Software Foundation; either version 2.1
0007# of the License, or (at your option) any later version.
0008#
0009# This library is distributed in the hope that it will be useful,
0010# but WITHOUT ANY WARRANTY; without even the implied warranty of
0011# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
0012# See the GNU Lesser General Public License for more details.
0013#
0014# You should have received a copy of the GNU Lesser General Public
0015# License along with this library; if not, write to the
0016#    Free Software Foundation, Inc.,
0017#    59 Temple Place,
0018#    Suite 330,
0019#    Boston, MA 02111-1307 USA
0020
0021"""Timing settings for all of pywinauto
0022
0023This module has one object that should be used for all timing adjustments
0024  timings.Timings
0025
0026There are a couple of predefined settings
0027
0028timings.Timings.Fast()
0029timings.Timings.Defaults()
0030timings.Timings.Slow()
0031
0032The Following are the individual timing settings that can be adjusted:
0033
0034* window_find_timeout   (default 3)
0035* window_find_retry (default .09)
0036
0037* app_start_timeout (default 10)
0038* app_start_retry   (default .90)
0039
0040* exists_timeout    (default .5)
0041* exists_retry  (default .3)
0042
0043* after_click_wait  (default .09)
0044* after_clickinput_wait (default .01)
0045
0046* after_menu_wait   (default .05)
0047
0048* after_sendkeys_key_wait   (default .01)
0049
0050* after_button_click_wait   (default 0)
0051
0052* before_closeclick_wait    (default .1)
0053* closeclick_retry  (default .05)
0054* closeclick_dialog_close_wait  (default .05)
0055* after_closeclick_wait (default .2)
0056
0057* after_windowclose_timeout (default 2)
0058* after_windowclose_retry (default .5)
0059
0060* after_setfocus_wait   (default .06)
0061
0062* after_setcursorpos_wait   (default .01)
0063
0064* sendmessagetimeout_timeout   (default .001)
0065
0066* after_tabselect_wait   (default .01)
0067* after_listviewselect_wait   (default .01)
0068* after_listviewcheck_wait  default(.001)
0069
0070* after_treeviewselect_wait  default(.001)
0071
0072* after_toobarpressbutton_wait  default(.01)
0073
0074* after_updownchange_wait  default(.001)
0075
0076* after_movewindow_wait  default(0)
0077* after_buttoncheck_wait  default(0)
0078* after_comboselect_wait  default(0)
0079* after_listboxselect_wait  default(0)
0080* after_listboxfocuschange_wait  default(0)
0081* after_editsetedittext_wait  default(0)
0082* after_editselect_wait  default(0)
0083
0084"""
0085
0086import time
0087import operator
0088
0089
0090__revision__ = "$Revision: 453 $"
0091
0092
0093#=========================================================================
0094class TimeConfig(object):
0095    "Central storage and minipulation of timing values"
0096    __default_timing = {
0097        'window_find_timeout' : 3,
0098        'window_find_retry' : .09,
0099
0100        'app_start_timeout' : 10,
0101        'app_start_retry' : .90,
0102
0103        'exists_timeout' : .5,
0104        'exists_retry' : .3,
0105
0106        'after_click_wait' : .09,
0107        'after_clickinput_wait' : .01,
0108
0109        'after_menu_wait' : .05,
0110
0111        'after_sendkeys_key_wait' : .01,
0112
0113        'after_button_click_wait' : 0,
0114
0115        'before_closeclick_wait' : .1,
0116        'closeclick_retry' : .05,
0117        'closeclick_dialog_close_wait' : .05,
0118        'after_closeclick_wait' : .2,
0119
0120        'after_windowclose_timeout': 2,
0121        'after_windowclose_retry':  .5,
0122
0123        'after_setfocus_wait' : .06,
0124
0125        'after_setcursorpos_wait' : .01,
0126
0127        'sendmessagetimeout_timeout' : .001,
0128
0129        'after_tabselect_wait': .01,
0130
0131        'after_listviewselect_wait': .01,
0132        'after_listviewcheck_wait': .001,
0133
0134        'after_treeviewselect_wait': .001,
0135
0136        'after_toobarpressbutton_wait': .01,
0137
0138        'after_updownchange_wait': .001,
0139
0140        'after_movewindow_wait': 0,
0141        'after_buttoncheck_wait': 0,
0142        'after_comboboxselect_wait': 0,
0143        'after_listboxselect_wait': 0,
0144        'after_listboxfocuschange_wait': 0,
0145        'after_editsetedittext_wait': 0,
0146        'after_editselect_wait': 0,
0147    }
0148
0149
0150    _timings = __default_timing.copy()
0151    _cur_speed = 1
0152
0153    def __getattr__(self, attr):
0154        "Get the value for a particular timing"
0155        if attr in TimeConfig.__default_timing:
0156            return TimeConfig._timings[attr]
0157        else:
0158            raise KeyError(
0159                "Unknown timing setting: %s" % attr)
0160
0161    def __setattr__(self, attr, value):
0162        "Set a particular timing"
0163        if attr in TimeConfig.__default_timing:
0164            TimeConfig._timings[attr] = value
0165        else:
0166            raise KeyError(
0167                "Unknown timing setting: %s" % attr)
0168
0169    def Fast(self):
0170        """Set fast timing values
0171
0172        Currently this changes the timing in the following ways:
0173        timeouts = 1 second
0174        waits = 0 seconds
0175        retries = .001 seconds (minimum!)
0176
0177        (if existing times are faster then keep existing times)
0178        """
0179
0180        for setting in TimeConfig.__default_timing:
0181            # set timeouts to the min of the current speed or 1 second
0182            if "_timeout" in setting:
0183                TimeConfig._timings[setting] = min(1, TimeConfig._timings[setting])
0184
0185            if "_wait" in setting:
0186                TimeConfig._timings[setting] = 0
0187
0188            elif setting.endswith("_retry"):
0189                TimeConfig._timings[setting] = 0.001
0190
0191            #self._timings['app_start_timeout'] = .5
0192
0193
0194    def Slow(self):
0195        """Set slow timing values
0196
0197        Currently this changes the timing in the following ways:
0198        timeouts = default timeouts * 10
0199        waits = default waits * 3
0200        retries = default retries * 3
0201
0202        (if existing times are slower then keep existing times)
0203        """
0204        for setting in TimeConfig.__default_timing:
0205            if "_timeout" in setting:
0206                TimeConfig._timings[setting] = max(
0207                    TimeConfig.__default_timing[setting] * 10,
0208                    TimeConfig._timings[setting])
0209
0210            if "_wait" in setting:
0211                TimeConfig._timings[setting] = max(
0212                    TimeConfig.__default_timing[setting] * 3,
0213                    TimeConfig._timings[setting])
0214
0215            elif setting.endswith("_retry"):
0216                TimeConfig._timings[setting] = max(
0217                    TimeConfig.__default_timing[setting] * 3,
0218                    TimeConfig._timings[setting])
0219
0220            if TimeConfig._timings[setting] < .2:
0221                TimeConfig._timings[setting]= .2
0222
0223    def Defaults(self):
0224        "Set all timings to the default time"
0225        TimeConfig._timings = TimeConfig.__default_timing.copy()
0226
0227
0228Timings = TimeConfig()
0229
0230
0231#=========================================================================
0232class TimeoutError(RuntimeError):
0233    pass
0234
0235
0236#=========================================================================
0237def WaitUntil(
0238    timeout,
0239    retry_interval,
0240    func,
0241    value = True,
0242    op = operator.eq,
0243    *args):
0244
0245    """Wait until ``op(function(*args), value)`` is True or until timeout 
0246       expires
0247    
0248     * **timeout**  how long the function will try the function
0249     * **retry_interval**  how long to wait between retries
0250     * **func** the function that will be executed
0251     * **value**  the value to be compared against (defaults to True)
0252     * **op** the comparison function (defaults to equality)\
0253     * **args** optional arguments to be passed to func when called
0254     
0255     Returns the return value of the function
0256     If the operation times out then the return value of the the function 
0257     is in the 'function_value' attribute of the raised exception.
0258     
0259     e.g. ::
0260      
0261      try:
0262         # wait a maximum of 10.5 seconds for the 
0263         # the objects ItemCount() method to return 10
0264         # in increments of .5 of a second
0265         WaitUntil(10.5, .5, self.ItemCount, 10)
0266      except TimeoutError, e:
0267         print "timed out"
0268     
0269    """
0270
0271    start = time.time()
0272
0273    func_val = func(*args)
0274    # while the function hasn't returned what we are waiting for    
0275    while not op(func_val, value):
0276
0277        # find how long we have waited
0278        waited = time.time() - start
0279
0280        # if we have to wait some more        
0281        if waited < timeout:
0282            # wait either the retry_interval or else the amount of
0283            # time until the timeout expires (whichever is less)
0284            time.sleep(min(retry_interval, timeout - waited))
0285            func_val = func(*args)
0286        else:
0287            err = TimeoutError("timed out")
0288            err.function_value = func_val
0289            raise err
0290
0291    return func_val
0292
0293
0294#def WaitUntilNot(timeout, retry_interval, func, value = True)
0295#    return WaitUntil(timeout, retry_interval, func, value = True)
0296
0297
0298def WaitUntilPasses(
0299    timeout,
0300    retry_interval,
0301    func,
0302    exceptions = (Exception),
0303    *args):
0304
0305    """Wait until ``func(*args)`` does not raise one of the exceptions in 
0306       exceptions
0307    
0308     * **timeout**  how long the function will try the function
0309     * **retry_interval**  how long to wait between retries
0310     * **func** the function that will be executed
0311     * **exceptions**  list of exceptions to test against (default: Exception)
0312     * **args** optional arguments to be passed to func when called
0313     
0314     Returns the return value of the function
0315     If the operation times out then the original exception raised is in
0316     the 'original_exception' attribute of the raised exception.
0317     
0318     e.g. ::
0319     
0320      try:
0321         # wait a maximum of 10.5 seconds for the 
0322         # window to be found in increments of .5 of a second.
0323         # P.int a message and re-raise the original exception if never found.
0324         WaitUntilPasses(10.5, .5, self.Exists, (WindowNotFoundError))
0325      except TimeoutError, e:
0326         print "timed out"
0327         raise e.
0328     
0329    """
0330
0331    start = time.time()
0332    waited = 0
0333
0334    # keep trying until the timeout is passed
0335    while waited <= timeout:
0336        try:
0337            # Call the function with any arguments
0338            func_val = func(*args)
0339
0340            # if this did not raise an exception -then we are finised
0341            break
0342
0343        # An exception was raised - so wait and try again
0344        except exceptions, e:
0345            waited = time.time() - start
0346
0347            if  waited < timeout:
0348                time.sleep(min(retry_interval, timeout - waited))
0349            else:
0350                # re-raise the original exeption
0351                err = TimeoutError()
0352                err.original_exception = e
0353                raise err
0354
0355    # return the function value
0356    return func_val
0357
0358
0359#
0360#
0361#
0362#def Defaults():
0363#    _current_timing = __default_timing.copy()
0364#
0365#
0366#def Slow():
0367#    for setting in __default_timing:
0368#        if "_timeout" in setting:
0369#            _current_timing[setting] = _default_timing[setting] * 10
0370#
0371#        if "_wait" in setting:
0372#            _current_timing[setting] = _default_timing[setting] * 3
0373#
0374#        elif setting.endswith("_retry"):
0375#            _current_timing[setting] = _default_timing[setting] * 3
0376#
0377#
0378#
0379#def SetTiming(**kwargs):
0380#    ""
0381#
0382#    for setting, time in kwargs.items():
0383#        if setting in __default_timing:
0384#            _current_timing[setting] = time
0385#        else:
0386#            raise KeyError(
0387#                "Unknown timing setting: %s" % setting)
0388#
0389#def Get(setting):
0390#    if setting in __default_timing:
0391#        return _current_timing[setting]
0392#    else:
0393#        raise KeyError(
0394#            "Unknown timing setting: %s" % setting)