Automatiseerime töölaua GUI Pythonis + pywinauto: kuidas sõbruneda MS UI Automationiga

Python teekonna pywinauto — on avatud allika projekt Windowsi lauaarvuti GUI rakenduste automatiseerimiseks. Viimase kahe aasta jooksul on sellele lisandunud mitu uut suurt funktsiooni:

  • MS UI automatiseerimise toe süsteem. Liides jääb samaks, ning nüüd toetatakse: WinForms, WPF, Qt5, Windows Store (UWP) ja nii edasi — peaaegu kõike, mis Windowsis on.
  • Taustsüsteemide/plugin’ide süsteem (praegu on neid kaks: vaikimisi "win32" ja uus "uia"). Edasi liigume sujuvalt platvormideülestesse lahendustesse.
  • Win32 hiire ja klaviatuuri hook'id (hot keys nagu pyHook).

Samuti teeme väikese ülevaate avatud lähtekoodiga lahendustest lauaarvuti automatiseerimiseks (ilma tõsise võrdluse pretensioonita).

See artikkel on osaliselt SQA Days 20 konverentsil Minskis peetud ettekande tõlgendus (videomaterjal ja Hiljuti toimunud online-kohtumisel IETF IPv6 Ops grupis rääkis Google'i võrginženäär Zhenya Lin'kova.), osaliselt vene keelne versioon Getting Started Guide pywinauto jaoks.

Alustame lühikese ülevaate andmisega avatud lähtekoodist selle valdkonna osas. Lauaarvuti GUI rakenduste jaoks on asjad veidi keerulisemad kui veebis, millel on Selenium. Siin on peamised lähenemisviisid:

Koordinaatide meetod

Kleebime klikikohtade koordinaate, lootes, et need on täpsed.
[+] Platvormidevaheline, lihtne rakendada.
[+] Lihtne on teha "record-replay" testide salvestust.
[-] Kõige vähem stabiilne muutuvate ekraani resolutsioonide, teemade, fondide, akende suuruse jne osas.
[-] Tõsise toe jaoks on vaja tohutult pingutada, tihti on lihtsam testid nullist uuesti genereerida või käsitsi testida.
[-] Automatiseerib ainult tegevusi, andmete kinnitamiseks ja väljajõudmiseks on muid meetodeid.

Tööriistad (platvormideülesed): autopy, PyAutoGUI, PyUserInput ja paljud teised. Üldiselt sisaldavad keerulisemad tööriistad seda funktsionaalsust (mitte alati platvormideüleselt).

Tuleb öelda, et koordinaatide meetod võib täiendada teisi lähenemisviise. Näiteks isiklike graafikute puhul saab klõpsata suhteliste koordinaatide järgi (akna/elemendi vasakult ülanurgast, mitte kogu ekraanist) — tavaliselt on see piisavalt usaldusväärne, eriti kui arvestada elemendi pikkust/laiust (siis ei sega erinev ekraani resolutsioon).

Teine variant: testimiseks eraldada ainult üks masin stabiilsete seadistustega (mitte ristplatvormiline, kuid teatud juhtudel sobib).

Mustriga piltide tuvastamine

[+] Ristplatvormiline
[+-] Suhteliselt usaldusväärne (parem kui koordinaatmeetod), kuid siiski nõuab näpunäiteid.
[-+] Suhteliselt aeglane, kuna vajab algoritmide tuvastamiseks CPU ressursse.
[-] Teksti tuvastamisest (OCR) ei räägita tavaliselt => tekstilisi andmeid ei saa kätte. Kuid minu teadmist mööda ei ole olemasolevad OCR lahendused selle tüübi ülesannete jaoks eriti usaldusväärsed ja laialdaselt rakendatud (teretulemast kommentaaridesse, kui see enam nii ei ole).

Tööriistad: Sikuli, Lackey (Sikuli ühilduv, puhtal Pythonil), PyAutoGUI.

Ligipääsu tehnoloogiad

