Flask-Testing-0.7.1/0000755000076500000240000000000013216265617014263 5ustar comostaff00000000000000Flask-Testing-0.7.1/docs/0000755000076500000240000000000013216265617015213 5ustar comostaff00000000000000Flask-Testing-0.7.1/docs/.DS_Store0000644000076500000240000001400412762226522016672 0ustar comostaff00000000000000Bud1 ldbwspblob_buildbwspblobbplist00  ]ShowStatusBar[ShowSidebar[ShowPathbar[ShowToolbar[ShowTabView_ContainerShowSidebar\WindowBounds_PreviewPaneVisibility   _{{335, 331}, {770, 436}}'3?KWn{_buildvSrnlong  @ @ @ @ E DSDB ` @ @ @Flask-Testing-0.7.1/docs/_static/0000755000076500000240000000000013216265617016641 5ustar comostaff00000000000000Flask-Testing-0.7.1/docs/_static/flask-testing.png0000644000076500000240000004734612656551557022150 0ustar comostaff00000000000000PNG  IHDRb5 +vsBIT|d pHYsa(atEXtSoftwarewww.inkscape.org< IDATxu+D  ŋ+)֖m"-NZIwD!?=sfsM`;gfϞ9{~#G9rG@9rȑcCNrȑ#GE B9rȑ9Aȑ#G9r!'9rȑ#G"!G9rQ ȑ#G99rȑ#Gr#G9r(B@s | FX9r1~Ωw@{`K[oY Fȑ#G%s'Ÿ]¾F8$p"}Jv:G9r %f4K"m$`k#|G׀ŀKݽO 9r`f}ÖK9?(s6&"АD f(Я;:نfbfKt~)0fvҸoftrѴ9G1 ==?cE?Ad`$0irQ(['Ǿ8E: uN}pit*G͂_Ah +Pc# ‚aߓE33G̬53'`Ckr`f]CcNbQ9,AǪ&@l`=2!tf #8)"ADĵ{?y!d/<=zGG"[f5OrR' m(l˰}E%C#yHŪșqpulX=nfFMm7!"Co./Y֡͗}n H_9NSr#-B̬ _B 𚻗ܻBNh!IF!@pݞἛCf6Nc@>>7W{wan}M$YqU}㺓#U9~h6w~AI'+af֏9 X @悶S6?.CZoPҽٸG]s@Eچ~f l|!Ϡ=72/Ue{kH"|j*<~N*'օ?یMGD2Mc#2fv+lam)5u [8coѬhR`f]PN{D!݁D$\!i>LFɐ& Bx^AGS5D @qq `} >|ct pW`'DvNסzA 8&ɴi6(Za a™4}J#Diȼ1u[GZ!f@OG#4$PL@̧H ByM(),}uEL3&"Z(k?fd^ŁE7+Z,i`0$a|QNq{mC΍Cϐtrnw;v^ ڡ f4P^DdhZx^+Mpؽ@5)ަ!uLyA^|j+"N{MZ3[WO9EkRu}C&ex8Ų//OV wA/.hE#LCϣv"ZZUЧ%w_/!-F73b#m"w)y#@}| ;qLw:bߎn5VA!Y6-b曃KGwIm>DSмp2G<㡈T=Ԩ8l-wdSC*iԵY1U:_su?qh-o2'"b"u'= L@ ф65ߺyp/Xji)0}>oCs^V̮Eݡ6йV(FS KI{+}yFh7Zt[/mf-ZH_x8?tFL2^쏐V' ^` yCϒG7ȏa~$ f:za@;n3+\w]1+:N׺3Dv*5,u"xi}|̬]"6n VE(.4c֗hfs>W㑴~-3['B&Rc)~(jm8sW`W{h"ԝ 3[-vi ɉ@ BH?  *Hq72,^bkbZ5lWwC,p+p="EWpeр_uWs9I z#O@fm ƫMf&[-vRڨ 4->.]K:)DfvʒR9b Y!ces4>B2DZצ^N#)Dh(w"Kߙ4̌7$.?nC*qHb2 E#p&=F;^Ȉ>E~|@R$=~#8Eq|"/"ߌAFgD>ߥ)~af!JcMrЄpif6IE_7wbJ(< B=G e?Vz/K#o+SL*Ew-s4!44eQZлm1B#|Ty}fG:YGD I罀a9G!_5|p\RhEZ<:`{w?fͬ [`+@c1 ,[ikF)01tВ oy^B_6,8V%ۏN3V( s(R.GI=*H?IJ$#ZxwM cQDAd  UfvPH62,9%͑q7x9GI&ǃ^+Yr5•YrFl) -z-;QȢ5sfEXb r>EA/FB4Aۍhqs)N:سKv 98Iޤp8"U8_mc88|1f/2|E )ę?Bb "9s[&ĪO^ACK>9Łjh# #'U#D-E"냌*^f6,D4םf QWCn^GjՐa '! dO6w !ɝ!h]CQ K#Pf6Ơ2 93ވ6yDĘ[O SÉf6i#nH)W&C;ۚ9<ӑCK>^6Ce! q ?A}"TAZW$V9C}.-#:RɏGm[w.0ʡf6E(aGdi >EZN!ZPfB QĻ7P|!\_ Dzf#߅my1f67(ęfkuIMd9Z$ }4`\(Xr4#M6dam[C~ojj("Т\ ~ q ݐa&J=$~hF']i? CrH+"5ryxYi`7>)GQ!PTǛ;df\rhg? ̘5s8|r̃ffKAo3b#Ɉev  _ `?sb RHXs'i@DC!Tpd9#Q3; =VG!OR(0 3{AȄr ʾΗ(3 oA }CPe伹-^0ɺ$ü#G4R4|9c2Ǒkqԅ Mu 9h^)dXeRtK.jf#|W3 |VD }WWO;$Bˢ C${QB2ߟB@WG~ "BMFv>gR{̖Gcw_s]/"(;j= Z_SJϫv jD .A9eLzQDhw&wOC鎓H¾UAyA(pMD>vBIVCaq,32YlK ^u, $w: F3z#E@|D ḿr9ܼP̬ !Q;aXwP/C`}z ? Ga0ʟ9űu f;%7(CH>I nϻ3Qֵ(*5dV(IN9bf8GqNi( h.j7VDaNEj$Լyg q koU | th>q5U<=0Z3BӑׇֺBzeSuwI""[҈,DU>?RꭟTw7bFF(o@pΟK#-v֡D#Ik|qϠzVk"TP9)6ϴ6MF@,RASDb4enKcQd&(4ocMSM?WE f5Ҹ~n($d=kJ[ mr,ǴO=9! BW}=PsQmU pZ:Cl40KUA+;`+4N@b29/ 2P' %3nfD'f$rě3Hz f*e45DQA&7 0<<|5~uD$h;6尹8\g|X|CKk'h~m\fvUJ~d>>%NTZ]#^!/_kKmZf!p B]~L &ϢP1$I> RȉoM\x2cF6^+0OcΏ fƎ 5|(}fue^$իG )$jƌ.Cyp5weU6أ}&5%}Og2>Ƿ=X^VN[3Z)Мh;X7(K@2>Bm '2k%6IyFw!%< X%qH8_o ەOe)n v'yP`g 2p$n[~\bZ#oCZ(+EF X^݉ (kqtʕH}Z| ZxNxA{4|OSpQh4Fxn8f2,V ?_õ{"b)z 'Jg.b0 |gd~"@&P{zJf| !&?v:T{ (q0!4^`=SIqAcTJKCxd/luO2}m؏>Z=YSo'Zk, ܴ<"+$4RڸiUxIldv5CSf]`D;yf&)$[zJiJ[Rz`w_.͸x?DFIB ͷ3 wifj{"BKl,/G9x0>wŔvڇg2tN|iTN_ֈi Bf ׿J3)uHabH+zюFYUd݀t[}1qua?iߝ4*4 SX ,B I5UflZTFKLRWEsx.-̥uu׿S}%/ql'4CatF{#+<I X%g6C$:BauVܴodS/ض(sG=R$0_DYC~ o#n&qE`kINDxiK "=_9oG1,2GNei yͩ'dY-QI}tIٿYTn]øi Fk%-iZV~;DE&@[F1Wx!)xs4Ѣ;RÿFaX0:|BPm lI("G"&u8b7!bvW]0C,s_p";=?M]$þ%&<ۀC[I4>UfhmZTFK#v&jRLYH*yٯcRSJKjXAW#HթDF0T]o!"HsZ!5)mTPq׻8(oG!qGec@DfCQ),%2=lڱ}"T|)&$W5h܅*8wפ-TEschڰ0C (VOGj#87($q0ɲ/B.E "A#ri96p֮Fd{> {z~D O|skcO _@Z6He_">j ݀ ۟W‘h-~\J_oR;L5{6Z!~\GOSohZ(o3&V*8w?;03t, ":Z)mܑطeH~Lm]+ynsJLI9~L4'_m9K""5bI Y.H*8 E$oJi*6E,$1߂X'mĈG;$@ l]2|U#̗$F#jD3[ F G(x.of!igB*C!}FҒ"T mz!W:3rƱ;nR6yWj+VHGw$3Oف#wLv3h /T(,ؾ#C8̆kNWIvfR Yo$iH=~ Rd#&: z%(p^cKq0iq"E}KTH 0 {h{scTǡy"q֠b1It=r!쟎h "v: ?)Ho#X0B΅qHForvC*}wwGX:}?B5ۅBA[r d"!.w&$ T D,9 BcR-3$5Z|x*YW$OI&^3B<)Floar#Lz*"Ǜ!MOkGs,Ca>i%W0J}L?"l/F]*PO5IdFLi; % mH3;^bqaRXe|-oC$@VH!rN &wd{ C3XS΢? 'o]s$G{,7"jLLB 7D1vG nOyqn`34TR\ 1h(Au,,P0>8! 2ah3>-|FY_^0Oh\C;oIḢ&._d_ rt=:ij7MN|rX+ȀLHKԁ:ZI6Bf۠WEsb Ko'NXU\wLwB%o2_&đ\|kA'Z7/@: _Bҿ!'i%Ov&Y؁q0ڪ8>5h:E)t6%%J?IhT35&h# ( g9* CRȚ8*)uFf/p{Ds`7Q6gӧ‚۰1djxw/ș?Jr ҒFYۛ&*z!cK&{3; @!p+ sP \-4f8Z/CLn- )BX\ɸuQ(҈/Gg#t?N'Tb$*`= cp/Iohw5w, r~jQp sC5,ɬ& x?2}dfVkv#3kcfֱFpOn +nL#ޔfWD?$]Dņ>t;lOtBf(^İE/#uΙhIkOD^G٤> Q  ;[{9X3(-Mc"09D92|.v, b}_g|?(^5mPk4xBDs@RdQi"tE?1Bܤ,ԢA(4]¸|ii&4 $ FΦ/Ȍy>  g<0o>pps PfOZiYՠ=*EH3~82_並ʹ LX9 4šIln#ӱ"WHB%͎Hj> 8AN|Dm1Ar?Pl%Y2QсylI"{Zc)}Eqы,"4=(^v TvDEݧ~L곩f2+Lh/{EڧvSZ#AĽܤGS܂44_/ O9i  -ȴxC: ~e;w*9󐻯lPH'Jm!-T7lEDRDe*%PGx&ZD%36.R_!&< l PPKOATy"IGnf'SHE:B]QTDG$-GgQ,wEq!5[VrS"E 4 wE7 ;>!b;Q(e>@׹̦Rhr3̶7m4@Rh_HPD鱚~H1}z#Mّ*rKsbm~ 欕Px(~'籊!-fvR)ݟt ~WQذ˥i HCH d(,kdi4Зʝ ? PJp:DT Dp͑Fl^R(5lhf=z) U菣Ȇ'#'<3Td|u$$߅!w /Gډ!݇ճvD@!B'!6ut!)N15\ۇ{y%oL lD,"5dTkױG;coTx;Dk7 ehq>-=)WsfKMClfG94!v^}adU)k`E A_ǎ0%x:9w Rכa.io=NpJ>ȉ*5i٢@wג! }|=; ͍B) Ÿ:" @nGf=ANCz?G8=]NBO_hsq숊xi :d "7c\.f9L A8'-""kG)!wFmf[sBFru#fv0X99Ư1 yrw-oDcHJ>oP96C*•AȊW@}2)&=m2𖻿Mw[`: fk!,R%&mRڭ AQ}gֳ,u,)tX᳏p$C~ LqQ <>ƙٮhҌXV@w -hx9\$"5ȩ'D<n {1}"t/>w]G;5x z]ɜ!%Y?A  }-<õ+|_mb-G ߝwc zi7zj~ IYu@N[焐zb?w9ѿHLz rз$b~>Iskvlw%R0-2IWi: ̢:?%FPPtBD&[jh3 T R`USOpsyS)g㠍ݧI^JW12vMiB$`i$aEf=p"Dkwf ?Bn~Dp ZcyK0"޺? Hњyx3*ODg=/ WJzY$QC<#Ԡma{jQr5SjI8Xy!{"lU: TH:qT/Df4\HCsd'(B) B=L c) @駓f+2vu6"!lMi P_-bPk"a6O@Bc5YT *D`y0TD~ fl@ꂒl,HOvr؟鄻I5i:x:s/r`<%ή(d{W8A3z K9ԴGll q EhEHm'!]R#LGi_Se=(gb*Фn8V^ҟRPT5y+D*%ff)FJxEiXU"OsPB,SC+(JP Jmr|>Oy]h<28fmVOI-'iZwCf'=#T4BY{w* p)|aLw(frX SWPkLT2>p+F"^{gO"2A/rT.ժ~ =7H79#2a|}>l1Ckf (.!,nF F&q؍bfYJ:=_GKyUwB:|v9p@ygd#+1{:``W@3W[.+ Y?2 s(~Wu 5T3;s#'e|]JlL +Y4|椙>iF1Of3{#z]r?PAv)+ŏc*Z(EVu)NfU;.6<_#fv7Z!2ߎ}9yB+K}ft8̮BޓIgdKX! $]O (-aJVFD/Sl$)LV"Ǯb`BN/ o"=ǙٛK PtGb}wT2i+WP#Tƕj3AfIҵ<'.5*ԥ!쳯3VM )BkhpZ>IEs-b7*3)efqAP^̠rJP/`f V-w"Ԫ֤7yEY-O@sz7pM\Y1,nhq 9&E |B Cf6Em?`NMPm ff}-" ɳpFPAUтI=)h(m1OJjz$&YEzp ɗ-4h'*b^$h-qW8(]$."nqDTmΫHs Pޏmצ'Y)k}?lYw;( 3[۫ȇ`Jv YЏ-bZQȷ 0KR ʈdov ucw5l~(B!MRvjh/}Jb*ڿw{%1SrOڋ.j1$ccjaYwIJYpڴ6nm&MBViѹz!B~9> 4# <^Dc8E؃ j Ur@DOC JOc!-`YSaW42g`>9ѓ&{$"? eP5 IpNt^*Jt6&haoƷЄK D8*?np_Wu Y>mÀ!MP~ao6~Z6x'ۍn2}M mN,LyS.RF_SkSع{kXok5i2WmBr}DrL3etc d|a5K t͋"gbǬrHJTa>!Z83 *XĹ=NֈSKn,  %i'!ccДGk 6z gE&'ѨS4yn;w0`s vӜRdq㯉BȁWp$rPt3 tI|BG׌kPh; E䇖6i]'e;U߬ݻ+xy{8ZGC`hܙU>6hq)u/ѻٺ6;#Kg4;Uh|7Cb5s1Z=3ͫм%M=Zp&Bsm6!B) uR[=^z~oR=> lh]X $/qn7`bJ#asw?!߆ߔs󷑳}(oM|挣A)qtSQxd|`z3&w--NFk8vgb9 0.FŝB HPn 6]y 0@cGÏ'\>~$sTD4)mUX&"t*"NI!uVxķWD.BUFSZ`m? _G:as⹷CU׷h?n88J۞4}il=BbA#86X> S58HS5"E w2?Ǭ2 "tS>i2 mnڈtHާUx{g|/CG}(T%%}2ނ x-q|g໔C jM!Eň]"6@>8EJ!-ѵ\1Y}f޲KIDAT'zߠ$=Ar ?rUL#: (eNaDvv׮༬p_&;Gƨȏ腺G etXalڧaH $HvTԫ!u\ch Rי_\gF4,FY,FE2}:#2_pݏHJ:ɮd[c9h$1Oiq}2"]%%ZP(tcN =ZDg µHڵpܖh!K}lʊTh͙/ʵiݎj}jW,!}]QZC遪EZ"! {H jCƍm^oCH]e5}:6b /DSC ?H,VR͎/|~䅨#i2pG DYvuHԣVpmbVI{c|J;HgI{*eDhĽ&U>8VToci{smmⱽZ. eQHU@TxX7ʚLsi'hk½eƑl"ٙL$< {u+93lL c>-&\^]]@>VRH}|~c}c".0!m@2<}9!mD ?GHzմ?M|wҏNv|⻇!Hz V@inŏ[Z37zQ/(C[$INJXgoCjĞ*s'kD!dw/%K4Jh Mw{f#Sջ?" KW+Sлma{9V3[-^ݑvdzcG˝\o"X??p[>G]w; ۛ~~c/sȟeWFa,nU^;ix{CBlWPGkvE$l5(r.E)4' 3{i؆{VB`fCY 4p|ߑ^AFSeߵPӃ m,J>0B77R' F֊h@ $ ]87';@!?Qj?&Ow62%<.~r3E3א $yƹ!L2r0t*s!IN;`tKΦz. a?'ƣye+^cZWAmw4NBXo:EkEHjwCyqֱnֽZAs{(bLmtAjU$X\M_Ü>2mE@[5ʨ6N<4F#WNA u,AǑ$͛r$.@!LT9-+mGpbBYV! b#5q_Hm?s,D)DG\-ooo-!gȄqWS-" uFE.%F Rm` :HbXOE9(X!~Ju6U7i D%YaR D6XxV!>z̷|˷|˷ِHkg$tg"M (dC&j]kJeRNz-D=U5XAs}),768"3>yFeAvߡPx=JDB̈{2^T9rȑc.2ӑViD^ .Hwa3|RP;5u8DЋ?G b:?F$i";c)8= -տMG%StC'DBdd\-8 8%Z{fooyi/l_2Ti֫Bu9&ᠪZ#GTD :Z0>(Ѧ!~D7‚<1Isߝ{&} 3˖ểVdBpoط0^oo9x+7m¾` BuO3[ K\ WGmQXM2=,aB߽M!`r G( iۗHS| 9<=蜰 dIZtWBZz[[[na87okgL(*#○AX(f+J'ԨH_BJ$E&(N-8R_GΎՌ}^ 8K2!ݍVȑ#/ SKve1T&X32בZ1JdyrX.<#,RDw^y;CdV¤TOi8̢Џ#!~db9J:𙇸X/#G9rG4!ED&(X!2a!?#>1ѱ9̺xHaifm}VS=lI9rȑ3[ ՌX*@zcmgV#G9r0]}^yfv60O{ J ȑ#G92j uuD9rȑ0E%q:_,Jy5pP471ȑ#GM*=el74[w^RO ڄqkrȑ#G&..73afs 3;9o|BbZ9rȑiq Jxl|?j(1 T6Th:Jxb8 w. B9r|0P($vwހQb{ K5*P"Ϝ ȑ#G͋y3Th330!MF eQAOk}T1'9rȑ#G!B| G&tdn 4uUWFHOIENDB`Flask-Testing-0.7.1/docs/_themes/0000755000076500000240000000000013216265617016637 5ustar comostaff00000000000000Flask-Testing-0.7.1/docs/_themes/flask/0000755000076500000240000000000013216265617017737 5ustar comostaff00000000000000Flask-Testing-0.7.1/docs/_themes/flask/static/0000755000076500000240000000000013216265617021226 5ustar comostaff00000000000000Flask-Testing-0.7.1/docs/_themes/flask/static/flasky.css_t0000644000076500000240000001245312656551557023571 0ustar comostaff00000000000000/* * flasky.css_t * ~~~~~~~~~~~~ * * Sphinx stylesheet -- flasky theme based on nature theme. * * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: 'Georgia', serif; font-size: 17px; background-color: #ddd; color: #000; margin: 0; padding: 0; } div.document { background: #fafafa; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 0 0 230px; } hr { border: 1px solid #B1B4B6; } div.body { background-color: #ffffff; color: #3E4349; padding: 0 30px 30px 30px; min-height: 34em; } img.floatingflask { padding: 0 0 10px 10px; float: right; } div.footer { position: absolute; right: 0; margin-top: -70px; text-align: right; color: #888; padding: 10px; font-size: 14px; } div.footer a { color: #888; text-decoration: underline; } div.related { line-height: 32px; color: #888; } div.related ul { padding: 0 0 0 10px; } div.related a { color: #444; } div.sphinxsidebar { font-size: 14px; line-height: 1.5; } div.sphinxsidebarwrapper { padding: 0 20px; } div.sphinxsidebarwrapper p.logo { padding: 20px 0 10px 0; margin: 0; text-align: center; } div.sphinxsidebar h3, div.sphinxsidebar h4 { font-family: 'Garamond', 'Georgia', serif; color: #222; font-size: 24px; font-weight: normal; margin: 20px 0 5px 0; padding: 0; } div.sphinxsidebar h4 { font-size: 20px; } div.sphinxsidebar h3 a { color: #444; } div.sphinxsidebar p { color: #555; margin: 10px 0; } div.sphinxsidebar ul { margin: 10px 0; padding: 0; color: #000; } div.sphinxsidebar a { color: #444; text-decoration: none; } div.sphinxsidebar a:hover { text-decoration: underline; } div.sphinxsidebar input { border: 1px solid #ccc; font-family: 'Georgia', serif; font-size: 1em; } /* -- body styles ----------------------------------------------------------- */ a { color: #004B6B; text-decoration: underline; } a:hover { color: #6D4100; text-decoration: underline; } div.body { padding-bottom: 40px; /* saved for footer */ } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; margin: 30px 0px 10px 0px; padding: 0; } div.body h1 { margin-top: 0; padding-top: 20px; font-size: 240%; } div.body h2 { font-size: 180%; } div.body h3 { font-size: 150%; } div.body h4 { font-size: 130%; } div.body h5 { font-size: 100%; } div.body h6 { font-size: 100%; } a.headerlink { color: white; padding: 0 4px; text-decoration: none; } a.headerlink:hover { color: #444; background: #eaeaea; } div.body p, div.body dd, div.body li { line-height: 1.4em; } div.admonition { background: #fafafa; margin: 20px -30px; padding: 10px 30px; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; } div.admonition p.admonition-title { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; font-size: 24px; margin: 0 0 10px 0; padding: 0; line-height: 1; } div.admonition p.last { margin-bottom: 0; } div.highlight{ background-color: white; } dt:target, .highlight { background: #FAF3E8; } div.note { background-color: #eee; border: 1px solid #ccc; } div.seealso { background-color: #ffc; border: 1px solid #ff6; } div.topic { background-color: #eee; } div.warning { background-color: #ffe4e4; border: 1px solid #f66; } p.admonition-title { display: inline; } p.admonition-title:after { content: ":"; } pre, tt { font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.9em; } img.screenshot { } tt.descname, tt.descclassname { font-size: 0.95em; } tt.descname { padding-right: 0.08em; } img.screenshot { -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils { border: 1px solid #888; -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils td, table.docutils th { border: 1px solid #888; padding: 0.25em 0.7em; } table.field-list, table.footnote { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } table.footnote { margin: 15px 0; width: 100%; border: 1px solid #eee; } table.field-list th { padding: 0 0.8em 0 0; } table.field-list td { padding: 0; } table.footnote td { padding: 0.5em; } dl { margin: 0; padding: 0; } dl dd { margin-left: 30px; } pre { background: #eee; padding: 7px 30px; margin: 15px -30px; line-height: 1.3em; } dl pre { margin-left: -60px; padding-left: 60px; } dl dl pre { margin-left: -90px; padding-left: 90px; } tt { background-color: #ecf0f3; color: #222; /* padding: 1px 2px; */ } tt.xref, a tt { background-color: #FBFBFB; text-decoration: none!important; } a:hover tt { background: #EEE; } Flask-Testing-0.7.1/docs/_themes/flask/theme.conf0000644000076500000240000000014112656551557021714 0ustar comostaff00000000000000[theme] inherit = basic stylesheet = flasky.css pygments_style = flask_theme_support.FlaskyStyle Flask-Testing-0.7.1/docs/_themes/flask_small/0000755000076500000240000000000013216265617021127 5ustar comostaff00000000000000Flask-Testing-0.7.1/docs/_themes/flask_small/layout.html0000644000076500000240000000125312656551557023343 0ustar comostaff00000000000000{% extends "basic/layout.html" %} {% block header %} {{ super() }} {% if pagename == 'index' %}
{% endif %} {% endblock %} {% block footer %} {% if pagename == 'index' %}
{% endif %} {% endblock %} {# do not display relbars #} {% block relbar1 %}{% endblock %} {% block relbar2 %} {% if theme_github_fork %} Fork me on GitHub {% endif %} {% endblock %} {% block sidebar1 %}{% endblock %} {% block sidebar2 %}{% endblock %} Flask-Testing-0.7.1/docs/_themes/flask_small/static/0000755000076500000240000000000013216265617022416 5ustar comostaff00000000000000Flask-Testing-0.7.1/docs/_themes/flask_small/static/flasky.css_t0000644000076500000240000001100112656551557024745 0ustar comostaff00000000000000/* * flasky.css_t * ~~~~~~~~~~~~ * * Sphinx stylesheet -- flasky theme based on nature theme. * * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: 'Georgia', serif; font-size: 17px; color: #000; background: white; margin: 0; padding: 0; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 40px auto 0 auto; width: 700px; } hr { border: 1px solid #B1B4B6; } div.body { background-color: #ffffff; color: #3E4349; padding: 0 30px 30px 30px; } img.floatingflask { padding: 0 0 10px 10px; float: right; } div.footer { text-align: right; color: #888; padding: 10px; font-size: 14px; width: 650px; margin: 0 auto 40px auto; } div.footer a { color: #888; text-decoration: underline; } div.related { line-height: 32px; color: #888; } div.related ul { padding: 0 0 0 10px; } div.related a { color: #444; } /* -- body styles ----------------------------------------------------------- */ a { color: #004B6B; text-decoration: underline; } a:hover { color: #6D4100; text-decoration: underline; } div.body { padding-bottom: 40px; /* saved for footer */ } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; margin: 30px 0px 10px 0px; padding: 0; } {% if theme_index_logo %} div.indexwrapper h1 { text-indent: -999999px; background: url({{ theme_index_logo }}) no-repeat center center; height: {{ theme_index_logo_height }}; } {% endif %} div.body h2 { font-size: 180%; } div.body h3 { font-size: 150%; } div.body h4 { font-size: 130%; } div.body h5 { font-size: 100%; } div.body h6 { font-size: 100%; } a.headerlink { color: white; padding: 0 4px; text-decoration: none; } a.headerlink:hover { color: #444; background: #eaeaea; } div.body p, div.body dd, div.body li { line-height: 1.4em; } div.admonition { background: #fafafa; margin: 20px -30px; padding: 10px 30px; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; } div.admonition p.admonition-title { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; font-size: 24px; margin: 0 0 10px 0; padding: 0; line-height: 1; } div.admonition p.last { margin-bottom: 0; } div.highlight{ background-color: white; } dt:target, .highlight { background: #FAF3E8; } div.note { background-color: #eee; border: 1px solid #ccc; } div.seealso { background-color: #ffc; border: 1px solid #ff6; } div.topic { background-color: #eee; } div.warning { background-color: #ffe4e4; border: 1px solid #f66; } p.admonition-title { display: inline; } p.admonition-title:after { content: ":"; } pre, tt { font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.85em; } img.screenshot { } tt.descname, tt.descclassname { font-size: 0.95em; } tt.descname { padding-right: 0.08em; } img.screenshot { -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils { border: 1px solid #888; -moz-box-shadow: 2px 2px 4px #eee; -webkit-box-shadow: 2px 2px 4px #eee; box-shadow: 2px 2px 4px #eee; } table.docutils td, table.docutils th { border: 1px solid #888; padding: 0.25em 0.7em; } table.field-list, table.footnote { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } table.footnote { margin: 15px 0; width: 100%; border: 1px solid #eee; } table.field-list th { padding: 0 0.8em 0 0; } table.field-list td { padding: 0; } table.footnote td { padding: 0.5em; } dl { margin: 0; padding: 0; } dl dd { margin-left: 30px; } pre { padding: 0; margin: 15px -30px; padding: 8px; line-height: 1.3em; padding: 7px 30px; background: #eee; border-radius: 2px; -moz-border-radius: 2px; -webkit-border-radius: 2px; } dl pre { margin-left: -60px; padding-left: 60px; } tt { background-color: #ecf0f3; color: #222; /* padding: 1px 2px; */ } tt.xref, a tt { background-color: #FBFBFB; } a:hover tt { background: #EEE; } Flask-Testing-0.7.1/docs/_themes/flask_small/theme.conf0000644000076500000240000000027012656551557023107 0ustar comostaff00000000000000[theme] inherit = basic stylesheet = flasky.css nosidebar = true pygments_style = flask_theme_support.FlaskyStyle [options] index_logo = '' index_logo_height = 120px github_fork = '' Flask-Testing-0.7.1/docs/_themes/flask_theme_support.py0000644000076500000240000001141312656551557023277 0ustar comostaff00000000000000# flasky extensions. flasky pygments style based on tango style from pygments.style import Style from pygments.token import Keyword, Name, Comment, String, Error, \ Number, Operator, Generic, Whitespace, Punctuation, Other, Literal class FlaskyStyle(Style): background_color = "#f8f8f8" default_style = "" styles = { # No corresponding class for the following: #Text: "", # class: '' Whitespace: "underline #f8f8f8", # class: 'w' Error: "#a40000 border:#ef2929", # class: 'err' Other: "#000000", # class 'x' Comment: "italic #8f5902", # class: 'c' Comment.Preproc: "noitalic", # class: 'cp' Keyword: "bold #004461", # class: 'k' Keyword.Constant: "bold #004461", # class: 'kc' Keyword.Declaration: "bold #004461", # class: 'kd' Keyword.Namespace: "bold #004461", # class: 'kn' Keyword.Pseudo: "bold #004461", # class: 'kp' Keyword.Reserved: "bold #004461", # class: 'kr' Keyword.Type: "bold #004461", # class: 'kt' Operator: "#582800", # class: 'o' Operator.Word: "bold #004461", # class: 'ow' - like keywords Punctuation: "bold #000000", # class: 'p' # because special names such as Name.Class, Name.Function, etc. # are not recognized as such later in the parsing, we choose them # to look the same as ordinary variables. Name: "#000000", # class: 'n' Name.Attribute: "#c4a000", # class: 'na' - to be revised Name.Builtin: "#004461", # class: 'nb' Name.Builtin.Pseudo: "#3465a4", # class: 'bp' Name.Class: "#000000", # class: 'nc' - to be revised Name.Constant: "#000000", # class: 'no' - to be revised Name.Decorator: "#888", # class: 'nd' - to be revised Name.Entity: "#ce5c00", # class: 'ni' Name.Exception: "bold #cc0000", # class: 'ne' Name.Function: "#000000", # class: 'nf' Name.Property: "#000000", # class: 'py' Name.Label: "#f57900", # class: 'nl' Name.Namespace: "#000000", # class: 'nn' - to be revised Name.Other: "#000000", # class: 'nx' Name.Tag: "bold #004461", # class: 'nt' - like a keyword Name.Variable: "#000000", # class: 'nv' - to be revised Name.Variable.Class: "#000000", # class: 'vc' - to be revised Name.Variable.Global: "#000000", # class: 'vg' - to be revised Name.Variable.Instance: "#000000", # class: 'vi' - to be revised Number: "#990000", # class: 'm' Literal: "#000000", # class: 'l' Literal.Date: "#000000", # class: 'ld' String: "#4e9a06", # class: 's' String.Backtick: "#4e9a06", # class: 'sb' String.Char: "#4e9a06", # class: 'sc' String.Doc: "italic #8f5902", # class: 'sd' - like a comment String.Double: "#4e9a06", # class: 's2' String.Escape: "#4e9a06", # class: 'se' String.Heredoc: "#4e9a06", # class: 'sh' String.Interpol: "#4e9a06", # class: 'si' String.Other: "#4e9a06", # class: 'sx' String.Regex: "#4e9a06", # class: 'sr' String.Single: "#4e9a06", # class: 's1' String.Symbol: "#4e9a06", # class: 'ss' Generic: "#000000", # class: 'g' Generic.Deleted: "#a40000", # class: 'gd' Generic.Emph: "italic #000000", # class: 'ge' Generic.Error: "#ef2929", # class: 'gr' Generic.Heading: "bold #000080", # class: 'gh' Generic.Inserted: "#00A000", # class: 'gi' Generic.Output: "#888", # class: 'go' Generic.Prompt: "#745334", # class: 'gp' Generic.Strong: "bold #000000", # class: 'gs' Generic.Subheading: "bold #800080", # class: 'gu' Generic.Traceback: "bold #a40000", # class: 'gt' } Flask-Testing-0.7.1/docs/_themes/README0000644000076500000240000000210512656551557017525 0ustar comostaff00000000000000Flask Sphinx Styles =================== This repository contains sphinx styles for Flask and Flask related projects. To use this style in your Sphinx documentation, follow this guide: 1. put this folder as _themes into your docs folder. Alternatively you can also use git submodules to check out the contents there. 2. add this to your conf.py: sys.path.append(os.path.abspath('_themes')) html_theme_path = ['_themes'] html_theme = 'flask' The following themes exist: - 'flask' - the standard flask documentation theme for large projects - 'flask_small' - small one-page theme. Intended to be used by very small addon libraries for flask. The following options exist for the flask_small theme: [options] index_logo = '' filename of a picture in _static to be used as replacement for the h1 in the index.rst file. index_logo_height = 120px height of the index logo github_fork = '' repository name on github for the "fork me" badge Flask-Testing-0.7.1/docs/conf.py0000644000076500000240000001615112656551557016526 0ustar comostaff00000000000000# -*- coding: utf-8 -*- # # flask-testing documentation build configuration file, created by # sphinx-quickstart on Wed Jun 23 08:26:41 2010. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert( 0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) sys.path.append(os.path.abspath('_themes')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Flask-Testing' copyright = u'2010, Dan Jacob' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '0.3' # The full version, including alpha/beta/rc tags. release = '0.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. #pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'flask_small' html_theme_options = { 'index_logo': 'flask-testing.png', 'github_fork': 'jarus/flask-testing' } # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. html_theme_path = ['_themes'] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'flask-testingdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'flask-testing.tex', u'Flask-Testing Documentation', u'Dan Jacob', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'flask-testing', u'Flask-Testing Documentation', [u'Dan Jacob'], 1) ] Flask-Testing-0.7.1/docs/index.rst0000644000076500000240000002557213216265577017074 0ustar comostaff00000000000000Flask-Testing ************* .. module:: flask_testing The **Flask-Testing** extension provides unit testing utilities for Flask. Installing Flask-Testing ======================== Install with **pip** and **easy_install**:: pip install Flask-Testing or download the latest version from version control:: git clone https://github.com/jarus/flask-testing.git cd flask-testing python setup.py develop If you are using **virtualenv**, it is assumed that you are installing **Flask-Testing** in the same virtualenv as your Flask application(s). Writing tests ============= Simply subclass the ``TestCase`` class:: from flask_testing import TestCase class MyTest(TestCase): pass You must specify the ``create_app`` method, which should return a Flask instance:: from flask import Flask from flask_testing import TestCase class MyTest(TestCase): def create_app(self): app = Flask(__name__) app.config['TESTING'] = True return app If you don't define ``create_app`` a ``NotImplementedError`` will be raised. Testing with LiveServer ----------------------- If you want your tests done via Selenium or other headless browser like PhantomJS you can use the LiveServerTestCase:: import urllib2 from flask import Flask from flask_testing import LiveServerTestCase class MyTest(LiveServerTestCase): def create_app(self): app = Flask(__name__) app.config['TESTING'] = True # Default port is 5000 app.config['LIVESERVER_PORT'] = 8943 # Default timeout is 5 seconds app.config['LIVESERVER_TIMEOUT'] = 10 return app def test_server_is_up_and_running(self): response = urllib2.urlopen(self.get_server_url()) self.assertEqual(response.code, 200) The method ``get_server_url`` will return http://localhost:8943 in this case. Dynamic LiveServerTestCase port ------------------------------- By default, ``LiveServerTestCase`` will use the pre-defined port for running the live server. If multiple tests need to run in parallel, the ``LIVESERVER_PORT`` can be set to ``0`` to have the underlying operating system pick an open port for the server. The full address of the running server can be accessed via the ``get_server_url`` call on the test case:: import urllib2 from flask import Flask from flask_testing import LiveServerTestCase class MyTest(LiveServerTestCase): def create_app(self): app = Flask(__name__) app.config['TESTING'] = True # Set to 0 to have the OS pick the port. app.config['LIVESERVER_PORT'] = 0 return app def test_server_is_up_and_running(self): response = urllib2.urlopen(self.get_server_url()) self.assertEqual(response.code, 200) Testing JSON responses ---------------------- If you are testing a view that returns a JSON response, you can test the output using a special ``json`` attribute appended to the ``Response`` object:: @app.route("/ajax/") def some_json(): return jsonify(success=True) class TestViews(TestCase): def test_some_json(self): response = self.client.get("/ajax/") self.assertEquals(response.json, dict(success=True)) Opt to not render the templates ------------------------------- When testing with mocks the template rendering can be a problem. If you don't want to render the templates in the tests you can use the ``render_templates`` attribute:: class TestNotRenderTemplates(TestCase): render_templates = False def test_assert_not_process_the_template(self): response = self.client.get("/template/") assert "" == response.data The signal will be sent anyway so that you can check if the template was rendered using the ``assert_template_used`` method:: class TestNotRenderTemplates(TestCase): render_templates = False def test_assert_mytemplate_used(self): response = self.client.get("/template/") self.assert_template_used('mytemplate.html') When the template rendering is turned off the tests will also run faster and the view logic can be tested in isolation. Using with Twill ---------------- `Twill`_ is a simple language for browsing the Web through a command line interface. .. note:: Please note that Twill only supports Python 2.x and therefore cannot be used with Python 3 or above. ``Flask-Testing`` comes with a helper class for creating functional tests using Twill:: def test_something_with_twill(self): with Twill(self.app, port=3000) as t: t.browser.go(t.url("/")) The older ``TwillTestCase`` has been deprecated. Testing with SQLAlchemy ----------------------- This covers a couple of points if you are using **Flask-Testing** with `SQLAlchemy`_. It is assumed that you are using the `Flask-SQLAlchemy`_ extension, but if not the examples should not be too difficult to adapt to your own particular setup. First, ensure you set the database URI to something other than your production database ! Second, it's usually a good idea to create and drop your tables with each test run, to ensure clean tests:: from flask_testing import TestCase from myapp import create_app, db class MyTest(TestCase): SQLALCHEMY_DATABASE_URI = "sqlite://" TESTING = True def create_app(self): # pass in test configuration return create_app(self) def setUp(self): db.create_all() def tearDown(self): db.session.remove() db.drop_all() Notice also that ``db.session.remove()`` is called at the end of each test, to ensure the SQLAlchemy session is properly removed and that a new session is started with each test run - this is a common "gotcha". Another gotcha is that Flask-SQLAlchemy **also** removes the session instance at the end of every request (as should any thread safe application using SQLAlchemy with **scoped_session**). Therefore the session is cleared along with any objects added to it every time you call ``client.get()`` or another client method. For example:: class SomeTest(MyTest): def test_something(self): user = User() db.session.add(user) db.session.commit() # this works assert user in db.session response = self.client.get("/") # this raises an AssertionError assert user in db.session You now have to re-add the "user" instance back to the session with ``db.session.add(user)``, if you are going to make any further database operations on it. Also notice that for this example the SQLite in-memory database is used : while it is faster for tests, if you have database-specific code (e.g. for MySQL or PostgreSQL) it may not be applicable. You may also want to add a set of instances for your database inside of a ``setUp()`` once your database tables have been created. If you want to work with larger sets of data, look at `Fixture`_ which includes support for SQLAlchemy. Running tests ============= with unittest ------------- I recommend you to put all your tests into one file so that you can use the :func:`unittest.main` function. This function will discover all your test methods in your :class:`TestCase` classes. Remember, the names of the test methods and classes must start with ``test`` (case-insensitive) so that they can be discovered. An example test file could look like this:: import unittest import flask_testing # your test cases if __name__ == '__main__': unittest.main() Now you can run your tests with ``python tests.py``. with nose --------- The `nose`_ collector and test runner works also fine with Flask-Testing. Changes ======= 0.7.1 (19.12.2017) ------------------ * Reverts the request context changes from ``0.7.0``. This change broke backwards compatibility so it will be moved to a major version release instead. 0.7.0 (18.12.2017) ------------------ * Changes the way request contexts are managed. Let's Flask be responsible for the context, which fixes some subtle bugs. 0.6.2 (26.02.2017) ------------------ * Add support for OS chosen port in ``LiveServerTestCase`` * Better error messages when missing required modules * ``assertRedirects`` now supports all valid redirect codes as specified in the HTTP protocol * Fixed bug that caused ``TypeError`` instead of ``AssertionError`` when testing against used templates * Fixed bug in ``assertRedirects`` where the location was not being checked properly 0.6.1 (03.09.2016) ------------------ * Fix issues that prevented tests from running when blinker was not installed 0.6.0 (02.09.2016) ------------------ * ``LiveServerTestCase`` will now start running as soon as the server is up * ``assertRedirects`` now respects the ``SERVER_NAME`` config value and can compare against absolute URLs * Compatibility with Flask 0.11.1 0.5.0 (12.06.2016) ------------------ * Improvements to ``LiveServerTestCase`` * The test case will now block until the server is available * Fixed an issue where no request context was available * Fixed an issue where tests would be run twice when ``DEBUG`` was set to True * Add missing message arguments for assertRedirects and assertContext * Better default failure message for assertRedirects * Better default failure message for assertTemplateUsed * Fix an issue that caused the ``render_templates`` option to not clean up after itself if set to False * Update docs to use new Flask extension import specification 0.4.2 (24.07.2014) ------------------ * Improved teardown to be more graceful. * Add ``message`` argument to ``assertStatus`` respectively all assertion methods with fixed status like ``assert404``. 0.4.1 (27.02.2014) ------------------ This release is dedicated to every contributer who made this release possible. Thank you very much. * Python 3 compatibility (without twill) * Add ``LiveServerTestCase`` * Use unittest2 backports if available in python 2.6 * Install multiprocessing for python versions earlier than 2.6 0.4 (06.07.2012) ---------------- * Use of the new introduced import way for flask extensions. Use ``import flask.ext.testing`` instead of ``import flaskext.testing``. * Replace all ``assert`` with ``self.assert*`` methods for better output with unittest. * Improved Python 2.5 support. * Use Flask's preferred JSON module. API === .. module:: flask_testing .. autoclass:: TestCase :members: .. autoclass:: Twill :members: .. autoclass:: TwillTestCase :members: .. _Flask: http://flask.pocoo.org .. _Twill: http://twill.idyll.org/ .. _Fixture: http://farmdev.com/projects/fixture/index.html .. _SQLAlchemy: http://sqlalchemy.org .. _Flask-SQLAlchemy: http://packages.python.org/Flask-SQLAlchemy/ .. _nose: http://nose.readthedocs.org/en/latest/ Flask-Testing-0.7.1/docs/make.bat0000644000076500000240000001003212656551557016624 0ustar comostaff00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\flask-unittest.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\flask-unittest.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end Flask-Testing-0.7.1/docs/Makefile0000644000076500000240000001101612656551557016662 0ustar comostaff00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/flask-unittest.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/flask-unittest.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/flask-unittest" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/flask-unittest" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." Flask-Testing-0.7.1/flask_testing/0000755000076500000240000000000013216265617017120 5ustar comostaff00000000000000Flask-Testing-0.7.1/flask_testing/__init__.py0000644000076500000240000000124112656551557021237 0ustar comostaff00000000000000# -*- coding: utf-8 -*- """ flask_testing ~~~~~~~~~~~~~ Flask unittest integration. :copyright: (c) 2010 by Dan Jacob. :license: BSD, see LICENSE for more details. """ from __future__ import absolute_import from .utils import TestCase, LiveServerTestCase try: import twill from .twill import Twill, TwillTestCase is_twill_available = True except ImportError: is_twill_available = False class Error(): def __init__(self, *args, **kwargs): msg = "'twill' package is required for %s" % ( self.__class__.__name__) raise ImportError(msg) Twill = Error TwillTestCase = Error Flask-Testing-0.7.1/flask_testing/twill.py0000644000076500000240000000535312656551557020643 0ustar comostaff00000000000000# -*- coding: utf-8 -*- """ flask_testing.twill ~~~~~~~~~~~~~~~~~~~ Flask unittest integration. :copyright: (c) 2010 by Dan Jacob. :license: BSD, see LICENSE for more details. """ from __future__ import absolute_import import StringIO import twill from .utils import TestCase class Twill(object): """ :versionadded: 0.3 Twill wrapper utility class. Creates a Twill ``browser`` instance and handles WSGI intercept. Usage:: t = Twill(self.app) with t: t.browser.go("/") t.url("/") """ def __init__(self, app, host='127.0.0.1', port=5000, scheme='http'): self.app = app self.host = host self.port = port self.scheme = scheme self.browser = twill.get_browser() def __enter__(self): twill.set_output(StringIO.StringIO()) twill.commands.clear_cookies() twill.add_wsgi_intercept(self.host, self.port, lambda: self.app) return self def __exit__(self, exc_type, exc_value, tb): twill.remove_wsgi_intercept(self.host, self.port) twill.commands.reset_output() def url(self, url): """ Makes complete URL based on host, port and scheme Twill settings. :param url: relative URL """ return "%s://%s:%d%s" % (self.scheme, self.host, self.port, url) class TwillTestCase(TestCase): """ :deprecated: use Twill helper class instead. Creates a Twill ``browser`` instance and handles WSGI intercept. """ twill_host = "127.0.0.1" twill_port = 5000 twill_scheme = "http" def _pre_setup(self): super(TwillTestCase, self)._pre_setup() twill.set_output(StringIO.StringIO()) twill.commands.clear_cookies() twill.add_wsgi_intercept(self.twill_host, self.twill_port, lambda: self.app) self.browser = twill.get_browser() def _post_teardown(self): twill.remove_wsgi_intercept(self.twill_host, self.twill_port) twill.commands.reset_output() super(TwillTestCase, self)._post_teardown() def make_twill_url(self, url): """ Makes complete URL based on host, port and scheme Twill settings. :param url: relative URL """ return "%s://%s:%d%s" % (self.twill_scheme, self.twill_host, self.twill_port, url) Flask-Testing-0.7.1/flask_testing/utils.py0000644000076500000240000004011613216265572020634 0ustar comostaff00000000000000# -*- coding: utf-8 -*- """ flask_testing.utils ~~~~~~~~~~~~~~~~~~~ Flask unittest integration. :copyright: (c) 2010 by Dan Jacob. :license: BSD, see LICENSE for more details. """ from __future__ import absolute_import, with_statement import gc import multiprocessing import socket import time try: import socketserver except ImportError: # Python 2 SocketServer fallback import SocketServer as socketserver try: import unittest2 as unittest except ImportError: import unittest try: from urllib.parse import urlparse, urljoin except ImportError: # Python 2 urlparse fallback from urlparse import urlparse, urljoin from werkzeug import cached_property # Use Flask's preferred JSON module so that our runtime behavior matches. from flask import json_available, templating, template_rendered try: from flask import message_flashed _is_message_flashed = True except ImportError: message_flashed = None _is_message_flashed = False if json_available: from flask import json # we'll use signals for template-related tests if # available in this version of Flask try: import blinker _is_signals = True except ImportError: # pragma: no cover _is_signals = False __all__ = ["TestCase"] class ContextVariableDoesNotExist(Exception): pass class JsonResponseMixin(object): """ Mixin with testing helper methods """ @cached_property def json(self): if not json_available: # pragma: no cover raise NotImplementedError return json.loads(self.data) def _make_test_response(response_class): class TestResponse(response_class, JsonResponseMixin): pass return TestResponse def _empty_render(template, context, app): """ Used to monkey patch the render_template flask method when the render_templates property is set to False in the TestCase """ if _is_signals: template_rendered.send(app, template=template, context=context) return "" def _check_for_message_flashed_support(): if not _is_signals or not _is_message_flashed: raise RuntimeError( "Your version of Flask doesn't support message_flashed. " "This requires Flask 0.10+ with the blinker module installed." ) def _check_for_signals_support(): if not _is_signals: raise RuntimeError( "Your version of Flask doesn't support signals. " "This requires Flask 0.6+ with the blinker module installed." ) class TestCase(unittest.TestCase): render_templates = True run_gc_after_test = False def create_app(self): """ Create your Flask app here, with any configuration you need. """ raise NotImplementedError def __call__(self, result=None): """ Does the required setup, doing it here means you don't have to call super.setUp in subclasses. """ try: self._pre_setup() super(TestCase, self).__call__(result) finally: self._post_teardown() def debug(self): try: self._pre_setup() super(TestCase, self).debug() finally: self._post_teardown() def _pre_setup(self): self.app = self.create_app() self._orig_response_class = self.app.response_class self.app.response_class = _make_test_response(self.app.response_class) self.client = self.app.test_client() self._ctx = self.app.test_request_context() self._ctx.push() if not self.render_templates: # Monkey patch the original template render with a empty render self._original_template_render = templating._render templating._render = _empty_render self.templates = [] self.flashed_messages = [] if _is_signals: template_rendered.connect(self._add_template) if _is_message_flashed: message_flashed.connect(self._add_flash_message) def _add_flash_message(self, app, message, category): self.flashed_messages.append((message, category)) def _add_template(self, app, template, context): if len(self.templates) > 0: self.templates = [] self.templates.append((template, context)) def _post_teardown(self): if getattr(self, '_ctx', None) is not None: self._ctx.pop() del self._ctx if getattr(self, 'app', None) is not None: if getattr(self, '_orig_response_class', None) is not None: self.app.response_class = self._orig_response_class del self.app if hasattr(self, 'client'): del self.client if hasattr(self, 'templates'): del self.templates if hasattr(self, 'flashed_messages'): del self.flashed_messages if _is_signals: template_rendered.disconnect(self._add_template) if _is_message_flashed: message_flashed.disconnect(self._add_flash_message) if hasattr(self, '_original_template_render'): templating._render = self._original_template_render if self.run_gc_after_test: gc.collect() def assertMessageFlashed(self, message, category='message'): """ Checks if a given message was flashed. Only works if your version of Flask has message_flashed signal support (0.10+) and blinker is installed. :param message: expected message :param category: expected message category """ _check_for_message_flashed_support() for _message, _category in self.flashed_messages: if _message == message and _category == category: return True raise AssertionError("Message '%s' in category '%s' wasn't flashed" % (message, category)) assert_message_flashed = assertMessageFlashed def assertTemplateUsed(self, name, tmpl_name_attribute='name'): """ Checks if a given template is used in the request. Only works if your version of Flask has signals support (0.6+) and blinker is installed. If the template engine used is not Jinja2, provide ``tmpl_name_attribute`` with a value of its `Template` class attribute name which contains the provided ``name`` value. :versionadded: 0.2 :param name: template name :param tmpl_name_attribute: template engine specific attribute name """ _check_for_signals_support() used_templates = [] for template, context in self.templates: if getattr(template, tmpl_name_attribute) == name: return True used_templates.append(template) raise AssertionError("Template %s not used. Templates were used: %s" % (name, ' '.join(repr(used_templates)))) assert_template_used = assertTemplateUsed def get_context_variable(self, name): """ Returns a variable from the context passed to the template. Only works if your version of Flask has signals support (0.6+) and blinker is installed. Raises a ContextVariableDoesNotExist exception if does not exist in context. :versionadded: 0.2 :param name: name of variable """ _check_for_signals_support() for template, context in self.templates: if name in context: return context[name] raise ContextVariableDoesNotExist def assertContext(self, name, value, message=None): """ Checks if given name exists in the template context and equals the given value. :versionadded: 0.2 :param name: name of context variable :param value: value to check against """ try: self.assertEqual(self.get_context_variable(name), value, message) except ContextVariableDoesNotExist: self.fail(message or "Context variable does not exist: %s" % name) assert_context = assertContext def assertRedirects(self, response, location, message=None): """ Checks if response is an HTTP redirect to the given location. :param response: Flask response :param location: relative URL path to SERVER_NAME or an absolute URL """ parts = urlparse(location) if parts.netloc: expected_location = location else: server_name = self.app.config.get('SERVER_NAME') or 'localhost' expected_location = urljoin("http://%s" % server_name, location) valid_status_codes = (301, 302, 303, 305, 307) valid_status_code_str = ', '.join(str(code) for code in valid_status_codes) not_redirect = "HTTP Status %s expected but got %d" % (valid_status_code_str, response.status_code) self.assertTrue(response.status_code in valid_status_codes, message or not_redirect) self.assertEqual(response.location, expected_location, message) assert_redirects = assertRedirects def assertStatus(self, response, status_code, message=None): """ Helper method to check matching response status. :param response: Flask response :param status_code: response status code (e.g. 200) :param message: Message to display on test failure """ message = message or 'HTTP Status %s expected but got %s' \ % (status_code, response.status_code) self.assertEqual(response.status_code, status_code, message) assert_status = assertStatus def assert200(self, response, message=None): """ Checks if response status code is 200 :param response: Flask response :param message: Message to display on test failure """ self.assertStatus(response, 200, message) assert_200 = assert200 def assert400(self, response, message=None): """ Checks if response status code is 400 :versionadded: 0.2.5 :param response: Flask response :param message: Message to display on test failure """ self.assertStatus(response, 400, message) assert_400 = assert400 def assert401(self, response, message=None): """ Checks if response status code is 401 :versionadded: 0.2.1 :param response: Flask response :param message: Message to display on test failure """ self.assertStatus(response, 401, message) assert_401 = assert401 def assert403(self, response, message=None): """ Checks if response status code is 403 :versionadded: 0.2 :param response: Flask response :param message: Message to display on test failure """ self.assertStatus(response, 403, message) assert_403 = assert403 def assert404(self, response, message=None): """ Checks if response status code is 404 :param response: Flask response :param message: Message to display on test failure """ self.assertStatus(response, 404, message) assert_404 = assert404 def assert405(self, response, message=None): """ Checks if response status code is 405 :versionadded: 0.2 :param response: Flask response :param message: Message to display on test failure """ self.assertStatus(response, 405, message) assert_405 = assert405 def assert500(self, response, message=None): """ Checks if response status code is 500 :versionadded: 0.4.1 :param response: Flask response :param message: Message to display on test failure """ self.assertStatus(response, 500, message) assert_500 = assert500 # A LiveServerTestCase useful with Selenium or headless browsers # Inspired by https://docs.djangoproject.com/en/dev/topics/testing/#django.test.LiveServerTestCase class LiveServerTestCase(unittest.TestCase): def create_app(self): """ Create your Flask app here, with any configuration you need. """ raise NotImplementedError def __call__(self, result=None): """ Does the required setup, doing it here means you don't have to call super.setUp in subclasses. """ # Get the app self.app = self.create_app() self._configured_port = self.app.config.get('LIVESERVER_PORT', 5000) self._port_value = multiprocessing.Value('i', self._configured_port) # We need to create a context in order for extensions to catch up self._ctx = self.app.test_request_context() self._ctx.push() try: self._spawn_live_server() super(LiveServerTestCase, self).__call__(result) finally: self._post_teardown() self._terminate_live_server() def get_server_url(self): """ Return the url of the test server """ return 'http://localhost:%s' % self._port_value.value def _spawn_live_server(self): self._process = None port_value = self._port_value def worker(app, port): # Based on solution: http://stackoverflow.com/a/27598916 # Monkey-patch the server_bind so we can determine the port bound by Flask. # This handles the case where the port specified is `0`, which means that # the OS chooses the port. This is the only known way (currently) of getting # the port out of Flask once we call `run`. original_socket_bind = socketserver.TCPServer.server_bind def socket_bind_wrapper(self): ret = original_socket_bind(self) # Get the port and save it into the port_value, so the parent process # can read it. (_, port) = self.socket.getsockname() port_value.value = port socketserver.TCPServer.server_bind = original_socket_bind return ret socketserver.TCPServer.server_bind = socket_bind_wrapper app.run(port=port, use_reloader=False) self._process = multiprocessing.Process( target=worker, args=(self.app, self._configured_port) ) self._process.start() # We must wait for the server to start listening, but give up # after a specified maximum timeout timeout = self.app.config.get('LIVESERVER_TIMEOUT', 5) start_time = time.time() while True: elapsed_time = (time.time() - start_time) if elapsed_time > timeout: raise RuntimeError( "Failed to start the server after %d seconds. " % timeout ) if self._can_ping_server(): break def _can_ping_server(self): host, port = self._get_server_address() if port == 0: # Port specified by the user was 0, and the OS has not yet assigned # the proper port. return False sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.connect((host, port)) except socket.error as e: success = False else: success = True finally: sock.close() return success def _get_server_address(self): """ Gets the server address used to test the connection with a socket. Respects both the LIVESERVER_PORT config value and overriding get_server_url() """ parts = urlparse(self.get_server_url()) host = parts.hostname port = parts.port if port is None: if parts.scheme == 'http': port = 80 elif parts.scheme == 'https': port = 443 else: raise RuntimeError( "Unsupported server url scheme: %s" % parts.scheme ) return host, port def _post_teardown(self): if getattr(self, '_ctx', None) is not None: self._ctx.pop() del self._ctx def _terminate_live_server(self): if self._process: self._process.terminate() Flask-Testing-0.7.1/Flask_Testing.egg-info/0000755000076500000240000000000013216265617020512 5ustar comostaff00000000000000Flask-Testing-0.7.1/Flask_Testing.egg-info/dependency_links.txt0000644000076500000240000000000113216265615024556 0ustar comostaff00000000000000 Flask-Testing-0.7.1/Flask_Testing.egg-info/not-zip-safe0000644000076500000240000000000112656553604022743 0ustar comostaff00000000000000 Flask-Testing-0.7.1/Flask_Testing.egg-info/PKG-INFO0000644000076500000240000000177013216265615021612 0ustar comostaff00000000000000Metadata-Version: 1.1 Name: Flask-Testing Version: 0.7.1 Summary: Unit testing for Flask Home-page: https://github.com/jarus/flask-testing Author: Dan Jacob Author-email: danjac354@gmail.com License: BSD Description: Flask-Testing ------------- Flask unittest integration. Links ````` * `documentation ` * `development version ` Platform: any Classifier: Development Status :: 4 - Beta Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules Flask-Testing-0.7.1/Flask_Testing.egg-info/requires.txt0000644000076500000240000000000613216265615023104 0ustar comostaff00000000000000Flask Flask-Testing-0.7.1/Flask_Testing.egg-info/SOURCES.txt0000644000076500000240000000147213216265617022402 0ustar comostaff00000000000000LICENSE MANIFEST.in README setup.py Flask_Testing.egg-info/PKG-INFO Flask_Testing.egg-info/SOURCES.txt Flask_Testing.egg-info/dependency_links.txt Flask_Testing.egg-info/not-zip-safe Flask_Testing.egg-info/requires.txt Flask_Testing.egg-info/top_level.txt docs/.DS_Store docs/Makefile docs/conf.py docs/index.rst docs/make.bat docs/_static/flask-testing.png docs/_themes/README docs/_themes/flask_theme_support.py docs/_themes/flask/theme.conf docs/_themes/flask/static/flasky.css_t docs/_themes/flask_small/layout.html docs/_themes/flask_small/theme.conf docs/_themes/flask_small/static/flasky.css_t flask_testing/__init__.py flask_testing/twill.py flask_testing/utils.py tests/__init__.py tests/__main__.py tests/run.py tests/test_twill.py tests/test_utils.py tests/flask_app/__init__.py tests/flask_app/templates/index.htmlFlask-Testing-0.7.1/Flask_Testing.egg-info/top_level.txt0000644000076500000240000000001613216265615023237 0ustar comostaff00000000000000flask_testing Flask-Testing-0.7.1/LICENSE0000644000076500000240000000265412656551557015307 0ustar comostaff00000000000000Copyright (c) 2010 by Dan Jacob. Some rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Flask-Testing-0.7.1/MANIFEST.in0000644000076500000240000000034412656551557016032 0ustar comostaff00000000000000include LICENSE recursive-include tests * recursive-exclude tests *.pyc recursive-exclude tests *.pyc recursive-include docs * recursive-exclude docs *.pyc recursive-exclude docs *.pyo prune docs/_build prune docs/_themes/.git Flask-Testing-0.7.1/PKG-INFO0000644000076500000240000000177013216265617015365 0ustar comostaff00000000000000Metadata-Version: 1.1 Name: Flask-Testing Version: 0.7.1 Summary: Unit testing for Flask Home-page: https://github.com/jarus/flask-testing Author: Dan Jacob Author-email: danjac354@gmail.com License: BSD Description: Flask-Testing ------------- Flask unittest integration. Links ````` * `documentation ` * `development version ` Platform: any Classifier: Development Status :: 4 - Beta Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules Flask-Testing-0.7.1/README0000644000076500000240000000023013207044670015130 0ustar comostaff00000000000000flask-testing Unit testing support for Flask. For full information please refer to the online docs: https://flask-testing.readthedocs.io/en/latest/ Flask-Testing-0.7.1/setup.cfg0000644000076500000240000000007313216265617016104 0ustar comostaff00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 Flask-Testing-0.7.1/setup.py0000644000076500000240000000264413216265577016010 0ustar comostaff00000000000000""" Flask-Testing ------------- Flask unittest integration. Links ````` * `documentation ` * `development version ` """ import sys from setuptools import setup tests_require = [ 'blinker' ] install_requires = [ 'Flask' ] if sys.version_info[0] < 3: tests_require.append('twill==0.9.1') if sys.version_info < (2, 6): tests_require.append('simplejson') install_requires.append('multiprocessing') setup( name='Flask-Testing', version='0.7.1', url='https://github.com/jarus/flask-testing', license='BSD', author='Dan Jacob', author_email='danjac354@gmail.com', description='Unit testing for Flask', long_description=__doc__, packages=['flask_testing'], test_suite="tests.suite", zip_safe=False, platforms='any', install_requires=install_requires, tests_require=tests_require, classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development :: Libraries :: Python Modules' ] ) Flask-Testing-0.7.1/tests/0000755000076500000240000000000013216265617015425 5ustar comostaff00000000000000Flask-Testing-0.7.1/tests/__init__.py0000644000076500000240000000220113216057214017521 0ustar comostaff00000000000000import unittest from flask_testing import is_twill_available from .test_twill import TestTwill, TestTwillDeprecated from .test_utils import TestSetup, TestSetupFailure, TestClientUtils, \ TestLiveServer, TestTeardownGraceful, TestRenderTemplates, \ TestNotRenderTemplates, TestRestoreTheRealRender, \ TestLiveServerOSPicksPort def suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(TestSetup)) suite.addTest(unittest.makeSuite(TestSetupFailure)) suite.addTest(unittest.makeSuite(TestClientUtils)) suite.addTest(unittest.makeSuite(TestLiveServer)) suite.addTest(unittest.makeSuite(TestLiveServerOSPicksPort)) suite.addTest(unittest.makeSuite(TestTeardownGraceful)) suite.addTest(unittest.makeSuite(TestRenderTemplates)) suite.addTest(unittest.makeSuite(TestNotRenderTemplates)) suite.addTest(unittest.makeSuite(TestRestoreTheRealRender)) if is_twill_available: suite.addTest(unittest.makeSuite(TestTwill)) suite.addTest(unittest.makeSuite(TestTwillDeprecated)) else: print("!!! Skipping tests of Twill components\n") return suite Flask-Testing-0.7.1/tests/__main__.py0000644000076500000240000000007212656551557017526 0ustar comostaff00000000000000from run import run if __name__ == '__main__': run() Flask-Testing-0.7.1/tests/flask_app/0000755000076500000240000000000013216265617017365 5ustar comostaff00000000000000Flask-Testing-0.7.1/tests/flask_app/__init__.py0000644000076500000240000000251513216265572021501 0ustar comostaff00000000000000from flask import ( Flask, Response, abort, redirect, jsonify, render_template, url_for, flash, request ) def create_app(): app = Flask(__name__) app.config['SECRET_KEY'] = 'super secret testing key' @app.route("/") def index(): return Response("OK") @app.route("/template/") def index_with_template(): return render_template("index.html", name="test") @app.route("/flash/") def index_with_flash(): flash("Flashed message") return render_template("index.html") @app.route("/no_flash/") def index_without_flash(): return render_template("index.html") @app.route("/oops/") def bad_url(): abort(404) @app.route("/redirect/") def redirect_to_index(): code = request.args.get('code') or 301 return redirect(url_for("index"), code=code) @app.route("/external_redirect/") def redirect_to_flask_docs(): return redirect("http://flask.pocoo.org/") @app.route("/ajax/") def ajax(): return jsonify(name="test") @app.route("/forbidden/") def forbidden(): abort(403) @app.route("/unauthorized/") def unauthorized(): abort(401) @app.route("/internal_server_error/") def internal_server_error(): abort(500) return app Flask-Testing-0.7.1/tests/flask_app/templates/0000755000076500000240000000000013216265617021363 5ustar comostaff00000000000000Flask-Testing-0.7.1/tests/flask_app/templates/index.html0000644000076500000240000000000312656551557023361 0ustar comostaff00000000000000OK Flask-Testing-0.7.1/tests/run.py0000644000076500000240000000127612656551557016621 0ustar comostaff00000000000000import sys import unittest try: from coverage import coverage coverage_available = True except ImportError: coverage_available = False def run(): if coverage_available: cov = coverage(source=['flask_testing']) cov.start() from tests import suite result = unittest.TextTestRunner(verbosity=2).run(suite()) if not result.wasSuccessful(): sys.exit(1) if coverage_available: cov.stop() print("\nCode Coverage") cov.report() cov.html_report(directory='cover') else: print("\nTipp:\n\tUse 'pip install coverage' to get great code " "coverage stats") if __name__ == '__main__': run() Flask-Testing-0.7.1/tests/test_twill.py0000644000076500000240000000205712656551557020205 0ustar comostaff00000000000000from __future__ import with_statement from flask_testing import TestCase, TwillTestCase, Twill from .flask_app import create_app class TestTwill(TestCase): def create_app(self): app = create_app() app.config.from_object(self) return app def test_twill_setup(self): twill = Twill(self.app) self.assertEqual(twill.host, "127.0.0.1") self.assertEqual(twill.port, 5000) self.assertTrue(twill.browser is not None) def test_make_twill_url(self): with Twill(self.app) as t: self.assertEqual(t.url("/"), "http://127.0.0.1:5000/") class TestTwillDeprecated(TwillTestCase): def create_app(self): app = create_app() app.config.from_object(self) return app def test_twill_setup(self): self.assertEqual(self.twill_host, '127.0.0.1') self.assertEqual(self.twill_port, 5000) self.assertTrue(self.browser is not None) def test_make_twill_url(self): self.assertEqual(self.make_twill_url("/"), "http://127.0.0.1:5000/") Flask-Testing-0.7.1/tests/test_utils.py0000644000076500000240000002074113216265572020202 0ustar comostaff00000000000000try: from urllib2 import urlopen except ImportError: from urllib.request import urlopen from unittest import TestResult from flask_testing import TestCase, LiveServerTestCase from flask_testing.utils import ContextVariableDoesNotExist from .flask_app import create_app class TestSetup(TestCase): def create_app(self): return create_app() def test_setup(self): self.assertTrue(self.app is not None) self.assertTrue(self.client is not None) self.assertTrue(self._ctx is not None) class TestSetupFailure(TestCase): def _pre_setup(self): pass def test_setup_failure(self): '''Should not fail in _post_teardown if _pre_setup fails''' assert True class TestTeardownGraceful(TestCase): def create_app(self): return create_app() def test_remove_testcase_attributes(self): """ There should no exception after this test because teardown is graceful. """ del self.app del self._ctx class TestClientUtils(TestCase): def create_app(self): return create_app() def test_get_json(self): response = self.client.get("/ajax/") self.assertEqual(response.json, dict(name="test")) def test_status_failure_message(self): expected_message = 'my message' try: self.assertStatus(self.client.get('/'), 404, expected_message) except AssertionError as e: self.assertTrue(expected_message in str(e)) def test_default_status_failure_message(self): expected_message = 'HTTP Status 404 expected but got 200' try: self.assertStatus(self.client.get('/'), 404) except AssertionError as e: self.assertTrue(expected_message in str(e)) def test_assert_200(self): self.assert200(self.client.get("/")) def test_assert_404(self): self.assert404(self.client.get("/oops/")) def test_assert_403(self): self.assert403(self.client.get("/forbidden/")) def test_assert_401(self): self.assert401(self.client.get("/unauthorized/")) def test_assert_405(self): self.assert405(self.client.post("/")) def test_assert_500(self): self.assert500(self.client.get("/internal_server_error/")) def test_assert_redirects(self): response = self.client.get("/redirect/") self.assertRedirects(response, "/") def test_assert_redirects_full_url(self): response = self.client.get("/external_redirect/") self.assertRedirects(response, "http://flask.pocoo.org/") def test_assert_redirects_failure_message(self): response = self.client.get("/") try: self.assertRedirects(response, "/anything") except AssertionError as e: self.assertTrue("HTTP Status 301, 302, 303, 305, 307 expected but got 200" in str(e)) def test_assert_redirects_custom_message(self): response = self.client.get("/") try: self.assertRedirects(response, "/anything", "Custom message") except AssertionError as e: self.assertTrue("Custom message" in str(e)) def test_assert_redirects_valid_status_codes(self): valid_redirect_status_codes = (301, 302, 303, 305, 307) for status_code in valid_redirect_status_codes: response = self.client.get("/redirect/?code=" + str(status_code)) self.assertRedirects(response, "/") self.assertStatus(response, status_code) def test_assert_redirects_invalid_status_code(self): status_code = 200 response = self.client.get("/redirect/?code=" + str(status_code)) self.assertStatus(response, status_code) try: self.assertRedirects(response, "/") except AssertionError as e: self.assertTrue("HTTP Status 301, 302, 303, 305, 307 expected but got 200" in str(e)) def test_assert_template_used(self): try: self.client.get("/template/") self.assert_template_used("index.html") except RuntimeError: pass def test_assert_template_not_used(self): self.client.get("/template/") try: self.assertRaises(AssertionError, self.assert_template_used, "invalid.html") except RuntimeError: pass def test_get_context_variable(self): try: self.client.get("/template/") self.assertEqual(self.get_context_variable("name"), "test") except RuntimeError: pass def test_assert_context(self): try: self.client.get("/template/") self.assert_context("name", "test") except RuntimeError: pass def test_assert_context_custom_message(self): self.client.get("/template/") try: self.assert_context("name", "nothing", "Custom message") except AssertionError as e: self.assertTrue("Custom message" in str(e)) except RuntimeError: pass def test_assert_bad_context(self): try: self.client.get("/template/") self.assertRaises(AssertionError, self.assert_context, "name", "foo") self.assertRaises(AssertionError, self.assert_context, "foo", "foo") except RuntimeError: pass def test_assert_bad_context_custom_message(self): self.client.get("/template/") try: self.assert_context("foo", "foo", "Custom message") except AssertionError as e: self.assertTrue("Custom message" in str(e)) except RuntimeError: pass def test_assert_get_context_variable_not_exists(self): try: self.client.get("/template/") self.assertRaises(ContextVariableDoesNotExist, self.get_context_variable, "foo") except RuntimeError: pass def test_assert_flashed_messages_succeed(self): try: self.client.get("/flash/") self.assertMessageFlashed("Flashed message") except RuntimeError: pass def test_assert_flashed_messages_failed(self): try: self.client.get("/flash/") self.assertRaises(AssertionError, self.assertMessageFlashed, "Flask-testing has assertMessageFlashed now") except RuntimeError: pass def test_assert_no_flashed_messages_fail(self): try: self.client.get("/no_flash/") self.assertRaises(AssertionError, self.assertMessageFlashed, "Flashed message") except RuntimeError: pass class BaseTestLiveServer(LiveServerTestCase): def test_server_process_is_spawned(self): process = self._process # Check the process is spawned self.assertNotEqual(process, None) # Check the process is alive self.assertTrue(process.is_alive()) def test_server_listening(self): response = urlopen(self.get_server_url()) self.assertTrue(b'OK' in response.read()) self.assertEqual(response.code, 200) class TestLiveServer(BaseTestLiveServer): def create_app(self): app = create_app() app.config['LIVESERVER_PORT'] = 8943 return app class TestLiveServerOSPicksPort(BaseTestLiveServer): def create_app(self): app = create_app() app.config['LIVESERVER_PORT'] = 0 return app class TestNotRenderTemplates(TestCase): render_templates = False def create_app(self): return create_app() def test_assert_not_process_the_template(self): response = self.client.get("/template/") assert len(response.data) == 0 def test_assert_template_rendered_signal_sent(self): self.client.get("/template/") self.assert_template_used('index.html') class TestRenderTemplates(TestCase): render_templates = True def create_app(self): return create_app() def test_assert_not_process_the_template(self): response = self.client.get("/template/") assert len(response.data) > 0 class TestRestoreTheRealRender(TestCase): def create_app(self): return create_app() def test_assert_the_real_render_template_is_restored(self): test = TestNotRenderTemplates('test_assert_not_process_the_template') test_result = TestResult() test(test_result) assert test_result.wasSuccessful() response = self.client.get("/template/") assert len(response.data) > 0