Ve druhém článku o vývojovém prostředí PyDev se seznámíme s některými pokročilejšími technikami, které lze v tomto propracovaném IDE použít. Ukážeme si například nástroje sloužící k refaktoringu zdrojových kódů a taktéž si popíšeme propojení PyDev s nástroji určenými pro práci s jednotkovými testy (spouštění, automatické znovuspuštění, výpis výsledků).

Obsah

1. Integrovaná vývojová prostředí ve Fedoře: PyDev (2.část)

2. Automatické doplňování kódu a odskok na volané funkce či metody

3. Kontrola chyb prováděná v průběhu vytváření a editace zdrojového kódu

4. Základy refaktoringu zdrojových kódů

5. Vygenerování properties pro vybranou třídu

6. Vytvoření inicializátoru s předáním hodnot atributů

7. Přesun vybraného bloku kódu do samostatné funkce či metody

8. Transformace zdrojových kódů z Pythonu 2.x do Pythonu 3.x

9. Podpora pro jednotkové testy v prostředí PyDev

10. Manuální spuštění a kontinuální spouštění jednotkových testů

11. Předchozí části seriálu

12. Odkazy na Internetu

1. Integrovaná vývojová prostředí ve Fedoře: PyDev (2.část)

V první části článku o vývojovém prostředí PyDev jsme si popsali způsob instalace této aplikace (jedná se o přídavný modul/plugin určený pro Eclipse) a taktéž jsme se seznámili se základními koncepty, na nichž je Eclipse a tím pádem i PyDev postaveno. Připomeňme si jen, že v PyDev + Eclipse se používají takzvané perspektivy, v nichž jsou sdružovány okna editoru a další specializované pohledy. Programátor se může mezi jednotlivými perspektivami přepínat, popř. k přepnutí může dojít automaticky, například při ladění kódu atd. Při práci s PyDev je nutné vytvářet projekty, což není nic jiného než adresář obsahující zdrojové soubory psané v Pythonu, další datové či multimediální soubory a taktéž adresář s konfigurací projektu. Projekty i konfigurace perspektiv je možné přenášet mezi různými počítači popř. je ukládat a verzovat například s využitím GITu. Díky této vlastnosti je možné mít shodné vývojové prostředí jak na pracovním počítači tak i na domácím notebooku atd.

01

Obrázek 1: Nástroj PyDev ve spolupráci s interpretrem programovacího jazyka Python dokáže detekovat některé problematické části zdrojového kódu. Pro kontrolu sémantických chyb je však nutné používat testy.

Dnes se budeme zabývat popisem dalších nástrojů, které je možné v PyDev používat. Nejprve se zaměříme na nástroje určené pro doplňování kódu a kontrolu chyb ve zdrojových kódech, což je téma zpracované ve druhé a ve třetí kapitole. V navazujících kapitolách se seznámíme s některými technikami používanými při refaktoringu zdrojových kódů. Následovat bude popis transformace zdrojových kódů z Pythonu 2.x do Pythonu 3.x, protože se stále jedná o poměrně aktuální (a definitivně nevyřešené) téma. V závěrečné části článku bude popsáno rozhraní používané pro spouštění a generování výsledků z jednotkových testů (unit tests). Užitečná může být především podpora pro automatické spouštění těch testů, které nebyly úspěšné. Takové testy lze spouštět kdykoli po změně zdrojového kódu a zjistit tak, zda kód skutečně odpovídá podmínkám popsaným v testech (ještě více se tato vlastnost využije ve chvíli, kdy se používá test-driven development).

02

Obrázek 2: Označení nedefinované proměnné a nedefinované funkce patří mezi základní nástroje používané pro detekci chyb ve zdrojových kódech. Naproti tomu si povšimněte, že se nevypisují informace o nepoužitém parametru funkce reciprocal ani o nesouladu počtu parametrů při volání této funkce. Pro detekci těchto potenciálních chyb je možné použít například nástroj Pylint.

2. Automatické doplňování kódu a odskok na volané funkce či metody

