Měl jsem možnost se podívat na PyCON UK a nelituji. Odnesl jsem si spoustu nových znalostí, tipů, na co se podívat či co aplikovat v praxi. Něco málo předám dál.
Logování
Můžete se snažit jak chcete, ale uživatelé vždycky najdou chyby ve vašich aplikacích. Kvůli tomu je potřeba si zajistit dobré logování a o tom byla jedna z prvních přednášek. Tipy jsou poměrně jasné, ale je dobré si je připomenout, stejně jako tak prozkoumat, zda neexistují nějaké nové pomůcky, které se mohou hodit.
Základ je logovat tak, aby šlo chybu jednoduše znovu vyvolat. Ještě lepší by byl formát, abych to mohl jednoduše hodit do unit testů. Což je sice hezká idea, ale přednášející ji dál nerozváděl a nedovedu si představit jak něco takového zautomatizovat. Ale rozhodně stojí na zamyšlenou. U webovek by šlo třeba generovat aspoň základ Seleniového testu…
Během přednášky zaznělo několik toolů na správu reportovaných chyb. Z nich mě zaujal například Sentry, který zvládne víc, než jen sbírat chyby, ale také umí vyhledávat duplicity. Mám chuť už dlouho udělat u naší aplikace automatické nahrávání bugů do systému, z čehož mě stále odrazují duplicity. Přednáška mi sice nedala odkaz na tool, který by se mi přesně hodil, ale minimálně mne nakopla se k tomuto problému vrátit a konečně vyřešit.
Refaktorování
Další obsahově zajímavá přednáška byla o Rope. Pythoní balík umožňující refaktoring. Občas se hodí udělat přejmenování některé proměnné, která je prolezlá všude možně. To se pak do práce moc nechce. Proto mne seznámení s Rope potěšilo. Škoda jen, že zatím není tolik propojení s editory (pro vim či emacs plugin samozřejmě existuje). Proto vznikl projekt Traad, který je nadstavba nad Rope komunikující v JSON, s čímž dnes komunikuje snad každý. Jsem zvědav, zda to podpoří vytvoření pluginů pro další editory.
Jak jsem však zmínil, jedná se o Pythoní balík s API v Pythonu. Takže to lze
pouštět hacker stylem. V následujícím příkladu přejmenovávám třídu nazvanou
ClassName
v modulu module.py
na NewClassName
. Hezké na Rope je, že, co
jsem zkoušel, zvládne projít codebase a nahradit opravdu všude, kde se
používá. Což například mé oblíbené Komodo IDE nezvládne.
project = rope.base.project.Project('.')
module = project.get_file('module.py')
offset = module.read().index('ClassName')
changes = rope.refactor.rename.Rename(project, module, offset).get_changes('NewClassName')
project.do(changes)
Hezké také na Rope je, že při volání project.history.undo()
vrátí všechny
změny z několika souborů najednou. Více informací na GitHubu
projektu.
Prezentace z přednášky.
Testování
Většinou, když se jde v Pythonu testovat, sáhne se po knihovně unittest
.
Nejsem si jist, zda jsem opravdu neslyšel o knihovně pytest
, nebo zda jsem
zaslechl, ale vůbec jsem se nepodíval a pustil to z hlavy. Každopádně mne její
představení mile překvapilo.
Klasický unittest
řeší testování a nějaký ten setUp
pro přípravu
testovacího prostředí. U větších projektů to nemusí stačit a je potřeba si
fixtures pořešit nějak jinak. V práci jsme si udělali docela dobrý jednoduchý
systém. Píšu docela, protože stále to není ono. Na pytest
u se mi líbí, že
právě tyto problémy má vyřešené, resp. obsahuje hezkou práci s fixtures, a to
hezky.
Napíšete jednoduše test, do parametru přidáte fixture(s), napíšete tyto fixtury, které označíte dekorátorem, a pustíte. Hotovo. Může to vypadat nějak takto:
@pytest.fixture(scope='module', params=['mysql', 'postgresql'])
def db_conn(request):
return create_db_conn(request.params)
@pytest.yield_fixture
def db_table(db_conn):
db_table = db_conn.make_db_table()
yield db_table
db_table.drop
def test_one(db_table):
...
Na této ukázce je hned několik věcí, které se mi líbí:
- Každý test má jen takové fixtury, které potřebuje. U
unittest
u je jedensetUp
pro třídu. Pokud tam budete mít jeden test, který patří do této sady, ale nepotřebuje všechny fixtury, vytváří se některé zbytečně (drahocené milisekundy). - Fixtury mohou na sebe záviset, stejně jako závisí test na fixturu. Není potřeba si dělat vlastní systém, kdy při použití tabulky musím také vytvářet konexi do databáze.
- U fixtury mohu říct její platnost. To je v ukázce u
db_conn
určeno pomocí parametruscope
, čímž říkáme, že chceme konexi sdílet pro module nazvanýmodule
. Konkrétní ukázka je obdobasetUpModule
, ale nemusím v každém modulu tuto funkci definovat – napíšu jednou bokem a použiji, kde potřebuji, jako závislost. - Pro více parametrů se volá test vícekrát. Například v ukázce výše máme jeden test. Zavolá se však dvakrát. Jednou pro databázi MySQL a jednou pro PostgreSQL. Samozřejmě, pokud použiji u jednoho testu více fixtur a každá bude mít různé parametry, vyzkouší se daný test se všemi možnostmi.
- Vytváření a rušení fixtur je hezky v jedné metodě vedle sebe.
Na jednoduché aplikace to nemusí mít moc velký wow efekt, ale co mi řeklo, že to rozhodně musím vyzkoušet na jakémkoliv dalším projektu, je zobrazení selhání:
def test_add():
a = 1
b = 2
expected = 4
> assert add(a, b) + add(b, b) == expected
E assert (3 + 4) == 4
E + where 3 = add(1, 2)
E + and 4 = add(2, 2)
test_pytest_examples.py:12: AssertionError
Normálně byste jen viděli, že 7 != 4. pytest
však udělá menší analýzu kódu a
rozpadne jednotlivé volání v příkazu. Tak můžete rychle najít, kde je problém.
Šikovné. Mimochodem nad testem je také vidět, jaké fixtures byly do testu
posílány.
Jinak vidíte správně – využívá se klasický assert
. Žádné volání různých
metod. Zde vidím jednu nevýhodu a to, že tímto způsobem není možné nahradit
metodu assertAlmostEqual
, musí se ručně psát něco jako assert abs(foo) <
0.0001
. Když si ale vzpomenu, kolikrát jsem tuto metodu využil, chybět mi
nebude.
Prezentace srovnání unittestu a pytestu. Dokumentace k pytestu.
Práce s daty
V poslední době mne zajímá téma machine learning a tak bylo jasné, že na
workshop Practical introduction to machine learning via Kaggle problems musím
zajít. Moc ohledně samotného machine learningu jsme se nedozvěděli. Celé nás
to spíš provázelo problémem „máme nějaká neúplná data a potřebujeme je nějak
transformovat do podoby, abychom mohli předvídat“. I to však přineslo své
ovoce – seznámení s knihovnou pandas
.
V práci děláme na obchodní aplikaci se spoustou statistik a vždy s těmi daty operujeme docela neohrabaně. Resp. nikdy mi nepřišlo, že ten styl je až tak neohrabaný, dokud jsem se neseznámil s pandou. Tato knihovna umí doslova psí kusy. Přesvědčte se sami:
::: python
In [55]: df['one']
Out[55]:
a 1
b 2
c 3
d NaN
Name: one, dtype: float64
In [56]: df['three'] = df['one'] * df['two']
In [57]: df['flag'] = df['one'] > 2
In [58]: df
Out[58]:
one two three flag
a 1 1 1 False
b 2 2 4 False
c 3 3 9 True
d NaN 4 NaN False
Viz dokumentace.
Může se to zdát tak trochu jako ne-Pythonovský přístup, ale líbí se mi. Je dost praktický. Složitá transformace dat lze provést jednoduše, čitelně. Je to další dokumentace, kterou si budu muset projít, abych měl přehled, kdy si budu moct jak zjednodušit práci. Hlavně odstranit zbytečné chyby. Brzy nás čekají velké úpravy statistik, tak se těším na použití. :-)
Dokumentace k pandě.
Requests
Určitě jste už někdy v Pythonu dělali nějaké requesty a určitě jste se trápili
s modulem urllib
. Případně jste už sáhli po lepším balíku requests
, ale
použili jste pouze requests.get('url').content
. Víte však, co všechno tento
balík zvládne a jak je sexy? Pro příště mám jasno, co použiji. Před chvílí
jsem si akorát upravil jedno použití a hned to vypadá lépe.
Na konferenci zaznělo samozřejmě více zajímavých přednášek. Pokud prahnete po dalších informacích, mrkněte na program a dohledejte si prezentace k tomu, co vás zajímá. Všechny přednášky v místnosti HP room byly nahrávány, takže se časem na internet dostanou i záznamy. Případně můžete mrknout na videa z jiných PyCON konferencí, která jsem postoval nedávno.