ÿØÿà JFIF    ÿÛ „ !.%+&8&+/1555$;@;4?.451 4,$,44444444444414444444444444444444444444444444444444ÿÀ  á á" ÿÄ     ÿÄ ?    !1AQaq"2‘¡±ÁðBRbrÑá#‚’¢²3S CñÿÄ   ÿÄ !    !1QAa‘2ÿÚ   ? 5˜Z¯V¦cø)›t/? z¨±>Õ5€¶‹Á¤·¼z¼Ü¬+ñ®v¤¨_ˆR­BFn©—˜ý®ç̝P8gýt·ÉSTŦˆìät?þé¼íìN/Þa)ì–í6ô… Ï¿øÃj´¿KÇü]ÿ ªô¹-eKànëÕHTx}ýSÜ›ÿ ”7Ø×&µ<¦  ¥ÑO¶[Ù¯ä¨ÞÃÿ PZ-¬;#õ|•oaÿ ©CìÞz3˜öː/¤­ñTûIØ}š^ mÓ%ªxˆ¥ÉŸu=Z+ISe¿45™¼u;ú&WØ÷€æßQ™®{|íx*TC“#ZŠìZ§²‹ 6pv…³¿¡äª*áZÐ%ÒOáˆo"x«OHk w±æ+¬V(kMúŸ5Vö«$ ÁrÏbàb57/luR ¸ÑÛj Òµì`Мq­û žICÀÊ•©4€Âcà¨Ï€O´<èÐ:›ù(Ë^L8þ‘ÍÌ#¸Ð_Ì©ÙK(Öz 4¬û+¸;ü’V’84‘¬ÃŽ:[â‡ÔÌáõp¢~§ªlæ£ö{®G>J¼"°‡7¯ÆÉèßû ‹É‹§ÁòÃýâßî ^ƾÙõ‹×óH#«LP½ïX=xÑÍ$|W?•~• îëÔ©ª‹ {ÝT…Kÿ ”hûâá)J*ö˜–ÔU;iÇ€/ ÆþjóZ\ýwØ=Ìm ºèËL9 ýèÆð/¨’¥öo=nË.%Îì ŽÕ¯È|{Oj²ƒE6e/ßdÄõ²Ìâ1O®ò×TsəԸhOMýíMˆ¿¼H˜l²,7Â¥#MF/Úf°Ö½± ¸–dr‹NýÊ íjqx{œÉ ä-È ¦ øÄër¨q°ð †nцýÑÄÆ’mä…n<0È™;ÁÝá¯ÁZƒ7FÀmì­ É&9ˆîéi¶ùN§Y• ÃZãAâ?•‡©‰ , ó¾IŸŠc1 4â&y­&pŠ­6;M À 0¹qç»p.á …ŸÅáK@%6·y6ƒ‰3?”úºŽ‰éX5ªPT §µ!=Mž«Ú½‹ÅgÂSâÉaþÓoö–¯ÁÔìR>5éÿ üs¶ÆUcÌ kÇR ]ÿ ù¬¼«VŽ;Â|‡~¢¦”ÏŰæ {L™Õ°Óv¹ò¸írޡעCÃ!íVÕ {¶»sŒNPg/ "uÕbkm²“$ďå¿é¹§°½æz¯6 †s¿!s–wÚÝ“™Œ °.ûj>·+™Òa…©Œ&rÝÎtÛë긪Ît’LAVp%c Úý[ÄzJ¾ÇàXXç@˜ó<êL]·T˜¾¥1Ó©V‡g´æ½¦Ý@¹óø!_@´ÞâSÁ —S3™•& ]@JHÚý©ZŽ €×æÔr»Áf!‡yÞ4Mv*èÓã_{‘åóUuљØ«Oïé*®EvÑ Œ÷‡U \"㪒ÍK+À 4“M¡ï:0¥5í!'<@î´”>Ç»&Z–ïCCV˜Ì5Šo&îhè.žû |ÓK©h$s6KìŒëã)¹hI¦GïOåóI;ììü#É$Š0…Ææ¥TØ.5­¾gn´ “ÂÖ\:hœ89G)J@„}œ:’Ò{/Š"¦_Æ×7Æ3VÇŠÊa]ÚŒÙ€Ä–=®uÁßâACZƒ§§£ Qnâ:«,×{tyø¬iÛcœÜÄ€H½ÄÍCk´÷šß .W'b¤Íåh]÷€=,Žv×cÚEÚHXJX¶îo¨FÒtèöŸ>ªª6[J®Fµ£sGÁeqõfe\íjÒÐïÄÐGˆe1Ø‹.Ø”‘Ëuø Y­ˆÜ ŽG|zùªüMpDnQWÄ”%JŠ™)â*p@Örš«ÕT2Ð%ˆG#ª„ ·¤!°ŸOTÂT¸aÚ%4&h™LµšØüÐ.F¿²ÐÞ_Ç‚¾ÅÃaÜ÷09Æ q€öy˜v‡85õN÷]¬äѼóS{°_MެúÔ#°Ç¸0åÞè2ëôPcvÆw9®ií1Ä8F™˜à‰´+‰Ik1òÝ7“Ñ×ÒsÝ\x‚h`ÞÑ`ó"|µEcý£n˜h`}GÞ !±ù²Ápü²ß6 0ïi󜵩SÈÇ7˜-ÕURO˜¦´f$ªž-Í6(œ}<„ éc øs]ŽŽ„*—¾ ìdŽ„)méª\¿êÎIg¾ØÞ~I#C/¼¼´EÁÈŽi8“©õådô·>euä ƒ'Ê×लR1ÉJE1ÐAát`t;ÇР%Ý<‡¥„ÍÆ`×Oyó)õiI€ñQaŸ4Ûù\áàaÃÔ¹HÃu¹*k€¦<„e S‡&õÏ B!ŽhüÞ`yj}mªf×\¿ Ç~æ­9‡û\՞Ǖg²1Žû5V7 !àöšm° c`ܬøÇìµÒ'P"?…´Ö,"§^•õލsÔ)6˜sæéÍR¼ ò|Sl”‹7 nPW Gòú÷½§O¯‡„l¡kSÞŒr½PÊ@æ¢pŽ-mÿ #Ÿ˜Àº¶Áä¦;ïÔæ$1££`“Õ>„—·ž)ßð³ñ#Ï Ô$¶œ‰ÊE‹À;÷º ¯«P:Ñ”8–IÊtpÞ3ª“>ê“þës4ò2OÏÕ­±zô†Õ§‰.÷ä¸;¿˜“'œ›žª}«Œ{ª±Ì 9ÔóÞÕ‡0 $íWV3Üì¬ —@kÝ4@¿r¼±½¬™›?øØæ´'Áé®CË3-g$˜ö‡×auÚi´Žp/êÛ æF›Ú2v‹ã¿¿,nB1̨ƃqÞa5͝@&Æû“él÷ \C²½UÍc ¯k×¢U ÖéQå™—-r wô ÞÏ<Ò=&=ÿ Ôê Òêˈt,i—;LîÜ á¸*ÚÃ1$êL•LÍ <É)ýÐà’ ;F™{ƒ™˜€&'}‚ãÄK`¡ÞT@I;®žZóè‚s’7®°›+§O­Åq©é»²9<Ô J ¼9O’HL»Ùïì¸rk¼Ž_ý‘TŸu[²ßÚŒ·ü÷B%¯E ŸÔX5êO´ Ç•€’I0 ÉJX` ñ¹õ%;µŸD‘«´€àwÒ™U ûئžÖö\×®×´8 ½‡ºÐÆÓ§?Àkmœ=;d5*@-ì0F Rªýš[Ü6âö̃ڸr*KA9· u*µæ£?U¸Âêí†8@¦X4 e-ò„0s{ HâUpU?¼mñRa°®a%Ð'tÉ×’\¾ÊÉ]t›h>·(Ë@R¼¡Ãt h}’O÷au<+nT…Ö…MӐ??Óe95 q>í/;&JSû °¯ÊéÞ øƒ*Ã2½Ài&:nôUl=¾¿5eˆ3”ñc|Ú2V”>„»&eE;«ÚäC p¢Û úy 9š[ŒÌx¼擼A&DåÒ¯ˆ¤ÀÌ;"˜ ÏQä¸åhÊ}Ûq«Û0WžÒ|»€ø®öCm5•\ÇÀ§Pe3£]0ÃàLDÉ‰1øªxjgwT‚÷¿LΨK‹›ùs—xˆÜ±µ kæ¸f‰‰ÜGk/LÛØ6d9ò¶ùA{ƒA3š/¬D¬khÓk‰`˜"㯒r¿±Óã jx‡°e}<Ñø\3y:'À•/h½Í€Ç4~g ?Û(¼]v‘ªlKÎâ~?O‚W%{Ì:“'©úNq¾›úo(X’¥¯ˆ nFê{Ç€ü?º'ë ø‹ì Þ09ŒÌç9Æ —ËC`j@ÓÄ(+a‹un¸#ÂꟋ{K`‘ÑÍÍ'à´»/Û,KW;Þ4²þð ï Nm|~fGÏ(…³Ã)«1ö­Õ ¥‡¨©ƒÃ™ü-s=à=U66Ï«Ýc蓦W¹íž®›nÔ%êÇìŒ<#Ü×84ån®Ð ÒåOC` ñânÑs‡¢ç 1õ%Îhì½Ã½® e:ݼUZo™`  ÅZŸŒÊ«ê1ÏÄo$q¹Þ€©ˆhÐÉä¯ñ[!…Ú˜àJ:x2$Íß&PåT£6ç— ‡Í*4Ýšçjÿ ‰É nófÐ ó(L5C•åÆ\rMÒ@ò }y-W}™üýVù—ú¢=Ù”c®‘< M ž ´Phr ¦©TD ‘ù.$´÷O‡‘V2Æò.=IUŒ=ž‡â¬i™aþÓåÙ?òUø'ØÖ•.~* šTŒ!•-×áºTâ®ä#õü'´ eýlYÅÓeÕKÂrT"CÚ@u!Óxƒ{š3€}1¿(r}%«nËamjÑ%ÑNEò v ˜à  σöK³,*º.àzù¨™Ó ÚçâU¦*¿ 9{%Ö¹ njûdaXöb) kÛÆ±ûÓ\°M7ˆÂ=û›ç¿Ã‚­V»Cg–8ÙêE- j)k$º`Ã-ùEýeBÆÇ]c¡°ñty&Òd0nõ'¡W+ƒ*|–øµFa\GQªEAÔp5\Ǽ·¼Ç8·õ -â§Ú[ ‡ uZeÖ 3}×d'+¹:ð+K†Û®s!Ï$úe€<Û”x)1»a­¡LC]¸µík…ÚàA»AYº{†ªS[¦5HÒ7ù --,ísòDØ€èk ÞÀîÜ ò@â( ËNˆë›4ô½•/¦o‡€Û7 ê•ÆêòðÜy'Án½µ á˜ݦ ndeo…[ì¶Ê,¥R³Ä=À±—–ß;£™´ñSâ*g§”ïaið‘Jå~™ÓÞ ß³Õ¢»8x埒²52>AÊb&-÷\7´éÄù€T˜,w;3{ï˜k…à¹ÄqÀ«œ{€\ ˆ¾[´¨јr &Úé„Ívˆ±8†¿]|¬ņ4I×pÞS1ÈÖz‰#Ìv‡G!YNògñ:màTz¢Ý1ô©^O=~ë|5Bã™ç•¼µõ•bÆ@úÕS¬ÈŒ#¬zünrŸ û” Z²•èðV"ÁHÚý©wÝ €7¼Ìu1hÑa3Éä û f$o¿É ™Ú›ÝçnpÒ3äÌ3†Í§,Äï]$‰/pê †«À¼¸e9­Æê_C]žƒ·ý·frÁN«, E=›Çq -‰öŒ:aÏ¿±í&£Í:-} 84‘ÿ eƒQÑeëSsuiA ³g㟥ú£?ÿ ʼn*”“÷aühe:ÊWa@ÒÞk±eØ] F Ô—r.åä˜ @ö¥ªZoÐýYL·¥S²G/‡ñ <~*ZÆ´è>JlòàÛÆ½ÿ 窘ìGN¢:I®KšJp/`íIÁÀõ#Ä-€ö­šµŒoF4|ÆQØÆ@Ì|£Ô…¢À{9˜è½Üó›€ôYÒÎYsið;ís¤€à²ˆ‚4qÉVŒI$ ‰"° æµ8cXGjœˏ¡Aâý•ËÜ¢ûï e·çLx']á"oÅÎê3¯Ç—¹”ó0nå‚âg{Œñ> S´˜îè°g238‚ãköÝfÚd´6Ò€;ò÷±¢™¼›º ¢Æ'¥Ðx'e¬ç ]bÈÆV¢ó‹kýBO ðÊâ$Ÿ!×T 3Mýמ žìٍàÌü‘8÷€àæØ8æ©6‰©L´«…oãpð„~Çk‰!ñ;‹”ÛžÍ àž±z Ÿôû øŸÝužÏ;ÿ #|u6™Þ¬ÚˆÐõA4¶â|ôl|Ê2ŽÇ¤ÝÅÇY.<#Aí.k§hóF‚”Y; M½Ö4hŸ4&›­¿tès´%FìL¥£Ãk‰ÇT¤haÁ¤ÚxfÉ`ÑìË›>i 3t‚:,–+^÷´–{Û–Nxi"x‘Ûg î¨>¥Õ܁ùZH,2Û“:8xÊ¢Çí9.É-Ìâã-=çjwµS˜dütžçwýGòú®®ûº_ˆýx$–¡ãøO EÚÛÏ÷R„×w+3£Á£öUMyR²¹âŒ°š›¸Ñãò9§Ó_Dl+Ùßc›úšGÅÌc†Ž!Ko=¶.‘Îÿ c²(2®V mª.ÿ ¹B›¹å ù„öŸSV>™ü¯$y:G¢Z×àøúdî¹û­·ýÇ´:•c LÍõi_‹ö+ÎæGÊè>OŠ•äž´§Þ{X}¨1ÚTc›»Qþ•êô°t¿OP?eæ~É{5]•ÙR£r5†nZ\ã@ &îJõ ¾àC°þV>fé¥/ü5ñÊIº_é5 ;e­h<@ Ä&æÃëE%;X,ÒãÆÞ`Oò¦kŸm#˜!ÀyÄ¢| óLšò¥Ä` ¶R=|ÈCâh5ò3DˆïF†ðÒ#ÅìÛœ?¸yhBãœí ZxßÎÄhºRK„`Þödvײ™ÀÈÑÒgŒuY w³%†ƒÓzõ ÖÏp‚dH®¦A´ù§»ÓÇMæ~)ˆð‡û:ù&Ä •vGD´À n ݇¼Ö8Fö óáà£~Ë¥x`oK|Ä?fxiØü%pìR>éò+Û±éÎ>núlFŤ'tq8LZÏvÃ?„¡ß±È⽆¯³íü@x|PöUäèØã¡ð‚ŒAìÏ"vÍwóŸÍ{ ý0.z È•Ö{,N¡£¡ŸKÕÙž>Ýœþ ÍÀ°<×EA!Å‚D™IúOÍ¡>ôG}Â` ÍßkÜL™Ž Þð™ {IøF²¹òQ3&!ÃÂÞz.d&Ï-sH¸,Ôõ˜ŽP€ 77ˆÝ¼ÊëÜw =cÕ Ú,ØÐ5ÎYÐ)ì´öœgŒ[¤ßv㙑8心>h]§µháYš£²ºÑ.{Ï7Sð•?´~×SÃKýJÛ˜ ™Íäiúu<µX¶1õ^kâçIÑ£sZ4h>j*ÔšD:4­¿_ ÷¸ Õxæÿ ¸?Mù _•­ÊÐ ä ÷ý ÑwL œ­ïnTkÛUÍN©ë:¦fV ¶ÜÔÜMªÅâA½–¿R×TXš-%iTÊT•‡Ù‚JôϐZxWÑè‰f‰òG º ×Õû2aZ7OU3[“×AT–ÞŒ…-‘¤”Ì ì&(ˆ¿­•ƒkï’:ðY¦W‘ Å)“†‘˜³Åtcø˜ñTÂwÚÇ4|üLÇªí–v- qˆèU qPE.†â‘˜µ Æ,ÐÅs]8¾„oúÑ i>ÜxxÈó)ƒ ´æÁâØ$À‰vžŸf$Ž |ãw;ÀÁIJ»b` {¦Ó¤Ú$©YÀ‘n@Óïž«9J¼êG m¤ ܯ¹ÌW4€ÐÒÅÛ‡#褕Ÿn-?í|с¥÷Ú¹¬'´ÞÜ9ÓK `hê£SÄSà?7—Wí_´…óB›»:=Ãïq`<8ñÓŒÑlú2d¬ê³£hÖ[l|$vÝro~'R®‰§°ñmY ͧäP |PUª¹·:3Œ[Û{Xÿ ºâ@‚W–Äé u‚ ¯´*=íή.pûÒdt @G‰¬ s¸ ëÉücr ÞæÑ¨Ê@>¤¢Ö±. Þ'¯°ÌME[YéïĵÂCå½ Ué©Áû'Ê9%eÔðNU”ë‘ÌsD3/®+UI˜9h.WC”빓$#:pz:YÓ ¿xž* ³$Í +$kñAŠ‹†¢ Uê>¸)_š¬÷©ßAÂÔb9ÇU ¯¾á•9¯ÏÏ÷O÷¼¼Fähal1‰3Ì[Ïr•´UCksNÐ] R‘¸¥H+§Šé†c©vÖÞ0iÓ76s†î!§=ß ¼~Ô'°Ãmäoäš³ªøi1úÉ)³yV8 CLÄØÁ‘WYïi€H6ÖÑiámø^ÈY´°Ñ7¥Û*—Ñ©L«Qƒï—Ùrÿ ›£Ð*š¸ˆL©ˆ$ˆ ÷¾D§9È®«qbqC)–ˆïv´çñsÑVT­Ø, <àïºÀO«Jý·õ àfPìð .wFšir´þ’2_Y *Æ€x\« ì€9š@ Ž|F⇥ˆkZ@hÖÄ0t¿-<“‹qµ¾*ZL¤Ú)&BJpÓF5=$„at*Zš$’ÑtdûÝRI1 2މ$€$I$#‰SÞ’Hë¬ï;Á$¡t$’`<(ñÇt)$‡Ð.Êf¢X’Kt=Éé$‚ˆªè¢oÝëòI%Rgcª÷ŠyI%¡‰ÿ !ñ)´õ $¤ Ô’IIGÿÙimport inspect import types import unittest from test.support import import_module from test.support import gc_collect asyncio = import_module("asyncio") class AwaitException(Exception): pass @types.coroutine def awaitable(*, throw=False): if throw: yield ('throw',) else: yield ('result',) def run_until_complete(coro): exc = False while True: try: if exc: exc = False fut = coro.throw(AwaitException) else: fut = coro.send(None) except StopIteration as ex: return ex.args[0] if fut == ('throw',): exc = True def to_list(gen): async def iterate(): res = [] async for i in gen: res.append(i) return res return run_until_complete(iterate()) class AsyncGenSyntaxTest(unittest.TestCase): def test_async_gen_syntax_01(self): code = '''async def foo(): await abc yield from 123 ''' with self.assertRaisesRegex(SyntaxError, 'yield from.*inside async'): exec(code, {}, {}) def test_async_gen_syntax_02(self): code = '''async def foo(): yield from 123 ''' with self.assertRaisesRegex(SyntaxError, 'yield from.*inside async'): exec(code, {}, {}) def test_async_gen_syntax_03(self): code = '''async def foo(): await abc yield return 123 ''' with self.assertRaisesRegex(SyntaxError, 'return.*value.*async gen'): exec(code, {}, {}) def test_async_gen_syntax_04(self): code = '''async def foo(): yield return 123 ''' with self.assertRaisesRegex(SyntaxError, 'return.*value.*async gen'): exec(code, {}, {}) def test_async_gen_syntax_05(self): code = '''async def foo(): if 0: yield return 12 ''' with self.assertRaisesRegex(SyntaxError, 'return.*value.*async gen'): exec(code, {}, {}) class AsyncGenTest(unittest.TestCase): def compare_generators(self, sync_gen, async_gen): def sync_iterate(g): res = [] while True: try: res.append(g.__next__()) except StopIteration: res.append('STOP') break except Exception as ex: res.append(str(type(ex))) return res def async_iterate(g): res = [] while True: an = g.__anext__() try: while True: try: an.__next__() except StopIteration as ex: if ex.args: res.append(ex.args[0]) break else: res.append('EMPTY StopIteration') break except StopAsyncIteration: raise except Exception as ex: res.append(str(type(ex))) break except StopAsyncIteration: res.append('STOP') break return res sync_gen_result = sync_iterate(sync_gen) async_gen_result = async_iterate(async_gen) self.assertEqual(sync_gen_result, async_gen_result) return async_gen_result def test_async_gen_iteration_01(self): async def gen(): await awaitable() a = yield 123 self.assertIs(a, None) await awaitable() yield 456 await awaitable() yield 789 self.assertEqual(to_list(gen()), [123, 456, 789]) def test_async_gen_iteration_02(self): async def gen(): await awaitable() yield 123 await awaitable() g = gen() ai = g.__aiter__() an = ai.__anext__() self.assertEqual(an.__next__(), ('result',)) try: an.__next__() except StopIteration as ex: self.assertEqual(ex.args[0], 123) else: self.fail('StopIteration was not raised') an = ai.__anext__() self.assertEqual(an.__next__(), ('result',)) try: an.__next__() except StopAsyncIteration as ex: self.assertFalse(ex.args) else: self.fail('StopAsyncIteration was not raised') def test_async_gen_exception_03(self): async def gen(): await awaitable() yield 123 await awaitable(throw=True) yield 456 with self.assertRaises(AwaitException): to_list(gen()) def test_async_gen_exception_04(self): async def gen(): await awaitable() yield 123 1 / 0 g = gen() ai = g.__aiter__() an = ai.__anext__() self.assertEqual(an.__next__(), ('result',)) try: an.__next__() except StopIteration as ex: self.assertEqual(ex.args[0], 123) else: self.fail('StopIteration was not raised') with self.assertRaises(ZeroDivisionError): ai.__anext__().__next__() def test_async_gen_exception_05(self): async def gen(): yield 123 raise StopAsyncIteration with self.assertRaisesRegex(RuntimeError, 'async generator.*StopAsyncIteration'): to_list(gen()) def test_async_gen_exception_06(self): async def gen(): yield 123 raise StopIteration with self.assertRaisesRegex(RuntimeError, 'async generator.*StopIteration'): to_list(gen()) def test_async_gen_exception_07(self): def sync_gen(): try: yield 1 1 / 0 finally: yield 2 yield 3 yield 100 async def async_gen(): try: yield 1 1 / 0 finally: yield 2 yield 3 yield 100 self.compare_generators(sync_gen(), async_gen()) def test_async_gen_exception_08(self): def sync_gen(): try: yield 1 finally: yield 2 1 / 0 yield 3 yield 100 async def async_gen(): try: yield 1 await awaitable() finally: await awaitable() yield 2 1 / 0 yield 3 yield 100 self.compare_generators(sync_gen(), async_gen()) def test_async_gen_exception_09(self): def sync_gen(): try: yield 1 1 / 0 finally: yield 2 yield 3 yield 100 async def async_gen(): try: await awaitable() yield 1 1 / 0 finally: yield 2 await awaitable() yield 3 yield 100 self.compare_generators(sync_gen(), async_gen()) def test_async_gen_exception_10(self): async def gen(): yield 123 with self.assertRaisesRegex(TypeError, "non-None value .* async generator"): gen().__anext__().send(100) def test_async_gen_exception_11(self): def sync_gen(): yield 10 yield 20 def sync_gen_wrapper(): yield 1 sg = sync_gen() sg.send(None) try: sg.throw(GeneratorExit()) except GeneratorExit: yield 2 yield 3 async def async_gen(): yield 10 yield 20 async def async_gen_wrapper(): yield 1 asg = async_gen() await asg.asend(None) try: await asg.athrow(GeneratorExit()) except GeneratorExit: yield 2 yield 3 self.compare_generators(sync_gen_wrapper(), async_gen_wrapper()) def test_async_gen_api_01(self): async def gen(): yield 123 g = gen() self.assertEqual(g.__name__, 'gen') g.__name__ = '123' self.assertEqual(g.__name__, '123') self.assertIn('.gen', g.__qualname__) g.__qualname__ = '123' self.assertEqual(g.__qualname__, '123') self.assertIsNone(g.ag_await) self.assertIsInstance(g.ag_frame, types.FrameType) self.assertFalse(g.ag_running) self.assertIsInstance(g.ag_code, types.CodeType) self.assertTrue(inspect.isawaitable(g.aclose())) class AsyncGenAsyncioTest(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) def tearDown(self): self.loop.close() self.loop = None asyncio.set_event_loop_policy(None) async def to_list(self, gen): res = [] async for i in gen: res.append(i) return res def test_async_gen_asyncio_01(self): async def gen(): yield 1 await asyncio.sleep(0.01) yield 2 await asyncio.sleep(0.01) return yield 3 res = self.loop.run_until_complete(self.to_list(gen())) self.assertEqual(res, [1, 2]) def test_async_gen_asyncio_02(self): async def gen(): yield 1 await asyncio.sleep(0.01) yield 2 1 / 0 yield 3 with self.assertRaises(ZeroDivisionError): self.loop.run_until_complete(self.to_list(gen())) def test_async_gen_asyncio_03(self): loop = self.loop class Gen: async def __aiter__(self): yield 1 await asyncio.sleep(0.01) yield 2 res = loop.run_until_complete(self.to_list(Gen())) self.assertEqual(res, [1, 2]) def test_async_gen_asyncio_anext_04(self): async def foo(): yield 1 await asyncio.sleep(0.01) try: yield 2 yield 3 except ZeroDivisionError: yield 1000 await asyncio.sleep(0.01) yield 4 async def run1(): it = foo().__aiter__() self.assertEqual(await it.__anext__(), 1) self.assertEqual(await it.__anext__(), 2) self.assertEqual(await it.__anext__(), 3) self.assertEqual(await it.__anext__(), 4) with self.assertRaises(StopAsyncIteration): await it.__anext__() with self.assertRaises(StopAsyncIteration): await it.__anext__() async def run2(): it = foo().__aiter__() self.assertEqual(await it.__anext__(), 1) self.assertEqual(await it.__anext__(), 2) try: it.__anext__().throw(ZeroDivisionError) except StopIteration as ex: self.assertEqual(ex.args[0], 1000) else: self.fail('StopIteration was not raised') self.assertEqual(await it.__anext__(), 4) with self.assertRaises(StopAsyncIteration): await it.__anext__() self.loop.run_until_complete(run1()) self.loop.run_until_complete(run2()) def test_async_gen_asyncio_anext_05(self): async def foo(): v = yield 1 v = yield v yield v * 100 async def run(): it = foo().__aiter__() try: it.__anext__().send(None) except StopIteration as ex: self.assertEqual(ex.args[0], 1) else: self.fail('StopIteration was not raised') try: it.__anext__().send(10) except StopIteration as ex: self.assertEqual(ex.args[0], 10) else: self.fail('StopIteration was not raised') try: it.__anext__().send(12) except StopIteration as ex: self.assertEqual(ex.args[0], 1200) else: self.fail('StopIteration was not raised') with self.assertRaises(StopAsyncIteration): await it.__anext__() self.loop.run_until_complete(run()) def test_async_gen_asyncio_anext_06(self): DONE = 0 # test synchronous generators def foo(): try: yield except: pass g = foo() g.send(None) with self.assertRaises(StopIteration): g.send(None) # now with asynchronous generators async def gen(): nonlocal DONE try: yield except: pass DONE = 1 async def run(): nonlocal DONE g = gen() await g.asend(None) with self.assertRaises(StopAsyncIteration): await g.asend(None) DONE += 10 self.loop.run_until_complete(run()) self.assertEqual(DONE, 11) def test_async_gen_asyncio_anext_tuple(self): async def foo(): try: yield (1,) except ZeroDivisionError: yield (2,) async def run(): it = foo().__aiter__() self.assertEqual(await it.__anext__(), (1,)) with self.assertRaises(StopIteration) as cm: it.__anext__().throw(ZeroDivisionError) self.assertEqual(cm.exception.args[0], (2,)) with self.assertRaises(StopAsyncIteration): await it.__anext__() self.loop.run_until_complete(run()) def test_async_gen_asyncio_anext_stopiteration(self): async def foo(): try: yield StopIteration(1) except ZeroDivisionError: yield StopIteration(3) async def run(): it = foo().__aiter__() v = await it.__anext__() self.assertIsInstance(v, StopIteration) self.assertEqual(v.value, 1) with self.assertRaises(StopIteration) as cm: it.__anext__().throw(ZeroDivisionError) v = cm.exception.args[0] self.assertIsInstance(v, StopIteration) self.assertEqual(v.value, 3) with self.assertRaises(StopAsyncIteration): await it.__anext__() self.loop.run_until_complete(run()) def test_async_gen_asyncio_aclose_06(self): async def foo(): try: yield 1 1 / 0 finally: await asyncio.sleep(0.01) yield 12 async def run(): gen = foo() it = gen.__aiter__() await it.__anext__() await gen.aclose() with self.assertRaisesRegex( RuntimeError, "async generator ignored GeneratorExit"): self.loop.run_until_complete(run()) def test_async_gen_asyncio_aclose_07(self): DONE = 0 async def foo(): nonlocal DONE try: yield 1 1 / 0 finally: await asyncio.sleep(0.01) await asyncio.sleep(0.01) DONE += 1 DONE += 1000 async def run(): gen = foo() it = gen.__aiter__() await it.__anext__() await gen.aclose() self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) def test_async_gen_asyncio_aclose_08(self): DONE = 0 fut = asyncio.Future(loop=self.loop) async def foo(): nonlocal DONE try: yield 1 await fut DONE += 1000 yield 2 finally: await asyncio.sleep(0.01) await asyncio.sleep(0.01) DONE += 1 DONE += 1000 async def run(): gen = foo() it = gen.__aiter__() self.assertEqual(await it.__anext__(), 1) await gen.aclose() self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) # Silence ResourceWarnings fut.cancel() self.loop.run_until_complete(asyncio.sleep(0.01)) def test_async_gen_asyncio_gc_aclose_09(self): DONE = 0 async def gen(): nonlocal DONE try: while True: yield 1 finally: await asyncio.sleep(0.01) await asyncio.sleep(0.01) DONE = 1 async def run(): g = gen() await g.__anext__() await g.__anext__() del g gc_collect() # For PyPy or other GCs. await asyncio.sleep(0.1) self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) def test_async_gen_asyncio_aclose_10(self): DONE = 0 # test synchronous generators def foo(): try: yield except: pass g = foo() g.send(None) g.close() # now with asynchronous generators async def gen(): nonlocal DONE try: yield except: pass DONE = 1 async def run(): nonlocal DONE g = gen() await g.asend(None) await g.aclose() DONE += 10 self.loop.run_until_complete(run()) self.assertEqual(DONE, 11) def test_async_gen_asyncio_aclose_11(self): DONE = 0 # test synchronous generators def foo(): try: yield except: pass yield g = foo() g.send(None) with self.assertRaisesRegex(RuntimeError, 'ignored GeneratorExit'): g.close() # now with asynchronous generators async def gen(): nonlocal DONE try: yield except: pass yield DONE += 1 async def run(): nonlocal DONE g = gen() await g.asend(None) with self.assertRaisesRegex(RuntimeError, 'ignored GeneratorExit'): await g.aclose() DONE += 10 self.loop.run_until_complete(run()) self.assertEqual(DONE, 10) def test_async_gen_asyncio_aclose_12(self): DONE = 0 async def target(): await asyncio.sleep(0.01) 1 / 0 async def foo(): nonlocal DONE task = asyncio.create_task(target()) try: yield 1 finally: try: await task except ZeroDivisionError: DONE = 1 async def run(): gen = foo() it = gen.__aiter__() await it.__anext__() await gen.aclose() self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) def test_async_gen_asyncio_asend_01(self): DONE = 0 # Sanity check: def sgen(): v = yield 1 yield v * 2 sg = sgen() v = sg.send(None) self.assertEqual(v, 1) v = sg.send(100) self.assertEqual(v, 200) async def gen(): nonlocal DONE try: await asyncio.sleep(0.01) v = yield 1 await asyncio.sleep(0.01) yield v * 2 await asyncio.sleep(0.01) return finally: await asyncio.sleep(0.01) await asyncio.sleep(0.01) DONE = 1 async def run(): g = gen() v = await g.asend(None) self.assertEqual(v, 1) v = await g.asend(100) self.assertEqual(v, 200) with self.assertRaises(StopAsyncIteration): await g.asend(None) self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) def test_async_gen_asyncio_asend_02(self): DONE = 0 async def sleep_n_crash(delay): await asyncio.sleep(delay) 1 / 0 async def gen(): nonlocal DONE try: await asyncio.sleep(0.01) v = yield 1 await sleep_n_crash(0.01) DONE += 1000 yield v * 2 finally: await asyncio.sleep(0.01) await asyncio.sleep(0.01) DONE = 1 async def run(): g = gen() v = await g.asend(None) self.assertEqual(v, 1) await g.asend(100) with self.assertRaises(ZeroDivisionError): self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) def test_async_gen_asyncio_asend_03(self): DONE = 0 async def sleep_n_crash(delay): fut = asyncio.ensure_future(asyncio.sleep(delay), loop=self.loop) self.loop.call_later(delay / 2, lambda: fut.cancel()) return await fut async def gen(): nonlocal DONE try: await asyncio.sleep(0.01) v = yield 1 await sleep_n_crash(0.01) DONE += 1000 yield v * 2 finally: await asyncio.sleep(0.01) await asyncio.sleep(0.01) DONE = 1 async def run(): g = gen() v = await g.asend(None) self.assertEqual(v, 1) await g.asend(100) with self.assertRaises(asyncio.CancelledError): self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) def test_async_gen_asyncio_athrow_01(self): DONE = 0 class FooEr(Exception): pass # Sanity check: def sgen(): try: v = yield 1 except FooEr: v = 1000 yield v * 2 sg = sgen() v = sg.send(None) self.assertEqual(v, 1) v = sg.throw(FooEr) self.assertEqual(v, 2000) with self.assertRaises(StopIteration): sg.send(None) async def gen(): nonlocal DONE try: await asyncio.sleep(0.01) try: v = yield 1 except FooEr: v = 1000 await asyncio.sleep(0.01) yield v * 2 await asyncio.sleep(0.01) # return finally: await asyncio.sleep(0.01) await asyncio.sleep(0.01) DONE = 1 async def run(): g = gen() v = await g.asend(None) self.assertEqual(v, 1) v = await g.athrow(FooEr) self.assertEqual(v, 2000) with self.assertRaises(StopAsyncIteration): await g.asend(None) self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) def test_async_gen_asyncio_athrow_02(self): DONE = 0 class FooEr(Exception): pass async def sleep_n_crash(delay): fut = asyncio.ensure_future(asyncio.sleep(delay), loop=self.loop) self.loop.call_later(delay / 2, lambda: fut.cancel()) return await fut async def gen(): nonlocal DONE try: await asyncio.sleep(0.01) try: v = yield 1 except FooEr: await sleep_n_crash(0.01) yield v * 2 await asyncio.sleep(0.01) # return finally: await asyncio.sleep(0.01) await asyncio.sleep(0.01) DONE = 1 async def run(): g = gen() v = await g.asend(None) self.assertEqual(v, 1) try: await g.athrow(FooEr) except asyncio.CancelledError: self.assertEqual(DONE, 1) raise else: self.fail('CancelledError was not raised') with self.assertRaises(asyncio.CancelledError): self.loop.run_until_complete(run()) self.assertEqual(DONE, 1) def test_async_gen_asyncio_athrow_03(self): DONE = 0 # test synchronous generators def foo(): try: yield except: pass g = foo() g.send(None) with self.assertRaises(StopIteration): g.throw(ValueError) # now with asynchronous generators async def gen(): nonlocal DONE try: yield except: pass DONE = 1 async def run(): nonlocal DONE g = gen() await g.asend(None) with self.assertRaises(StopAsyncIteration): await g.athrow(ValueError) DONE += 10 self.loop.run_until_complete(run()) self.assertEqual(DONE, 11) def test_async_gen_asyncio_athrow_tuple(self): async def gen(): try: yield 1 except ZeroDivisionError: yield (2,) async def run(): g = gen() v = await g.asend(None) self.assertEqual(v, 1) v = await g.athrow(ZeroDivisionError) self.assertEqual(v, (2,)) with self.assertRaises(StopAsyncIteration): await g.asend(None) self.loop.run_until_complete(run()) def test_async_gen_asyncio_athrow_stopiteration(self): async def gen(): try: yield 1 except ZeroDivisionError: yield StopIteration(2) async def run(): g = gen() v = await g.asend(None) self.assertEqual(v, 1) v = await g.athrow(ZeroDivisionError) self.assertIsInstance(v, StopIteration) self.assertEqual(v.value, 2) with self.assertRaises(StopAsyncIteration): await g.asend(None) self.loop.run_until_complete(run()) def test_async_gen_asyncio_shutdown_01(self): finalized = 0 async def waiter(timeout): nonlocal finalized try: await asyncio.sleep(timeout) yield 1 finally: await asyncio.sleep(0) finalized += 1 async def wait(): async for _ in waiter(1): pass t1 = self.loop.create_task(wait()) t2 = self.loop.create_task(wait()) self.loop.run_until_complete(asyncio.sleep(0.1)) # Silence warnings t1.cancel() t2.cancel() with self.assertRaises(asyncio.CancelledError): self.loop.run_until_complete(t1) with self.assertRaises(asyncio.CancelledError): self.loop.run_until_complete(t2) self.loop.run_until_complete(self.loop.shutdown_asyncgens()) self.assertEqual(finalized, 2) def test_async_gen_asyncio_shutdown_02(self): messages = [] def exception_handler(loop, context): messages.append(context) async def async_iterate(): yield 1 yield 2 it = async_iterate() async def main(): loop = asyncio.get_running_loop() loop.set_exception_handler(exception_handler) async for i in it: break asyncio.run(main()) self.assertEqual(messages, []) def test_async_gen_asyncio_shutdown_exception_01(self): messages = [] def exception_handler(loop, context): messages.append(context) async def async_iterate(): try: yield 1 yield 2 finally: 1/0 it = async_iterate() async def main(): loop = asyncio.get_running_loop() loop.set_exception_handler(exception_handler) async for i in it: break asyncio.run(main()) message, = messages self.assertEqual(message['asyncgen'], it) self.assertIsInstance(message['exception'], ZeroDivisionError) self.assertIn('an error occurred during closing of asynchronous generator', message['message']) def test_async_gen_asyncio_shutdown_exception_02(self): messages = [] def exception_handler(loop, context): messages.append(context) async def async_iterate(): try: yield 1 yield 2 finally: 1/0 async def main(): loop = asyncio.get_running_loop() loop.set_exception_handler(exception_handler) async for i in async_iterate(): break asyncio.run(main()) message, = messages self.assertIsInstance(message['exception'], ZeroDivisionError) self.assertIn('unhandled exception during asyncio.run() shutdown', message['message']) def test_async_gen_expression_01(self): async def arange(n): for i in range(n): await asyncio.sleep(0.01) yield i def make_arange(n): # This syntax is legal starting with Python 3.7 return (i * 2 async for i in arange(n)) async def run(): return [i async for i in make_arange(10)] res = self.loop.run_until_complete(run()) self.assertEqual(res, [i * 2 for i in range(10)]) def test_async_gen_expression_02(self): async def wrap(n): await asyncio.sleep(0.01) return n def make_arange(n): # This syntax is legal starting with Python 3.7 return (i * 2 for i in range(n) if await wrap(i)) async def run(): return [i async for i in make_arange(10)] res = self.loop.run_until_complete(run()) self.assertEqual(res, [i * 2 for i in range(1, 10)]) def test_asyncgen_nonstarted_hooks_are_cancellable(self): # See https://bugs.python.org/issue38013 messages = [] def exception_handler(loop, context): messages.append(context) async def async_iterate(): yield 1 yield 2 async def main(): loop = asyncio.get_running_loop() loop.set_exception_handler(exception_handler) async for i in async_iterate(): break asyncio.run(main()) self.assertEqual([], messages) def test_async_gen_await_same_anext_coro_twice(self): async def async_iterate(): yield 1 yield 2 async def run(): it = async_iterate() nxt = it.__anext__() await nxt with self.assertRaisesRegex( RuntimeError, r"cannot reuse already awaited __anext__\(\)/asend\(\)" ): await nxt await it.aclose() # prevent unfinished iterator warning self.loop.run_until_complete(run()) def test_async_gen_await_same_aclose_coro_twice(self): async def async_iterate(): yield 1 yield 2 async def run(): it = async_iterate() nxt = it.aclose() await nxt with self.assertRaisesRegex( RuntimeError, r"cannot reuse already awaited aclose\(\)/athrow\(\)" ): await nxt self.loop.run_until_complete(run()) def test_async_gen_aclose_twice_with_different_coros(self): # Regression test for https://bugs.python.org/issue39606 async def async_iterate(): yield 1 yield 2 async def run(): it = async_iterate() await it.aclose() await it.aclose() self.loop.run_until_complete(run()) def test_async_gen_aclose_after_exhaustion(self): # Regression test for https://bugs.python.org/issue39606 async def async_iterate(): yield 1 yield 2 async def run(): it = async_iterate() async for _ in it: pass await it.aclose() self.loop.run_until_complete(run()) def test_async_gen_aclose_compatible_with_get_stack(self): async def async_generator(): yield object() async def run(): ag = async_generator() asyncio.create_task(ag.aclose()) tasks = asyncio.all_tasks() for task in tasks: # No AttributeError raised task.get_stack() self.loop.run_until_complete(run()) if __name__ == "__main__": unittest.main()