Mezi další vlastnosti integrovaného vývojového prostředí PyDev patří automatické doplňování kódu a podpora okamžitého odskoku na zdrojový kód volané funkce či metody (popř. třídy). Použití automatického doplňování kódu je velmi snadné a intuitivní – kdykoli při psaní jména třídy, metody, atributu či lokální proměnné je možné použít klávesovou zkratku Ctrl+Space a editor implementovaný v PyDev buď přímo doplní celé jméno (které dává v daném kontextu smysl), nebo zobrazí seznam všech možných jmen, z nichž je možné provést výběr. Druhou možností je zapsat jméno třídy (popř. jméno objektu implementujícího nějakou třídu) a za ním tečku. V této chvíli se zobrazí podobné okno jako v předchozím případě, z něhož lze vybrat požadovanou metodu či atribut (to funguje velmi dobře především u zápisu „self.“, kdy editor přesně zná kontext). Užitečná je i klávesová zkratka F3, po jejímž stisku se zobrazí zdrojový kód příslušné třídy, metody či funkce (pokud je třída/metoda/funkce deklarována v jiném souboru, otevře se tento soubor v samostatném tabu).

3. Kontrola chyb prováděná v průběhu vytváření a editace zdrojového kódu

Integrované vývojové prostředí Eclipse se ve spolupráci s PyDev a interpretrem Pythonu snaží při každém uložení zdrojového kódu zavolat interpret a zjistit všechny chyby, které se ve zdrojovém kódu nachází. Tyto chyby jsou pak zvýrazněny červenou vlnovkou a navíc se na pravé straně editoru zobrazí červený obdélník, díky němuž lze chyby snadno lokalizovat i v rozsáhlejších zdrojových textech (ve výchozí konfiguraci se na levém okraji editoru zobrazí i ikona informující o chybě). Seznam všech chyb a případných varování se taktéž zobrazuje v pohledu „Problems“, jehož okno je v typické konfiguraci umístěno ve spodní části grafického uživatelského rozhraní integrovaného vývojového prostředí. U každé chyby je vypsána cesta k příslušnému zdrojovému souboru i konkrétní řádek, kde se chyba vyskytuje. PyDev nabízí i možnost opravy některých chyb – postačuje přejít kurzorem na konkrétní chybu a stlačit klávesovou zkratku Ctrl+1. V porovnání s Eclipse JDT jsou však nabízené možnosti menší, což souvisí s dynamickou povahou Pythonu. Nicméně takové základní operace, jako například doplnění importu, přidání funkce či metody, v okně „Quick Fix“ nalezneme.

03

Obrázek 3: Poměrně častá chyba – u inicializátoru chybí uvedení parametru „self“, což PyDev správně označí jako chybu a napíše návod na opravu (samotnou opravu však musí provést programátor).

4. Základy refaktoringu zdrojových kódů

