Waiting for Long Operations

A GUI application behaviour is often unstable and your script needs waiting until a new window appears or an existing window is closed/hidden. pywinauto can flexibly wait for a dialog initialization implicitly (with the default timeout) or explicitly using dedicated methods/functions that could help you to make your code easier and more reliable.

Application methods

This method is useful for multi-threaded interfaces that allow a lazy initialization in another thread while GUI is responsive and all controls already exist and seems ready to use. So waiting for a specific window existence/state is useless. In such case the CPU usage for the whole process indicates that a task calculation is not finished yet.

Example:

app.wait_cpu_usage_lower(threshold=5) # wait until CPU usage is lower than 5%

NOTE: this method is available for the whole application process only, not for a window/element.

WindowSpecification methods

These methods are available to all controls.

There is an example containing long waits: install script for 7zip 9.20 x64.

A WindowSpecification object isn’t necessarily related to an existing window/control. It’s just a description namely a couple of criteria to search the window. The wait method (if no any exception is raised) can guarantee that the target control exists or even visible, enabled and/or active.

Functions in timings module

There are also low-level methods useful for any Python code.

Decorators pywinauto.timings.always_wait_until() and pywinauto.timings.always_wait_until_passes() can also be used if every function call should have timing control.

# call ensure_text_changed(ctrl) every 2 sec until it's passed or timeout (4 sec) is expired

@always_wait_until_passes(4, 2)
def ensure_text_changed(ctrl):
    if previous_text == ctrl.window_text():
        raise ValueError('The ctrl text remains the same while change is expected')

Global timings for all actions

Many actions require some pause before, after and in-between. There are several global constants in module timings defining such pauses. It can be aligned for your needs individually by setting global static variables in object timings.Timings.

All global timings can be set to default at once, or doubled, or divided by two:

from timings import Timings

Timings.defaults()
Timings.slow() # double all timings (~2x slower script execution)
Timings.fast() # divide all timings by two (~2x faster)

Identify controls

The methods to help you to find a needed control.

How To`s