본문 바로가기
Software coding skill(python, web등)

pywinauto 7 - 안정적인 자동화

by 호빵님 2020. 2. 11.
반응형

pywinauto 공식사이트 내용을 번역한 것입니다.

 

I start the application as I did before (app.start("C:\setup.exe") and then connect the application (app.connect(title="Setup")) so you are connected to the process that is running the GUI window.

어플리케이션을 start하고나서 connect를 해줘야, 실행중인 window의 프로세스에 connect된다.

 

pywinauto doesn't catch spawing additional processes (but we have plans to make windows manipulation available without process binding in the future).

pywinauto는 뜨고 있는 추가 프로세스들을 인식할 수 없다.

 

In your case you may try app.connect(path='calc.exe') or app.connect(title='Calculator') before finding the top level window.

탑 레벨 window를 찾기전에 계산기 예제라면, 계산기 프로세스에 connect해야한다.

 

https://pywinauto.readthedocs.io/en/latest/HowTo.html#how-to-specify-a-usable-application-instance

 

How To’s — pywinauto 0.6.8 documentation

The windows handle of a window of the application, e.g. app = Application().connect(handle=0x010f0c)

pywinauto.readthedocs.io

 

 

For this case we have UIA branch that is under development (but feedback is welcome). After installing comtypes package you will be able to run app = pywinauto.Application(backend='uia').start('calc.exe') that will use Microsoft UI Automation technology instead of native Win32 API (0.5.4 supports Win32 API only). Other high-level API should remain almost the same.

사용할 어플리케이션이 기존에 옛날 부터 쓰던 Win32 API 와 맞는지, 새로 만든 UIA에 맞는지에 따라서, backend설정을 다르게 한다.

 


 

Once you have an Application instance you can access dialogs in that application either by using one of the methods below. :: 

어플리케이션 인스턴스를 갖으면 그 어플리케이션 내의 다이얼로그에 접근할 수 있다. 아래 방법들을 사용한다.

dlg = app.YourDialogTitle 
dlg = app.ChildWindow(title = "your title", classname = "your class", ...) 
dlg = app['Your Dialog Title']

 

 

https://pywinauto.readthedocs.io/en/latest/HowTo.html#how-to-specify-a-dialog-of-the-application

 

How To’s — pywinauto 0.6.8 documentation

The windows handle of a window of the application, e.g. app = Application().connect(handle=0x010f0c)

pywinauto.readthedocs.io


 

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. 

GUI 어플리케이션은 자주 안정적이지 않고, 너의 스크립트는 새로운 window가 나타나거나 존재하는 window가 닫히거나/숨겨지는걸 기다리는 것이 필요하다.

 

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.

pywinauto는 유동적으로 다이얼로그 초기화를 암시적으로 기다린다.(기본 타임아웃설정) 혹은, 명시적으로 전용 메소드와 펑션을 사용해서 당신이 코드를 쉽고 믿을 수 있게 만들수 있도록 도와준다.

 


 

Application methods

 

• wait_cpu_usage_lower (new in pywinauto 0.5.2, renamed in 0.6.0)

 

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.

특별한 window 존재나 상태를 기다리지 않고, 전체 프로세스에 대한 CPU사용량이 계산작업이 아직 끝나지 않았다는 것을 가리킨다고 본다.

 

Example:

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

CPU사용량이 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.

이 메소드들은 모든 컨트롤들에서 사용할 수 있다.

 

 

• wait

control.wait("ready", timeout=10)

몇초 기다릴지 설정할 수 있다. default는 5초.

 

 

• wait_not

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

이 예제는 긴 대기가 포함되어 있다.

# Requirements:
#  - Win7 or Win8.1 x64, 64-bit Python
#  - pywinauto 0.5.2+
#  - 7z920-x64.msi is in the same folder as the script
#  - UAC is fully disabled
from __future__ import print_function
import sys, os
os.chdir(os.path.join(os.getcwd(), os.path.dirname(sys.argv[0])))
import pywinauto

app = pywinauto.Application().Start(r'msiexec.exe /i 7z920-x64.msi')

Wizard = app['7-Zip 9.20 (x64 edition) Setup']
Wizard.NextButton.Click()

Wizard['I &accept the terms in the License Agreement'].Wait('enabled').CheckByClick()
Wizard.NextButton.Click()

Wizard['Custom Setup'].Wait('enabled')
Wizard.NextButton.Click()

Wizard.Install.Click()

Wizard.Finish.Wait('enabled', timeout=30)
Wizard.Finish.Click()
Wizard.WaitNot('visible')

# final check
if os.path.exists(r"C:\Program Files\7-Zip\7zFM.exe"):
    print('OK')
else:
    print('FAIL')

 

A WindowSpecification object isn’t necessarily related to an existing window/control.

WindowSpecification object는 존재하는 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.

wait 메소드는 타겟 컨트롤이 존재하는지 보이는지, 사용가능한지 보증할 수 있다. (어떤 exception도 안 떳다면)

 


 

Functions in timings module

 

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

python code에 유용한 로우레벨 메소드들이 있다.

 

• wait_until

• wait_until_passes

 

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.

모든 function call이 타이밍 컨트롤을 갖는 다면, 위 코드를 사용할 수 있다.

# 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')

 

wait_until 모듈을 임포트해서 사용.

from pywinauto.timings import wait_until

wrapper = app.top_window().children()[0]
wait_until(timeout=5, retry_interval=0.1, wrapper.is_enabled)

 

 


 

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.

timing모듈은 그런 정지상태를 설정할 수 있다. 글로벌 변수를 설정함으로써 요구에 맞게 설정할 수 있다.

 

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)

 

 

반응형