Konečně se dostáváme k mnohem zajímavější a pro naprostou většinu programátorů velmi užitečné technologii – k podpoře takzvaného refaktoringu (refactoring). Integrované vývojové prostředí Eclipse ve spolupráci s PyDev totiž dokáže na žádost programátora měnit obsah zdrojových kódů, a to mnohdy i velmi radikálním způsobem. Mnoho změn je prováděno na globální úrovni celého projektu, což například znamená, že přejmenování metody je provedeno ve všech částech projektu, kde se tato metoda volá. Ovšem v žádném případě se nejedná o primitivní operaci typu „najdi a nahraď zadaný řetězec“, protože Eclipse dokáže v mnoha případech zjistit, kde je použita přejmenovávaná metoda a kde je naopak použita lokální proměnná, parametr apod. (v Pythonu ovšem tato operace nemusí být za všech okolností úspěšná, opět kvůli dynamičnosti jazyka.

04_

Obrázek 4: Dialog zobrazující změny ve zdrojovém kódu provedené po přejmenování funkce.

Podporovány jsou následující operace:

  1. Uložení mezivýsledku nějakého výpočtu do nové lokální proměnné. Postačuje vybrat část výrazu a zvolit příkaz Refactoring → Extract Local Variable.
  2. Vygenerování properties pro vybranou třídu. Bude ukázáno v páté kapitole.
  3. Vytvoření inicializátoru s předáním hodnot atributů. Touto technikou se budeme zabývat v šesté kapitole.
  4. Blok příkazů se může přesunout do samostatné funkce či metody. Bude ukázáno v sedmé kapitole.

04

Obrázek 5: Opravený kód z předchozího obrázku, který zároveň slouží jako základ pro další příklady popsané v navazujících dvou kapitolách.

5. Vygenerování properties pro vybranou třídu

V programovacím jazyku Python je možné pro vybranou třídu (či objekt) vytvořit takzvané properties, které umožňují, aby se volaly settery a gettery nějakého atributu s využitím operátoru tečky, tj. stylem objekt.atribut=výraz či xxx=objekt.atribut. Navíc je možné, pokud to samozřejmě povaha řešeného problému vyžaduje, povolit i volání speciální metody v případě použití příkazu del objekt.atribut (tato metoda se potom nazývá deleter). Properties se deklarují minimálně dvěma způsoby. První způsob spočívá v použití takzvaných dekorátorů, druhý pak v použití funkce property, díky níž je možné navázat určitý atribut na příslušný getter, setter, deleter atd. A právě vygenerování programového kódu, který toto navázání zajistí, může být provedeno automaticky v prostředí PyDev po zadání příkazu Refactoring → Generate Properties.

Průběh celé operace je rozdělen do několika kroků, které jsou vysvětleny na čtyřech snímcích grafického uživatelského rozhraní prostředí PyDev:

05

Obrázek 6: Dialog pro určení, které atributy budou dostupné přes properties. Před vyvoláním tohoto dialogu se musí textový kurzor nacházet uvnitř třídy a následně se musí zadat příkaz Refactoring → Generate Properties. Může se zvolit, pro které atributy se vytvoří gettery, settery, deletery atd.

06

Obrázek 7: Nástroj PyDev automaticky vygeneruje příslušný programový kód s metodami pro přístup k atributům a zobrazuje jeho náhled ve druhém dialogu.

07

Obrázek 8: Po stisku tlačítka Finish se vygenerované metody použité pro přístup k atributům vloží do zdrojového kódu.

08

Obrázek 9: V dolní části programátorského editoru můžeme vidět vygenerovaný kód s definicemi properties.

6. Vytvoření inicializátoru s předáním hodnot atributů

Při vytváření instance nějaké třídy se automaticky volají dvě metody: __new__ a __init__ (v tomto pořadí). První z těchto metod je volána ještě ve chvíli, kdy není objekt zkonstruován, druhá pak v okamžiku, kdy došlo ke konstrukci objektu a je nutné provést inicializaci jeho stavu. Tyto dvě metody jsou v ostatních programovacích jazycích většinou spojeny do jediné subrutiny nazývané konstruktor, ovšem Python je v tomto případě otevřenější a umožňuje programátorům, aby si definovali jak chování při vzniku objektu, tak i při inicializaci jeho stavu. Nás nyní bude zajímat „druhá polovina konstruktoru“ představovaná metodou __init__, protože v této metodě se nastavuje stav právě vytvořeného objektu, tj. inicializují se jeho atributy. Hodnoty atributů se typicky (ne však vždy) odvozují od parametrů předaných konstruktoru a právě zde existuje možnost si celou situaci zautomatizovat a nechat si příslušný zdrojový kód vygenerovat PyDevem. Opět se podívejme na sekvenci screenshotů s podrobnějším popisem:

09

Obrázek 10: V tomto dialogu zobrazeném po zadání příkazu Refactoring → Generate Constructor using Fields je možné vybrat ty atributy, jejichž hodnoty se budou nastavovat přes parametry předané inicializátoru, tj. funkci __init__.

10

Obrázek 11: Zajímají nás pouze atributy přístupné přes properties, proto vybereme jen část nabízených možností.

11

Obrázek 12: Kód vygenerovaný nástrojem PyDev. Povšimněte si, že původní inicializátor zůstal zachován a bude ho nutné smazat (popř. oba kódy ručně sloučit).

7. Přesun vybraného bloku kódu do samostatné funkce či metody

Pravděpodobně nejužitečnější funkce určená pro refaktoring programového kódu se vyvolává příkazem Refactoring → Extract Method. Tato funkce umožňuje, aby se určitý vybraný blok přenesl do samostatné funkce nebo metody, což může vést ke zjednodušení programu, k jeho snadnější testovatelnosti a samozřejmě taktéž k možnosti volat takto vytvořenou funkci či metodu i z dalších částí aplikace. Před extrakcí funkce/metody je nejdříve zapotřebí vybrat (do bloku) programový kód, který se má přenést. Přitom je zapotřebí zahrnout i případné lokální proměnné (jinak by se do nové funkce předávaly explicitně) a kód by měl mít jeden jasný výsledek. Ukažme si nyní použití této technologie pro přenos algoritmu pro výpočet faktoriálu do samostatné funkce (samotný výpočet obsahuje chybu, ale tou se budeme zabývat až v navazujícím textu):

12

Obrázek 13: Původní kód pro výpočet faktoriálu (tento kód navíc obsahuje chybu, kterou odhalíme při spouštění jednotkových testů – viz další text).

13

Obrázek 14: Vybereme tu část programového kódu, ze které budeme chtít vytvořit funkci. Zde se jedná o celý výpočet faktoriálu i s použitím pomocné proměnné (výběr se provádí běžnými blokovými operacemi, například Shift+kurzorové šipky).

14

Obrázek 15: Vybereme příkaz Refactoring → Extract Method. V dialogu, který se zobrazí, je nutné specifikovat parametry předávané do vytvářené funkce či metody. Zde je to jednoduché – jediným parametrem bude „n“.

15

Obrázek 16: Došlo k vytvoření funkce, samozřejmě se správným parametrem i příkazem pro předání návratové hodnoty zpět do volajícího kódu.

8. Transformace zdrojových kódů z Pythonu 2.x do Pythonu 3.x

V některých případech potřebují vývojáři upravit své aplikace, které byly původně psány pro Python 2.x, takovým způsobem, aby tyto aplikace byly použitelné s Pythonem 3.x. Pro tyto účely existuje nástroj (transcompiler, transpiler) nazvaný 2to3, který se více či méně úspěšně snaží detekovat a upravit ty programové konstrukce, které již v Pythonu 3.x nejsou podporovány či mají odlišný význam. Tento nástroj je možné vyvolat přímo z prostředí PyDev, a to konkrétně z kontextového menu vyvolaného pravým tlačítkem myši buď v editoru, nebo v Package Exploreru (to je okno zobrazené na screenshotech v levém sloupci). Z tohoto menu se vybere příkaz PyDev → Apply 2to3, který vyvolá dialog zobrazený na screenshotu číslo 18. Zde máme možnost ovlivnit chování nástroje 2to3. Nejdůležitější je přepínač -w, který povede k tomu, že 2to3 skutečně změní původní programový kód a nahradí ho kódem novým:

16

Obrázek 17: Původní programový kód psaný ve stylu Pythonu 2.x.

17

Obrázek 18: Dialog zobrazený po zadání příkazu PyDev → Apply 2to3 z kontextového menu programátorského editoru popř. Package Exploreru. Povšimněte si explicitního zadání přepínače -w.

18

Obrázek 19: Výsledný kód odpovídající konvencím Pythonu 3.x. V Package Exploreru si povšimněte, že se vytvořila záloha původního obsahu souboru se zdrojovým kódem.

9. Podpora pro jednotkové testy v prostředí PyDev

Integrované vývojové prostředí PyDev obsahuje podporu pro spouštění a následné generování výsledků z jednotkových testů (unit tests). Pro mnoho účelů může být užitečná především podpora pro automatické spouštění těch testů, které nebyly úspěšné. Takové testy lze spouštět kdykoli po změně zdrojového kódu a zjistit tak, zda upravený programový kód skutečně odpovídá podmínkám popsaným v testech. Podívejme se nyní na jednoduchý příklad, v němž otestujeme výše vytvořenou funkci factorial a zjistíme, že je ve skutečnosti naprogramována špatně :-). Test je představován třídou nazvanou pro jednoduchost Test. Tato třída musí být odvozena od třídy unittest.TestCase. Ve třídě bude implementováno mnoho testovacích metod, jejichž názvy začínají na test…. Vzhledem k tomu, že testujeme chování poměrně jednoduché funkce, vystačíme si s porovnáním výsledků, což má na starost zděděná metoda nazvaná assertEqual:

19

Obrázek 20: Vytvoření nové třídy nazvané Test, která je odvozena od třídy unittest.TestCase (to je velmi důležité pro další běh jednotkových testů). Povšimněte si použití self.assertEqual, jméno této metody naznačuje vše o jejím fungování. Testy byly spuštěny, což je vidět na výpisu na konzoli.

20

Obrázek 21: Výsledky běhu testů se nejlépe prohlížejí v okně PyUnit. Zde je patrné, že všechny testy proběhly bez chyby, což ovšem nemusí znamenat, že je i testovaný kód bez chyby, ale jen to, že netestujeme všechny varianty.

10. Manuální spuštění a kontinuální spouštění jednotkových testů

Manuálně se jednotkové testy spouští z hlavního menu Run příkazem Run As. Podívejme se, co se stane ve chvíli, kdy do testů přidáme další kontroly, zejména pak kontrolu výsledků pro n=2 a n=3:

21

Obrázek 22: Vzhledem k tomu, že je algoritmus implementovaný ve funkci factorial ve skutečnosti chybný, nahlásí správně vytvořené jednotkové testy chybu, což se stalo i v tomto případě. V pravé dolní části plochy IDE je vypsáno podrobnější hlášení o chybě – na kterém místě vznikla a co ji způsobilo.