[+] Kõige usaldusväärsem meetod, kuna võimaldab otsida teksti, olenemata sellest, kuidas see süsteemis või raamistikus joonistatud on.
[+] Võimaldab välja võtta tekstilisi andmeid => lihtsam kontrollida testitulemusi.
[+] Üldiselt kõige kiirem, kuna peaaegu ei kuluta CPU ressursse.
[-] Ristplatvormilise tööriista loomine on keeruline: absoluutselt kõik open-source raamatukogud toetavad ühte-kahte ligipääsetavuse tehnoloogiat. Windows/Linux/MacOS ei toeta keegi täielikult, välja arvatud tasulised sellised nagu TestComplete, UFT või Squish.
[-] Mitte alati on selline tehnoloogia üldse kergesti kätšmõistetav. Näiteks hübriidse ekraani testimine VirtualBoxis — siin ei pääse ilma pildituvastuseta. Kuid paljusid klassikalisi juhtumeid saab siiski rakendada ligipääsetavuse lähenemist. Edasi läheb jutt sellest.

Tööriistad: TestStack.White C#-l, Winium.Desktop C#-l (Seleniumi ühilduv), MS WinAppDriver C#-l (Appiumi ühilduv), pywinauto, pyatom (ühilduv LDTP-ga), Python-UIAutomation-for-Windows, RAutomation Ruby-l, LDTP (Linuxi Lauaarvuti Testimise Projekt) ja selle Windowsi versioon Cobra.

LDTP on tõenäoliselt ainus ristplatvormiline open-source tööriist (täpsemalt ligipääsetavuse tehnoloogiatele põhinev raamatukogude perekond). Siiski pole see eriti populaarne. Olen seda ise kasutanud, kuid tagasiside järgi ei ole selle liides kõige mugavam. Kui on positiivset tagasisidet, palun jagage kommentaarides.

Testbackdoor (a.k.a. sisemine jalgratas)

Ristplatvormiliste rakenduste jaoks teevad arendajad sageli sisemise mehhanismi testitavuse tagamiseks. Näiteks loovad nad rakenduses teenindava TCP serveri, millele testid ühenduvad ja saadavad tekstilisi käske: mida vajutada, kust andmeid võtta jne. Usaldusväärne, kuid mitte universaalne.

Peamised lauaarvuti ligipääsu tehnoloogiad

Hea vana Win32 API

Enamik Windowsi rakendusi, mis on kirjutatud enne WPF-i ja hilisema Windows Store'i käimist, on mingil määral ehitatud Win32 API-le. Nende hulka kuuluvad MFC, WTL, C++ Builder, Delphi, VB6 — kõik need tööriistad kasutavad Win32 API-d. Isegi Windows Forms on suuresti Win32 API-ga ühilduv.

Tööriistad: AutoIt (sarnane VB-le) ja Pythoni mähis pyautoit, AutoHotkey (oma keel, sisaldab IDispatch COM liidese), pywinauto (Python), RAutomation (Ruby), win32-autogui (Ruby).

Microsoft UI Automatiseerimine

Peamine pluss: MS UI Automation tehnoloogia toetab enamikku Windowsi GUI rakendustest, välja arvatud harvad erandid. Probleem: see ei ole õppimisel oluliselt lihtsam kui Win32 API. Vastasel juhul ei oleks kedagi, kes keeraks selle ümber.