Než chybu opravíme, přesvědčte se, že v pohledu PyUnit je vybráno (zatlačeno) tlačítko obsahující ikonu tužky a žluté šipky (na screenshotech se jedná o pátou ikonu v řadě). Pokud je toto tlačítko vybráno, budou se při změně zdrojového kódu, přesněji řečeno při jeho ukládání na disk, automaticky spouštět ty testy, které předtím proběhly neúspěšně. Ostatně si to můžeme snadno vyzkoušet, a to opravou zdrojového kódu funkce factorial, konkrétně v místě předání parametrů funkci range. Ihned po uložení zdrojového kódu pomocí Ctrl+S se testy spustí znovu, tentokrát již s očekávaným „zeleným“ výsledkem:

22

Obrázek 23: Po malé úpravě programového kódu funkce factorial již jednotkové testy žádné chyby (podle očekávání) nehlásí.

11. Předchozí části seriálu

  1. Vývojová prostředí ve Fedoře (1. díl)
    http://mojefedora.cz/vyvojova-prostredi-ve-fedore-1-dil/
  2. Vývojová prostředí ve Fedoře (2. díl)
    http://mojefedora.cz/vyvojova-prostredi-ve-fedore-2-dil/
  3. Vývojová prostředí ve Fedoře (3. díl)
    http://mojefedora.cz/vyvojova-prostredi-ve-fedore-3-dil/
  4. Vývojová prostředí ve Fedoře (4. díl)
    http://mojefedora.cz/vyvojova-prostredi-ve-fedore-4-dil/
  5. Integrovaná vývojová prostředí ve Fedoře: PyDev
    http://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-pydev/

12. Odkazy na Internetu

  1. Seznámení s Python IDE Spyder (článek vyšel zde na mojefedora.cz)
    http://mojefedora.cz/seznameni-s-python-ide-spyder/
  2. Stránka s popisem různých IDE pro Python
    http://quintagroup.com/cms/python/ide
  3. Eclipse (stránka o frameworku na Fedoraproject.org)
    https://fedoraproject.org/wiki/Eclipse
  4. PyDev (hlavní stránka)
    http://pydev.sourceforge.net/index.html
  5. PyDev (download, v podstatě není zapotřebí)
    http://pydev.sourceforge.net/download.html
  6. PyDev (stránka s metainformacemi o PyDev pluginu, použita v Eclipse)
    http://www.pydev.org/updates/
  7. PyDev (stránka s pluginem, použita v Eclipse)
    https://dl.bintray.com/fabioz/pydev/4.5.4/
  8. Certifikát, který lze do Eclipse doinstalovat
    http://www.pydev.org/pydev_certificate.cer
  9. PyDev FAQ
    http://pydev.sourceforge.net/faq.html
  10. PyDev (Wikipedia)
    https://en.wikipedia.org/wiki/PyDev
  11. Python (oficiální stránky projektu)
    https://www.python.org/
  12. Jython
    http://www.jython.org/
  13. IronPython
    http://ironpython.net/
  14. Python 3.5.1 documentation
    https://docs.python.org/3/
  15. PyDev: Unittest integration
    http://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-pydev/
  16. Continuous unit testing with Pydev (Python and Eclipse)
    http://stackoverflow.com/questions/1015581/continuous-unit-testing-with-pydev-python-and-eclipse
  17. Test-driven development
    https://en.wikipedia.org/wiki/Test-driven_development