Tegelikult on see komplekt custom COM liideseid (peamiselt, UIAutomationCore.dll), samuti .NET kestana namespace System.Windows.Automation. Muide, sellel on sisse toodud viga, mille tõttu mõned UI elemendid võivad jääda vahele. Seega on parem kasutada UIAutomationCore.dll otse (kui olete kuulnud UiaComWrapperist C#-s, siis see on see).

COM liideste variandid:

(1) Põhi IUknown — "iga kurja juur". Kõige madalama tasemega, mitte kunagi kasutajasõbralik.
(2) IDispatch ja selle tuletised (näiteks, Excel.Application), mida saab kasutada Pythonis paketi win32com.client abil (kuulub pyWin32-sse). Kõige mugavam ja kaunim variant.
(3) Custom liideseid, millega saab töötada kolmanda osapoole Python pakett comtypes.

Tööriistad: TestStack.White C#-l, pywinauto 0.6.0+, Winium.Desktop C#-l, Python-UIAutomation-for-Windows (nende C-kood UIAutomationCore.dll ümbritsemiseks ei ole avaldatud), RAutomation Ruby-s.

AT-SPI

Kuigi praktiliselt kõik Linuxi pereliigid on ehitatud X Window Systemile (Fedora 25-s vahetati "X'id" Wayland'i vastu), võimaldavad "X'id" tegeleda ainult ülataseme akendega ja hiire/kliendi sisendiga. Klahvide, loendibokside jne detailseks analüüsiks on olemas AT-SPI tehnoloogia. Kõige populaarsematel aknahalduritel on nii-öelda AT-SPI registri deemon, mis tagab rakendustele automatiseeritud GUI (minimaalselt toetatakse Qt ja GTK).

Tööriistad: pyatspi2.

pyatspi2, minu arvates, sisaldab liiga palju sõltuvusi nagu PyGObject. Ise tehnoloogia on saadaval tavalise dünaamilise raamatukoguna libatspi.so. Sellele on olemas Reference Manual. pywinauto raamatukogu jaoks plaanime AT-SPI toe rakendada just nii: laadides sisse libatspi.so ja mooduli ctypes. Ainuke väike probleem on õige versiooni kasutamine, kuna GTK+ ja Qt rakenduste jaoks on need veidi erinevad. Oodata on tõenäolist pywinauto 0.7.0 versiooni, kus on täielik Linuxi tugi, esimeses pooles 2018.

Apple Accessibility API

MacOS has its own automation language, AppleScript. To implement something similar in Python, you obviously need to use functions from Objective-C. Starting from MacOS 10.6, the pre-installed Python includes the pyobjc package. This will also simplify the list of dependencies for future support in pywinauto.

Tools: In addition to Apple Script, it is worth paying attention to ATOMac, also known as pyatom. It is compatible with the LDTP interface but is also a standalone library. There is a sample automation of iTunes on macOS, written by my student. There is a known issue: flexible timing (methods waitFor*) does not work. But overall, it's not a bad tool.

Kuidas alustada pywinautoga

First of all, arm yourself with a GUI object inspector (what is called a Spy tool). It will help you study the application from the inside: how the element hierarchy is arranged, what properties are available. The most well-known object inspectors are:

  • Spy++ — included with Visual Studio, including Express or Community Edition. It uses the Win32 API. Its clone is also well-known, AutoIt Window Info.
  • Inspect.exe — included in the Windows SDK. If you have it installed, you can find it on 64-bit Windows in the folder C:Program Files (x86)Windows Kits<winver>binx64. In the inspector itself, you need to select the mode UI Automation instead of MS AA (Active Accessibility, the predecessor of UI Automation).

Having illuminated the application completely, we choose the backend we will use. It is enough to specify the backend name when creating the Application object.

  • backend=»win32″ — is still used by default, works well with MFC, WTL, VB6, and other legacy applications.
  • backend=»uia» — a new backend for MS UI Automation: works perfectly with WPF and WinForms; also good for Delphi and Windows Store applications; works with Qt5 and some Java applications. In general, if Inspect.exe can see elements and their properties, this backend is suitable. Basically, most browsers also support UI Automation (Mozilla by default, while Chrome requires a command line switch --force-renderer-accessibility, to see elements on pages in Inspect.exe). Of course, competition with Selenium in this area is unlikely. It's just another way to work with the browser (may be useful for cross-product scenarios).

Sisenemispunktid automatiseerimiseks

The application is well studied. It's time to create an Application object and run it or attach to an already running one. This is not just a clone of the standard class subprocess.Popen, nimelt, sisene objekt, mis piirab kõiki teie toiminguid protsessi piiridega. See on väga kasulik, kui rakenduse mitu instantsi on käivitatud ja teisi tahate puudutada.

from pywinauto.application import Application
app = Application(backend="uia").start('notepad.exe')

# Kirjeldame aken, mida tahame leida protsessis Notepad.exe
dlg_spec = app.UntitledNotepad
# ootame, kuni aken tõeliselt ilmub
actionable_dlg = dlg_spec.wait('visible')

Kui soovite hallata korraga mitut rakendust, aitab teil klass Desktop. Näiteks Win10 kalkulaatoris on elementide hierarhia laiali mitmete protsesside vahel (mitte ainult calc.exe). Seega ei saa objekti Desktop ilma hakkama.

from subprocess import Popen
from pywinauto import Desktop

Popen('calc.exe', shell=True)
dlg = Desktop(backend="uia").Calculator
dlg.wait('visible')

Juureobjekt (Application või Desktop) — see on ainus koht, kus peab märkima bändi. Kõik muu asetub sujuvalt „spetsifikatsioon->wrapper“ kontseptsiooni, millest hiljem.

Akende/elementide spetsifikatsioonid

See on põhiidee, millele pywinauto liides põhineb. Saate kirjeldada aken/elementi umbkaudu või täpselt, isegi kui see veel ei eksisteeri või on juba suletud. Aknakäsitluse spetsifikatsioon (objekt WindowSpecification) hoiab endas kriteeriume, mille alusel tuleb otsida tegelikku akent või elementi.

Näide detailsetest aknaspetsifikatsioonist:

>>> dlg_spec = app.window(title='Untitled - Notepad')

>>> dlg_spec


>>> dlg_spec.wrapper_object()

Aknade otsimine toimub meetodi väljakutsumise kaudu .wrapper_object(). See tagastab mingi „wrapperi“ tegeliku akna/elemendi jaoks või annab ElementNotFoundError (mõnikord ElementAmbiguousError, kui leitud on mitu elementi, tähendab see, et otsingukriteerimit tuleb täpsustada). See „wrapper“ suudab juba teha mõningaid toiminguid elemendi või saada andmeid selle kohta.

Python võib varjata väljakutset .wrapper_object(), nii et lõplik kood muutub lühemaks. Soovitame seda kasutada ainult tõrkeotsimiseks. Järgmised kaks rida teevad täiesti sama:

dlg_spec.wrapper_object().minimize() # debugging
dlg_spec.minimize() # production

Aknaspetsifikatsiooni otsimiseks on palju kriteerime. Siin on vaid mõned näited:

# могут иметь несколько уровней
app.window(title_re='.* - Notepad$').window(class_name='Edit')

# можно комбинировать критерии (как AND) и не ограничиваться одним процессом приложения
dlg = Desktop(backend="uia").Calculator
dlg.window(auto_id='num8Button', control_type='Button')

Kõik võimalikud kriteeriumid on dokumentides funktsioonis pywinauto.findwindows.find_elements(…).

Juurdepääs atribuutide ja võtmete järgi

Python lihtsustab aknaspetsifikatsioonide loomist ja tuvastab objekti atribuudid dünaamiliselt (meetod on üle määratud __getattribute__). Loomulikult kehtivad atribuutide nimele samasugused piirangud nagu igasugustele muutujate nimedele (tühikute, komade ja muude erisümbolite sisestamine ei ole lubatud). Õnneks kasutab pywinauto nii nimetatud «best match» otsingualgoritmi, mis on vigade ja väikeste variatsioonide suhtes tolerantne.

app.UntitledNotepad
# sama mis
app.window(best_match='UntitledNotepad')

Kui vajate Unicode'i stringe (näiteks vene keele jaoks), tühikute jms, saate kasutada juurdepääsu võtme kaudu (nagu oleks see tavapärane sõnastik):

app['Untitled - Notepad']
# sama mis
app.window(best_match='Untitled - Notepad')

Viis reeglit maagiliste nimede jaoks

Kuidas teada saada ehtsaid maagilisi nimesid? Neid, mis määratakse elemendile enne otsingut. Kui olete määranud nime, mis on piisavalt sarnane ehtsele, leidub element.

  1. Pealkirja (tekst, nimi) järgi: app.Properties.OK.click()
  2. Teksti ja elemendi tüübi järgi: app.Properties.OKButton.click()
  3. Sordi ja numbri järgi: app.Properties.Button3.click() (nimed Button0 ja Button1 on seotud esimese leitud elemendiga, Button2 — teise, ja edasi juba järjestikku — nii on ajalooliselt juhtunud)
  4. Statilise teksti (vasakul või ülal) ja elemendi tüübi järgi: app.OpenDialog.FileNameEdit.set_text("") (kasulik dünaamilise tekstiga elementide puhul)
  5. Tüübi ja tekstiga sees: app.Properties.TabControlSharing.select("General")

Üldjuhul rakendatakse kaht-kolme reeglit korraga, harva rohkem. Et kontrollida, millised täpsed nimed on iga elemendi jaoks saadaval, võite kasutada meetodit print_control_identifiers(). See suudab trükkida elementide puu nii ekraanile kui ka faili. Iga elemendi puhul trükitakse tema ehtsad maagilised nimed. Samuti on võimalik sealt kopeerida üksikasjalikud kirjeldused alam-elementide kohta. Tulemuseks on skriptis midagi sellist:

app.Properties.child_window(title="Contains:", auto_id="13087", control_type="Edit")

Elementide puu ise — tavaliselt üsna suur tekstimaht.

>>> app.Properties.print_control_identifiers()

Kontrollidentifikaatorid:

Dialoog - 'Windows NT Properties' (L688, T518, R1065, B1006)
[u'Windows NT PropertiesDialog', u'Dialoog', u'Windows NT Properties']
child_window(title="Windows NT Properties", control_type="Window")
   |
   | Pilt - '' (L717, T589, R749, B622)
   | [u'', u'0', u'Pilt1', u'Pilt0', 'Pilt', u'1']
   | child_window(auto_id="13057", control_type="Image")
   |
   | Pilt - '' (L717, T630, R1035, B632)
   | ['Pilt2', u'2']
   | child_window(auto_id="13095", control_type="Image")
   |
   | Redigeeri - 'Kataloogi nimi:' (L790, T596, R1036, B619)
   | [u'3', 'Redigeeri', u'Redigeeri1', u'Redigeeri0']
   | child_window(title="Kataloogi nimi:", auto_id="13156", control_type="Edit")
   |
   | Staatiline - 'Tüüp:' (L717, T643, R780, B658)
   | [u'Tüüp:Staatiline', u'Static', u'Static1', u'Tüüp:']
   | child_window(title="Tüüp:", auto_id="13080", control_type="Text")
   |
   | Redigeeri - 'Tüüp:' (L790, T643, R1036, B666)
   | [u'4', 'Redigeeri2', u'Tüüp:Redigeeri']
   | child_window(title="Tüüp:", auto_id="13059", control_type="Edit")
   |
   | Staatiline - 'Asukoht:' (L717, T669, R780, B684)
   | [u'Asukoht:Staatiline', u'Asukoht:', u'Static2']
   | child_window(title="Asukoht:", auto_id="13089", control_type="Text")
   |
   | Redigeeri - 'Asukoht:' (L790, T669, R1036, B692)
   | ['Redigeeri3', u'Asukoht:Redigeeri', u'5']
   | child_window(title="Asukoht:", auto_id="13065", control_type="Edit")
   |
   | Staatiline - 'Suurus:' (L717, T695, R780, B710)
   | [u'Suurus:Staatiline', u'Suurus:', u'Static3']
   | child_window(title="Suurus:", auto_id="13081", control_type="Text")
   |
   | Redigeeri - 'Suurus:' (L790, T695, R1036, B718)
   | ['Redigeeri4', u'6', u'Suurus:Redigeeri']
   | child_window(title="Suurus:", auto_id="13064", control_type="Edit")
   |
   | Staatiline - 'Suurus kettal:' (L717, T721, R780, B736)
   | [u'Suurus kettal:', u'Suurus kettal:Staatiline', u'Static4']
   | child_window(title="Suurus kettal:", auto_id="13107", control_type="Text")
   |
   | Redigeeri - 'Suurus kettal:' (L790, T721, R1036, B744)
   | ['Redigeeri5', u'7', u'Suurus kettal:Redigeeri']
   | child_window(title="Suurus kettal:", auto_id="13106", control_type="Edit")
   |
   | Staatiline - 'Sisaldab:' (L717, T747, R780, B762)
   | [u'Sisaldab:1', u'Sisaldab:0', u'Sisaldab:Staatiline', u'Static5', u'Sisaldab:']
   | child_window(title="Sisaldab:", auto_id="13088", control_type="Text")
   |
   | Redigeeri - 'Sisaldab:' (L790, T747, R1036, B770)
   | [u'8', 'Redigeeri6', u'Sisaldab:Redigeeri']
   | child_window(title="Sisaldab:", auto_id="13087", control_type="Edit")
   |
   | Pilt - 'Sisaldab:' (L717, T773, R1035, B775)
   | [u'Sisaldab:Pilt', 'Pilt3', u'Sisaldab:2']
   | child_window(title="Sisaldab:", auto_id="13096", control_type="Image")
   |
   | Staatiline - 'Loodi:' (L717, T786, R780, B801)
   | [u'Loodi:', u'Loodi:Staatiline', u'Static6', u'Loodi:1', u'Loodi:0']
   | child_window(title="Loodi:", auto_id="13092", control_type="Text")
   |
   | Redigeeri - 'Loodi:' (L790, T786, R1036, B809)
   | [u'Loodi:Redigeeri', 'Redigeeri7', u'9']
   | child_window(title="Loodi:", auto_id="13072", control_type="Edit")
   |
   | Pilt - 'Loodi:' (L717, T812, R1035, B814)
   | [u'Loodi:Pilt', 'Pilt4', u'Loodi:2']
   | child_window(title="Loodi:", auto_id="13097", control_type="Image")
   |
   | Staatiline - 'Atribuudid:' (L717, T825, R780, B840)
   | [u'Atribuudid:Staatiline', u'Static7', u'Atribuudid:']
   | child_window(title="Atribuudid:", auto_id="13091", control_type="Text")
   |
   | Kontrollkast - 'Ainult lugemine (kehtib ainult kataloogis olevatele failidele)' (L790, T825, R1035, B841)
   | [u'Kontrollkasti0', u'Kontrollkasti1', 'Kontrollkaste', u'Ainult lugemine (kehtib ainult kataloogis olevatele failidele)Kontrollkaste', u'Ainult lugemine (kehtib ainult kataloogis olevatele failidele)']
   | child_window(title="Ainult lugemine (kehtib ainult kataloogis olevatele failidele)", auto_id="13075", control_type="CheckBox")
   |
   | Kontrollkaste - 'Peidetud' (L790, T848, R865, B864)
   | ['Kontrollkaste2', u'PeidetudKontrollkaste', u'Peidetud']
   | child_window(title="Peidetud", auto_id="13076", control_type="CheckBox")
   |
   | Nupp - 'Täpsem...' (L930, T845, R1035, B868)
   | [u'Täpsem...', u'Täpsem...Nupp', 'Nupp', u'Nupp1', u'Nupp0']
   | child_window(title="Täpsem...", auto_id="13154", control_type="Button")
   |
   | Nupp - 'OK' (L814, T968, R889, B991)
   | ['Nupp2', u'OK', u'OKNupp']
   | child_window(title="OK", auto_id="1", control_type="Button")
   |
   | Nupp - 'Tühista' (L895, T968, R970, B991)
   | ['Nupp3', u'TühistaNupp', u'Tühista']
   | child_window(title="Tühista", auto_id="2", control_type="Button")
   |
   | Nupp - 'Rakenda' (L976, T968, R1051, B991)
   | ['Nupp4', u'RakendaNupp', u'Rakenda']
   | child_window(title="Rakenda", auto_id="12321", control_type="Button")
   |
   | Vahekaardikontroll - '' (L702, T556, R1051, B962)
   | [u'10', u'VahekaardiJagamine', u'VahekaardiEelmised versioonid', u'VahekaardiTurve', u'Vahekaardi', u'VahekaardiKohanda']
   | child_window(auto_id="12320", control_type="Tab")
   |    |
   |    | VahekaardiElement - 'Üldine' (L704, T558, R753, B576)
   |    | [u'ÜldineVahekaardiElement', 'VahekaardiElement', u'Üldine', u'VahekaardiElement0', u'VahekaardiElement1']
   |    | child_window(title="Üldine", control_type="TabItem")
   |    |
   |    | VahekaardiElement - 'Jagamine' (L753, T558, R801, B576)
   |    | [u'Jagamine', u'JagamineVahekaardiElement', 'VahekaardiElement2']
   |    | child_window(title="Jagamine", control_type="TabItem")
   |    |
   |    | VahekaardiElement - 'Turve' (L801, T558, R851, B576)
   |    | [u'Turve', 'VahekaardiElement3', u'TurveVahekaardiElement']
   |    | child_window(title="Turve", control_type="TabItem")
   |    |
   |    | VahekaardiElement - 'Eelmised versioonid' (L851, T558, R947, B576)
   |    | [u'Eelmised versioonidVahekaardiElement', u'Eelmised versioonid', 'VahekaardiElement4']
   |    | child_window(title="Eelmised versioonid", control_type="TabItem")
   |    |
   |    | VahekaardiElement - 'Kohanda' (L947, T558, R1007, B576)
   |    | [u'KohandaVahekaardiElement', 'VahekaardiElement5', u'Kohanda']
   |    | child_window(title="Kohanda", control_type="TabItem")
   |
   | Pealkiririba - 'Puudub' (L712, T521, R1057, B549)
   | ['Pealkiririba', u'11']
   |    |
   |    | Menüü - 'Süsteem' (L696, T526, R718, B548)
   |    | [u'Süsteem0', u'Süsteem', u'Süsteem1', u'Menüü', u'SüsteemiMenüü']
   |    | child_window(title="Süsteem", auto_id="MenuBar", control_type="MenuBar")
   |    |    |
   |    |    | MenüüElement - 'Süsteem' (L696, T526, R718, B548)
   |    |    | [u'Süsteem2', u'MenüüElement', u'SüsteemiMenüüElement']
   |    |    | child_window(title="Süsteem", control_type="MenuItem")
   |    |
   |    | Nupp - 'Sulge' (L1024, T519, R1058, B549)
   |    | [u'SulgeNupp', u'Sulge', 'Nupp5']
   |    | child_window(title="Sulge", control_type="Button")

Mõnel juhul võib kogu puu printimine olla aeglane (näiteks iTunes'is, kus ühes vahekaardis on lausa kolm tuhat elementi), kuid saab kasutada parameetrit depth (sügavus): depth=1 — iseenesest element, depth=2 — ainult vahetud lapsed, ja nii edasi. Seda saab ka spetsifikatsioonides kasutada loomiseks child_window.

Näited

Me pidevalt täiendame näidiste loendit repos. Viimastest väärib märkimist WireSharki võrguanalüsaatori automatiseerimine (see on hea näide Qt5 rakendusest; kuigi seda ülesannet saab lahendada ka ilma GUI-ta, sest on olemas scapy.Sniffer Pythoni paketist scapy). Samuti on olemas MS Painti automatiseerimise näide koos selle Ribbon tööriistaribaga.

Veel üks suurepärane näide, mille kirjutas minu üliõpilane: faili lohistamine explorer.exe-st Chrome'i lehele Google Drive'i jaoks (see lisatakse peavaramusse natukene hiljem).

Ja muidugi, näide klaviatuuri (kiirklahvide) ja hiire sündmustele tellimisest:
hook_and_listen.py.

Tänud

Eriti suur tänu — neile, kes pidevalt aitavad projekti arendada. Minu jaoks ja Valentina on see pidev hobi. Kaks minu üliõpilast NNGU-st kaitsesid hiljuti bakalaureusekraadi selle teemal. Aleksander andis suure panuse MS UI automatiseerimise toe arendamisse ja alustas hiljuti automaatse koodi genereerimise loomist „salvestamine-mängimine” printsiibi järgi tekstipõhiste omaduste alusel (see on kõige keerulisem funktsioon), praegu ainult „uia” tagaplaanile. Ivan arendab Linuxi jaoks uut tagapletni AT-SPI alusel (moodulid mouse ja keyboard põhjal python-xlib — juba versioonides 0.6.x).

Kuna ma olen juba mõnda aega õpetanud Pythoni automatiseerimise erikursust, täidavad mõned magistriõppe üliõpilased kodutöid, rakendades väikseid funktsioone või automatiseerimise näiteid. Mõningad olulised asjad, mis on uurimisetappid, avastasid kunagi üliõpilased. Kuigi mõnikord tuleb koodi kvaliteedi üle rangelt järele valvata. Sellest on suurt abi statilised analüsaatorid (QuantifiedCode, Codacy ja Landscape) ja automaatsed testid pilves (AppVeyori teenus) koodi katvusega umbes 95%.

Samuti suur tänu kõigile, kes jätavad tagasisidet, avavad vigu ja saadavad pull-request'e!

Lisainfo

Küsimustega jälgime me märgist StackOverflow'is (hiljuti tekkis silt venekeelses SO-s) ja võtmesõnaga Tosteris. On olemas venekeelne jututuba Gitteris.

Iga kuu uuendame open-source raamatukogude edetabelit GUI testimiseksGitHubis tõusnud vaid Autohotkey (neil on väga suur kogukond ja pikk ajalugu) ja PyAutoGUI (suures osas tänu oma autori Al Sweigarti populaarsetele raamatutele: „Automate the Boring Stuff with Python“ ja teistele).

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster