ÿØÿà 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ÿÙ bs*4ddlZddlZddlZddlZddlZddlZddlmZddlm Z m Z m Z m Z ddl mZmZmZddlmZmZmZmZmZmZmZmZddlmZddlmZmZdZd Z d Z!d Z"d Z#Gd de$Z%dZ&dZ'dZ(dZ)ide*de*de*de*de*de*de*de*de*de*de*de*de*d e*d!e*d"e*d#e*e*e*e*e*e*e*d$Z+d%Z,d&Z-d'Z.d(Z/d)Z0d]d+Z1d,Z2d-Z3d.Z4d/Z5d0Z6d1Z7d2Z8d3Z9d4Z:d5Z;d6Zd9Z?d:Z@d;ZAd<ZBd=ZCd>ZDd?ZEd@ZFdAZGdBZHdCZIdDZJdEZKdFZLdGZMdHZNdIZOdJZPdKZQdLZRdMZSdNZTdOZUdPZVGdQdRZWGdSdTeWe e e ZXeXZYGdUdVZZGdWdXZ[GdYdZej\Z]Gd[d\eXZ^dS)^N)chain) CoreCommandsRedisModuleCommandsSentinelCommands list_or_args)ConnectionPool SSLConnectionUnixDomainSocketConnection)ConnectionErrorExecAbortError ModuleError PubSubError RedisError ResponseError TimeoutError WatchErrorLock)safe_str str_if_bytesEMPTY_RESPONSE NEVER_DECODEc|sdS t|}n#t$rYdSwxYwtj|S)z5Converts a unix timestamp to a Python datetime objectN)int ValueErrordatetime fromtimestampresponses ./usr/lib/python3/dist-packages/redis/client.pytimestamp_to_datetimer"$sZ tx== tt   * *8 4 44s  $$c\t||SN)dictfromkeyssplit) key_stringcallbacks r!string_keys_to_dictr*/s" ==))++X 6 66rc\eZdZdZdZfdZfdZfdZd fd ZfdZ fd Z xZ S) CaseInsensitiveDictz?Case insensitive dict implementation. Assumes string keys only.ch|D]\}}|||<dSr$)itemsupper)selfdatakvs r!__init__zCaseInsensitiveDict.__init__6s:JJLL  DAqDOO  rcjt|Sr$)super __contains__r/r0r2 __class__s r!r7z CaseInsensitiveDict.__contains__:s#ww##AGGII...rcnt|dSr$)r6 __delitem__r/r8s r!r;zCaseInsensitiveDict.__delitem__=s) AGGII&&&&&rcjt|Sr$)r6 __getitem__r/r8s r!r=zCaseInsensitiveDict.__getitem__@s#ww""17799---rNclt||Sr$)r6getr/)r0r2defaultr9s r!r?zCaseInsensitiveDict.getCs#ww{{17799g...rcpt||dSr$)r6 __setitem__r/)r0r2r3r9s r!rBzCaseInsensitiveDict.__setitem__Fs+ AGGIIq)))))rcht|}t|dSr$)r,r6update)r0r1r9s r!rDzCaseInsensitiveDict.updateIs,"4(( trr$) __name__ __module__ __qualname____doc__r4r7r;r=r?rBrD __classcell__r9s@r!r,r,3sEE   /////'''''.....//////*****rr,ct|}d|z}td|D}d}|D]}||vrt||||<|S)zDParse the results of Redis's DEBUG OBJECT command into a Python dictztype:c3@K|]}|dVdS:Nr').0kvs r! z%parse_debug_object..Ts,==bBHHSMM======r)refcountserializedlengthlrulru_seconds_idle)rr%r'r)r int_fieldsfields r!parse_debug_objectrYNs~H%%H!H==HNN,<,<=====HMJ33 H  !(5/22HUO Orc,|dvrt|S|S)z&Parse the results of an OBJECT command)idletimerS) int_or_none)r infotypes r! parse_objectr^`s!+++8$$$ Orci}t|}fd|D]}|r|ds|ddkr|dd\}}|dkr|dd\}}|dkr3|dg||||<|d g||S) z;Parse the result of Redis's INFO command into a Python dictcd|vsd|vr5 d|vrt|St|S#t$r|cYSwxYwi}|dD])}|dd\}}|||<*|S)N,=.)floatrrr'rsplit)valuesub_dictitemr2r3 get_values r!rjzparse_info..get_valuels e  s%// %<< <<'u::%     H C(( + +{{3**1'ill Os-- <<#rNrd cmdstat_hostmodulemodules__raw__)r splitlines startswithfindr'rf setdefaultappend)r infolinekeyrgrjs @r! parse_inforygs/ DH%%H ##%%<<  <,, <yy~~##"ZZQ// U.((!%S!!4!4JC(??OOIr2299))E:J:JKKKK ) % 0 0DII 2..55d;;; Krc t|dd}|D]/\}}|drt|dd||<0|S)z!Parse the results of MEMORY STATST) decode_keysdecode_string_valueszdb.) pairs_to_dictr.rr)r kwargsstatsrxrgs r!parse_memory_statsrsl (4 P P PEkkmm U >>%  &4dE#J Lrzcan-failover-its-masterz config-epochzdown-after-millisecondszfailover-timeoutz info-refreshzlast-hello-messagezlast-ok-ping-replyzlast-ping-replyzlast-ping-sentzmaster-link-down-timez master-portznum-other-sentinelsz num-slavesz o-down-timezpending-commandszparallel-syncsport)quorumzrole-reported-timez s-down-timezslave-priorityzslave-repl-offsetzvoted-leader-epochct|t}t|dd}dD] \}}||v||< |S)Nflagsra)) is_mastermaster)is_slaveslave)is_sdowns_down)is_odowno_down) is_sentinelsentinel)is_disconnected disconnected)is_master_down master_down)pairs_to_dict_typedSENTINEL_STATE_TYPESsetr')riresultrnameflags r!parse_sentinel_staters\ '; < z7parse_sentinel_slaves_and_sentinels..s+ O O Od \4!8!8 9 9 O O Orrrs r!#parse_sentinel_slaves_and_sentinelsrs O Oh O O OOrcD|r|dt|dfpdSNrrdrrs r!parse_sentinel_get_masterrs'  7!c(1+&6&67 ?4?rFc,|iS|s|ra|ddd}|rtt|}|ddd}|rtt|}tt||St |}tt||S)z-Create a dict given a list of key/value pairsNrd)rrr%zipiter)r r{r|keysvaluesits r!r}r}s  !* !!}  +|T**D!$Q$  /v..FCf%%&&& (^^CBKK   rct|}i}t||D]1\}}||vr# |||}n#t$rYnwxYw|||<2|Sr$)rr Exception)r type_inforrrxrgs r!rrs hB F"bkk U )   & #u--    s Ms> A  A c |r|ds|S|dt}t|}tt |t ||S)zr If ``withscores`` is specified in the options, return the response as a list of (value, score) pairs withscoresscore_cast_func)r?rerlistrr)r optionsrrs r!zset_score_pairsrse 7;;|44kk"3U;;O hB BOR0011 2 22rc r|dsS|dttfdtDS)z If ``groups`` is specified, return the response as a list of n-element tuples with n being the value found in options['groups'] groupsc&g|] }|dSr$r)rPinr s r!rz&sort_return_tuples..s#777hqt!tn777r)r?rrrange)r rrs` @r!sort_return_tuplesr sa 7;;x00A 77777eAhh7778 9 99rc(|dSt|Sr$rrs r!r\r\st x==rc|dSg}|D]J}|1||dt|df5|dK|S)Nrrd)NN)rur})r r1rs r!parse_stream_listrsjt D && = KK1}QqT223 4 4 4 4 KK % % % % Krc$t|dS)NTr{r}rs r!pairs_to_dict_with_str_keysr(s t 4 4 44rcFttt|Sr$)rrrrs r!parse_list_of_dictsr,s /:: ; ;;rc P|ddr|St|S)N parse_justidFr?rr rs r! parse_xclaimr0s+{{>5)) X & &&rc r|ddr|dSt|d|d<|S)NrFrdrrs r!parse_xautoclaimr6s<{{>5)){#HQK00HQK Orc Rt|d}|ddsU|d}| |dt|df|d<|d}| |dt|df|d<n*d |d D|d <d |d D|d <|S) NTrfullFz first-entryrrdz last-entryc4i|]\}}|t|Srr)rP_identrys r! z&parse_xinfo_stream..Gs&WWWe3 e 4 4WWWrentriesc0g|]}t|dS)Trr)rPgroups r!rz&parse_xinfo_stream..Hs2   7.Qs. > > >QqT$QqT** + > > >rrrs r! parse_xreadrNs! > >X > > >>rc |ddrt|Sd|dpgD}|d|d|d|dS) N parse_detailFc8g|]\}}|t|dS))rpendingr)rPrps r!rz"parse_xpending..Ws*NNNDAq!A//NNNrrrdr)rminmax consumers)r?parse_xpending_range)r rrs r!parse_xpendingrTsi{{>5)).#H---NNHQK.bs' . . .DQOO . . .rr)r r2s @r!rr`s"MA . . . .X . . ..rc(|dSt|Sr$rers r! float_or_nonerest ??rc(t|dkSNOKrrs r!bool_okrks  ! !T ))rc p|dS|drt|St|S)Nas_score)r?rerrs r! parse_zaddros9t{{:X x==rc g}t|D]A}|td|dDB|S)Nc3BK|]}|ddVdS)rbrdNrO)rPpairs r!rRz$parse_client_list..{s0HH4DJJsA..HHHHHHr )rrqrur%r')r rclientscs r!parse_client_listrwsgG ( # # . . 0 0JJtHH1773<<HHHHHIIII Nrc @d|D}|rt|piS)Nc4g|]}|t|ndSr$r)rPrs r!rz$parse_config_get..s&MMMq1= QdMMMrrrs r!parse_config_getrs-MMHMMMH  / h// 525rc .|\}}t||fSr$rr rcursorrs r! parse_scanr sIFA v;;>rc P|\}}t||rt|pifSr$)rr}rs r! parse_hscanr s.IFA v;;.mA..4" 44rc |dt}|\}}t|}t|t t |t ||fS)Nr)r?rerrrrr)r rrr rrs r! parse_zscanrsWkk"3U;;OIFA aB v;;SS"%=%=>>?? ??rc d|DS)Nc4g|]}|t|ndSr$r)rPscores r!rz!parse_zmscore..s' N N NEE-E%LLL4 N N Nrrrs r! parse_zmscorers N NX N N NNrc `|ddrdndfdfd|DS)Ndecode_responsesFr c2|dt|dt|dd}t|dtr|d|d<n)|d|d<|d|d<|S) Nrrdr)id start_timedurationrcommand complexity)r isinstancerjoin)rirspaces r! parse_itemz%parse_slowlog_get..parse_itemsQs47||TRSWVV d1gt $ $ 4 % 47 3 3F9  #'7F< % 47 3 3F9  rc&g|] }|Srr)rPrir s r!rz%parse_slowlog_get..s# 2 2 2JJt   2 2 2r)r?)r rr rs @@r!parse_slowlog_getr"sV;;1599 CCCtE      3 2 2 2 2 2 22rc |ddrt|S|ddrz|ddrd|dD}nd|dD}t|d|t|d t|d iSt|S) a Parse the response from `STRALGO` command. Without modifiers the returned value is string. When LEN is given the command returns the length of the result (i.e integer). When IDX is given the command returns a dictionary with the LCS length and all the ranges in both the strings, start and end offset for each string, where there are matches. When WITHMATCHLEN is given, each array representing a match will also have the length of the match at the beginning of the array. lenFidx withmatchlenc g|]C}t|dgttt|ddzDS)rlN)rrrtuplerPmatchs r!rz!parse_stralgo..sTeBi.."T#eU3B3Z*@*@%A%AArrdcRg|]$}ttt|%Sr)rrr(r)s r!rz!parse_stralgo..s*HHH5tCu--..HHHrrrr)r?rr)r rmatchess r! parse_stralgor-s{{5%  8}}{{5%   ;;~u - - I%a[GG IHHQKHHHG ! % %w ! % %s8A;'7'7    ! !!rc vt|}td|DS)Nc3DK|]}||dVdSrMrO)rPrws r!rRz%parse_cluster_info..s1JJDTJ 3JJJJJJr)rr%rqrs r!parse_cluster_infor0s8H%%H JJH,?,?,A,AJJJ J JJrc N|d}|ddd\}}}}}}}} |dd}||||||gg| dkrdndd } t|d kr%t|dd\} } | | c| d <| d <|| fS) Nr@r connectedTF) node_idr master_idlast_ping_sentlast_pong_rcvdepochslots migrationsr4 r:r;)r'r$ _parse_slots) rw line_itemsr5addrrr6pingpongr9r4 node_dictr:r;s r!_parse_node_linerCsCJDHJJsOOTVUVTVDWAGT5)T4 ::c??1 D&+55TT5  I :!(ABB88z6;Z3 'Il3 ?rcgg}}|D]}d|vr;|dddd\}}|||ddAd|vr;|dddd\}}|||ddd|d D}||||fS) Nz->-rdrl migrating)slotr5rz-<- importingcg|]}|Srr)rPsls r!rz _parse_slots..s777br777r-)r'ru) slot_rangesr:r;s_rangeslot_id dst_node_id src_node_ids r!r=r=s B:E " " G  #*1R4=#6#6ua#@#@ G[    [;OO    g  #*1R4=#6#6ua#@#@ G[    [;OO    87GMM#$6$6777G LL ! ! ! ! * rc t|ttfr|}t d|DS)z @see: https://redis.io/commands/cluster-nodes # string / bytes @see: https://redis.io/commands/cluster-replicas # list of string / bytes c3NK|] }tt|V!dSr$)rCr)rPnodes r!rRz&parse_cluster_nodes..s3JJ d!3!344JJJJJJr)rstrbytesrqr%rs r!parse_cluster_nodesrUsH (S%L)))&&(( JJJJJ J JJrc dsdr|St|tkr|g}n|}dsds ds|Stdtddgfd d Dz fd |DS) z Parse the response of 'GEOSEARCH', GEORADIUS' and 'GEORADIUSBYMEMBER' commands according to 'withdist', 'withhash' and 'withcoord' labels. store store_distwithdist withcoordwithhashcVt|dt|dfSrrlls r!z)parse_geosearch_generic..sr!uuRU|| <r)rYrZr[c|Sr$rxs r!r_z)parse_geosearch_generic..s1rc0g|]}| |Srr)rPocastrs r!rz+parse_geosearch_generic..s& O O OaGAJ O$q' O O Or)rYr[rZc hg|].}ttdt|/S)c0|d|dSrr)fvs r!r_z4parse_geosearch_generic...s1be r)rrr)rPrfs r!rz+parse_geosearch_generic..s7 Q Q QaD,,c!Qii88 9 9 Q Q Qr)typerrer)r r response_listreris ` @@r!parse_geosearch_genericrls w7<0 H~~!  : w{';GJDW<<  D  A O O O O O@ O O OOA Q Q Q Q= Q Q QQrc Zi}|D]}i}t|d}||d<t|d|d<d|dD|d<|d|d <|d |d <|d |d <t|dkr!|d|d<|d|d<|d|d<|||<|S)Nrrrdarityc,g|]}t|Srr)rPrs r!rz!parse_command..)s GGGD\$//GGGrrrr first_key_posr last_key_pos step_counttipsr2key_specificationsr< subcommands)rrr$)r rcommandsrcmd_dictcmd_names r! parse_commandr{"sH & & ++# OOGGGAJGGG$+AJ!#*1: !( w<.Rs7   2:D\8,, - -   rr3 categoriesonenabled) r}rrrrrSrTr'ru)r rr1rxrrs r!parse_acl_getuserr?s-t t 4 4 4D\4=99::DMStK/@AABBD#D$455D$v,$$C 4<(G(GCLf66<B;>O   [ rjH #))#..%% '>>   g & & & & OOG $ $ $ $D#Dd7m+DO Krc 2|dSt|trng}|D]h}t|dd}|dd}t ||d<t |d|d<||int|}|S)NTz client-inforz age-seconds)rrr}r?parse_client_inforerur)r rr1loglog_data client_infos r! parse_acl_logrdst(D!! ! " "C$S$55H",,}b99K&7 &D&DH] #',H],C&D&DH] # KK ! ! ! ! "x   Krci}t|d}|D]}|d\}}|||< dD]}t||||<|S)zg Parsing client-info in ACL Log in following format. "key1=value1 key2=value2 key3=value3" rrb>tot-memargv-mem qbuf-freedbrageoblollsubidleomempsubqbufmulti)rr'r)rgrinfosrvrxint_keys r!rrvs K    % %c * *E!!ZZ__ U C99 #;w#788 G rc4t|tr|dSNT)rr rs r!parse_module_resultrs(K(( 4rc Z|dr|S|ot|dkS)z Handle SET result since GET argument is available since Redis 6.2. Parsing SET result into: - BOOL - String when GET argument is used r?r)r?rrs r!parse_set_resultrs7{{5  6 X..$66rc <eZdZiedeedeedeeddedeedeede ed d ed d ed e eddede ede ede eddidddedededdddde ded e d!e d"d#d$ed%ed&ed'ed(ed)eid*e d+d,d-e d.ed/d0d1e d2e d3d4d5d6d7e d8e d9e d:e d;d<d=ed>d?d@e idAedBedCe dDe dEe dFe dGe dHedIedJedKdLdMedNe dOe dPedQe dRe idSe dTdUdVdWdXedYedZed[d\d]ed^ed_ed`e daedbe dceddededfdgeidhdidje dke dle!dmdndoedpe"dqdrdse dte duedve dwe dxe dye#dze$d{e%id|e d}e d~e de&de de&de'de(dede de"ddde)de*de dedee e+e+e,e-e.e/e0dZ1dS) AbstractRediszyAUTH COPY EXPIRE EXPIREAT PEXPIRE PEXPIREAT HEXISTS HMSET MOVE MSETNX PERSIST PSETEX RENAMENX SISMEMBER SMOVE SETEX SETNXaBITCOUNT BITPOS DECRBY DEL EXISTS GEOADD GETBIT HDEL HLEN HSTRLEN INCRBY LINSERT LLEN LPUSHX PFADD PFCOUNT RPUSHX SADD SCARD SDIFFSTORE SETBIT SETRANGE SINTERSTORE SREM STRLEN SUNIONSTORE UNLINK XACK XDEL XLEN XTRIM ZCARD ZLEXCOUNT ZREM ZREMRANGEBYLEX ZREMRANGEBYRANK ZREMRANGEBYSCOREzINCRBYFLOAT HINCRBYFLOATz LPUSH RPUSHcVt|tr|pt|dkSrrrs r!r_zAbstractRedis.s%jC((.QI,q//T2IrSORTzZSCORE ZINCRBY GEODISTz|FLUSHALL FLUSHDB LSET LTRIM MSET PFMERGE ASKING READONLY READWRITE RENAME SAVE SELECT SHUTDOWN SLAVEOF SWAPDB WATCH UNWATCH z BLPOP BRPOPc(|rt|pdSr$)r(rs r!r_zAbstractRedis.sq~U1XX7MrzSDIFF SINTER SMEMBERS SUNIONc@|rt|p tSr$)rrs r!r_zAbstractRedis.salCFF6KceerzSZPOPMAX ZPOPMIN ZINTER ZDIFF ZUNION ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCOREzBZPOPMIN BZPOPMAXcR|r$|d|dt|dfpdS)Nrrdrrrs r!r_zAbstractRedis.s)1+J!A$!eAaDkk1J+RdrzZRANK ZREVRANKzXREVRANGE XRANGEzXREAD XREADGROUPzBGREWRITEAOF BGSAVEcdSrrrs r!r_zAbstractRedis.strzACL CATcFttt|Sr$rrs r!r_zAbstractRedis.T#lA"6"677rz ACL DELUSERz ACL GENPASSz ACL GETUSERzACL HELPcFttt|Sr$rrs r!r_zAbstractRedis.d3|Q#7#788rzACL LISTcFttt|Sr$rrs r!r_zAbstractRedis.rrzACL LOADzACL LOGzACL SAVEz ACL SETUSERz ACL USERScFttt|Sr$rrs r!r_zAbstractRedis.stC a$8$899rz ACL WHOAMIzCLIENT GETNAMEz CLIENT IDz CLIENT KILLz CLIENT LISTz CLIENT INFOzCLIENT SETNAMEzCLIENT UNBLOCKc0|rt|dkpdS)NrdFrrs r!r_zAbstractRedis.sA$5#a&&A+$>rz CLIENT PAUSEzCLIENT GETREDIRzCLIENT TRACKINGINFOcFttt|Sr$rrs r!r_zAbstractRedis.sc,.B.B)C)CrzCLUSTER ADDSLOTSzCLUSTER ADDSLOTSRANGEzCLUSTER COUNT-FAILURE-REPORTSc t|Sr$rras r!r_zAbstractRedis.s 3q66rzCLUSTER COUNTKEYSINSLOTc t|Sr$rras r!r_zAbstractRedis.s SVVrzCLUSTER DELSLOTSzCLUSTER DELSLOTSRANGEzCLUSTER FAILOVERzCLUSTER FORGETzCLUSTER GETKEYSINSLOTcFttt|Sr$rrs r!r_zAbstractRedis.s4L!0D0D+E+Erz CLUSTER INFOzCLUSTER KEYSLOTc t|Sr$rras r!r_zAbstractRedis.s SVVrz CLUSTER MEETz CLUSTER NODESzCLUSTER REPLICASzCLUSTER REPLICATEz CLUSTER RESETzCLUSTER SAVECONFIGzCLUSTER SET-CONFIG-EPOCHzCLUSTER SETSLOTzCLUSTER SLAVESCOMMANDz COMMAND COUNTzCOMMAND GETKEYScFttt|Sr$rrs r!r_zAbstractRedis.sT#lA*>*>%?%?rz CONFIG GETzCONFIG RESETSTATz CONFIG SETz DEBUG OBJECTzFUNCTION DELETEzFUNCTION FLUSHzFUNCTION RESTOREGEOHASHcFttt|Sr$rrs r!r_zAbstractRedis. rrGEOPOSc>ttd|S)Nc^|*t|dt|dfndSrrr]s r!r_z(AbstractRedis... s(2>E"Q%LL%1,,77tr)rrrs r!r_zAbstractRedis. s"D SSUV W W  r GEOSEARCH GEORADIUSGEORADIUSBYMEMBERHGETALLc(|rt|piSr$rrs r!r_zAbstractRedis.sQ3=#3#39rrHSCANINFOLASTSAVEz MEMORY PURGEz MEMORY STATSz MEMORY USAGEz MODULE LOADz MODULE UNLOADz MODULE LISTcd|DS)Nc,g|]}t|Srr)rPms r!rz*AbstractRedis...s !>!>!>q-"2"2!>!>!>rrrs r!r_zAbstractRedis.s!>!>A!>!>!>rOBJECTPINGc(t|dkS)NPONGrrs r!r_zAbstractRedis.s,q//V3rQUITSTRALGOz PUBSUB NUMSUB RANDOMKEYc|r|pdSr$rrs r!r_zAbstractRedis.!sqwQ$rRESETSCAN SCRIPT EXISTScFttt|Sr$)rrboolrs r!r_zAbstractRedis.$s4D! #5#5rz SCRIPT FLUSHz SCRIPT KILL SCRIPT LOADzSENTINEL CKQUORUMzSENTINEL FAILOVERzSENTINEL FLUSHCONFIGz SENTINEL GET-MASTER-ADDR-BY-NAMEzSENTINEL MASTERzSENTINEL MASTERSzSENTINEL MONITORzSENTINEL RESETzSENTINEL REMOVEzSENTINEL SENTINELSz SENTINEL SETzSENTINEL SLAVESSETz SLOWLOG GETz SLOWLOG LENz SLOWLOG RESETSSCANTIMEcVt|dt|dfSrrras r!r_zAbstractRedis.9s3qt99c!A$ii0rXCLAIM XAUTOCLAIMz XGROUP CREATEzXGROUP DELCONSUMERzXGROUP DESTROY)z XGROUP SETIDzXINFO CONSUMERSz XINFO GROUPSz XINFO STREAMXPENDINGZADDZSCANZMSCOREN)2rErFrGr*rrrerrrrr\rrrrrrrrr0rUr{rrYrlr ryr"rrr^r-r}r rrrrrr"rrrrrrrrRESPONSE_CALLBACKSrrr!rrs\   :    \   >    \  8% @ @\    I I  !\*  f&8 9 9+\,  6 F F-\.   H   /\8  m-M-M N N9\:   *,K,K  ;\@   )   A\J   !R!R  K\P  . < >U\V  3^^ D DW\\X 77Y\Z s[\\ |]\^ (_\` 88a\b 88c\d Ge\f =g\h Gi\j wk\l 99m\n lo\p ,q\r Ss\t (u\v (w\x (y\\\z '{\| >>}\~ \@ 3A\B CCC\D GE\F G\H ()9)9I\J "#3#3K\L GM\N O\P GQ\R 'S\T !E!EU\V *W\X ++Y\Z [\\\\ ,]\^ /_\` Wa\b c\d ge\f #Gg\h 7i\j -k\l =m\n o\p ??q\r &s\t Gu\v gw\x *y\z 7{\| '}\\\~ G\@ 77A\B   C\H ,I\J ,K\L 4M\N 99O\P Q\R  S\T )U\V W\X *Y\Z  [\\ *]\^ ,_\` >>a\b ,c\\\d 33e\f g\h =i\j ,k\l ..m\n o\p  q\r 55s\t u\v ww\x |y\z W{\| W}\~ \@ +,EA\B 0C\D 2E\\\F GG\H 'I\J 7K\L AM\N O\P >Q\R S\T (U\V sW\X Y\Z [\\ 00]\^ ,_\` &a\b c\d ce\f $g\\h .+*" w\\\rrceZdZdZedZ d!d Zd Zd ZdZ dZ dZ d"dZ dZ d#dZdZdZdZdZdZdZdZdZdZdZd ZdS)$Redisa Implementation of the Redis protocol. This abstract class provides a Python interface to all Redis commands and an implementation of the Redis protocol. Pipelines derive from this, implementing how the commands are sent and received to the Redis server. Based on configuration, an instance will either use a ConnectionPool, or Connection object to talk to redis. c >tj|fi|}||S)a Return a Redis client object configured from the given URL For example:: redis://[[username]:[password]]@localhost:6379/0 rediss://[[username]:[password]]@localhost:6379/0 unix://[[username]:[password]]@/path/to/socket.sock?db=0 Three URL schemes are supported: - `redis://` creates a TCP socket connection. See more at: - `rediss://` creates a SSL wrapped TCP socket connection. See more at: - ``unix://``: creates a Unix Domain Socket connection. The username, password, hostname, path and all querystring values are passed through urllib.parse.unquote in order to replace any percent-encoded values with their corresponding characters. There are several ways to specify a database number. The first value found will be used: 1. A ``db`` querystring option, e.g. redis://localhost?db=0 2. If using the redis:// or rediss:// schemes, the path argument of the url, e.g. redis://localhost/0 3. A ``db`` keyword argument to this function. If none of these options are specified, the default db=0 is used. All querystring options are cast to their appropriate Python types. Boolean arguments can be specified with string values "True"/"False" or "Yes"/"No". Values that cannot be properly cast cause a ``ValueError`` to be raised. Once parsed, the querystring arguments and keyword arguments are passed to the ``ConnectionPool``'s class initializer. In the case of conflicting arguments, querystring arguments always win. )connection_pool)rfrom_url)clsurlr~rs r!rzRedis.from_urlWs0T)1#@@@@s?3333r localhostrNutf-8strictFrequiredc&| s| #tjtd| } |#tjtd|} |sg}|dur|t||#||| | ||t j|$||!|"|%d }&| |&| tdnE|&|||||d|r(|&t||||||||||||d td i|&} | |_ d|_ | r|j d |_ t|jj|_dS) a4 Initialize a new Redis client. To specify a retry policy for specific errors, first set `retry_on_error` to a list of the error/s to retry on, then set `retry` to a valid `Retry` object. To retry on TimeoutError, `retry_on_timeout` can also be set to `True`. Nz/"charset" is deprecated. Use "encoding" insteadz5"errors" is deprecated. Use "encoding_errors" insteadT) rusernamepasswordsocket_timeoutencodingencoding_errorsrretry_on_errorretrymax_connectionshealth_check_interval client_nameredis_connect_func)pathconnection_class)hostrsocket_connect_timeoutsocket_keepalivesocket_keepalive_options) r ssl_keyfile ssl_certfile ssl_cert_reqs ssl_ca_certs ssl_ca_datassl_check_hostname ssl_password ssl_ca_pathssl_validate_ocsp_stapledssl_validate_ocspssl_ocsp_contextssl_ocsp_expected_cert_r)warningswarnDeprecationWarningrurcopydeepcopyrDr r rr connectionget_connectionr,r9rresponse_callbacks)'r0rrrrrrrrrunix_socket_pathrrcharseterrorsrretry_on_timeoutrsslrrrr r r r r rrrrrsingle_connection_clientrrrrrr~s' r!r4zRedis.__init__s^H 7" &I #! &O #)! $!#4''%%l333$$"0$#2$4"0u--#2)>*&8F  + 0,F $ $2H,<4L MM0=+6,8-:,8+62D,8+69R1B0@6L"-66v66O. # G"2AA#FFDO"5dn6W"X"XrcZt|jdt|jdS)N<>)rjrEreprrr0s r!__repr__zRedis.__repr__s-t**%EET-A(B(BEEEErc4|jS)z!Get the connection pool's encoder)r get_encoderr%s r!r(zRedis.get_encoders#//111rc|jjS)z'Get the connection's key-word arguments)rconnection_kwargsr%s r!get_connection_kwargszRedis.get_connection_kwargs s#55rc||j|<dS)zSet a custom Response CallbackN)r)r0rr)s r!set_response_callbackzRedis.set_response_callbacks+3(((rc(t|||dS)a This function can be used to add externally defined redis modules, and their namespaces to the redis client. funcname - A string containing the name of the function to create func - The function, being added to this class. ex: Assume that one has a custom redis module named foomod that creates command named 'foo.dothing' and 'foo.anotherthing' in redis. To load function functions into this namespace: from redis import Redis from foomodule import F r = Redis() r.load_external_module("foo", F) r.foo().dothing('your', 'arguments') For a concrete example see the reimport of the redisjson module in tests/test_connection.py::test_loading_external_modules N)setattr)r0funcnamefuncs r!load_external_modulezRedis.load_external_modules* h%%%%%rTc:t|j|j||S)a_ Return a new pipeline object that can queue multiple commands for later execution. ``transaction`` indicates whether all commands should be executed atomically. Apart from making a group of operations atomic, pipelines are useful for reducing the back-and-forth overhead between the client and server. )Pipelinerr)r0 transaction shard_hints r!pipelinezRedis.pipeline)s%  $"9;    rc|dd}|dd}|dd}|d|5} |r |j|||}|} |r|n| cdddS#t$r||dkrt j|YhwxYw#1swxYwYdS)z Convenience method for executing the callable `func` as a transaction while watching all keys specified in `watches`. The 'func' callable should expect a single argument which is a Pipeline object. r6Nvalue_from_callableF watch_delayTr)popr7watchexecutertimesleep) r0r1watchesr~r6r9r:pipe func_value exec_values r!r5zRedis.transaction5s> ZZ d33 $jj)>FFjj55 ]]4 , ,   -" G,,!%dJ!%J)<L::*L        "".;?? ;///H          s0C0B&CCCCC  C 皙?c 8|t}||||||||S)aL Return a new Lock object using key ``name`` that mimics the behavior of threading.Lock. If specified, ``timeout`` indicates a maximum life for the lock. By default, it will remain locked until release() is called. ``sleep`` indicates the amount of time to sleep per loop iteration when the lock is in blocking mode and another client is currently holding the lock. ``blocking`` indicates whether calling ``acquire`` should block until the lock has been acquired or to fail immediately, causing ``acquire`` to return False and the lock not being acquired. Defaults to True. Note this value can be overridden by passing a ``blocking`` argument to ``acquire``. ``blocking_timeout`` indicates the maximum amount of time in seconds to spend trying to acquire the lock. A value of ``None`` indicates continue trying forever. ``blocking_timeout`` can be specified as a float or integer, both representing the number of seconds to wait. ``lock_class`` forces the specified lock implementation. Note that as of redis-py 3.0, the only lock class we implement is ``Lock`` (which is a Lua-based lock). So, it's unlikely you'll need this parameter, unless you have created your own custom lock class. ``thread_local`` indicates whether the lock token is placed in thread-local storage. By default, the token is placed in thread local storage so that a thread only sees its token, not a token set by another thread. Consider the following timeline: time: 0, thread-1 acquires `my-lock`, with a timeout of 5 seconds. thread-1 sets the token to "abc" time: 1, thread-2 blocks trying to acquire `my-lock` using the Lock instance. time: 5, thread-1 has not yet completed. redis expires the lock key. time: 5, thread-2 acquired `my-lock` now that it's available. thread-2 sets the token to "xyz" time: 6, thread-1 finishes its work and calls release(). if the token is *not* stored in thread local storage, then thread-1 would see the token value as "xyz" and would be able to successfully release the thread-2's lock. In some use cases it's necessary to disable thread local storage. For example, if you have code where one thread acquires a lock and passes that lock instance to a worker thread to release later. If thread local storage isn't disabled in this case, the worker thread won't see the token set by the thread that acquired the lock. Our assumption is that these cases aren't common and as such default to using thread local storage.N)timeoutr?blockingblocking_timeout thread_localr)r0rrFr?rGrH lock_classrIs r!lockz Redis.lockKs>|  Jz  -%    rc &t|jfi|S)z Return a Publish/Subscribe object. With this object, you can subscribe to channels and listen for messages that get published to them. )PubSubr)r0r~s r!pubsubz Redis.pubsubs d*55f555rc*t|jSr$)Monitorrr%s r!monitorz Redis.monitorst+,,,rc:||jdS)NT)rr )r9rr%s r!clientz Redis.clients%~~ 04   rc|Sr$rr%s r! __enter__zRedis.__enter__ rc.|dSr$closer0exc_type exc_value tracebacks r!__exit__zRedis.__exit__ rc.|dSr$rXr%s r!__del__z Redis.__del__r_rct|dsdS|j}|r#d|_|j|dSdS)Nr)hasattrrrreleaser0conns r!rYz Redis.closesXt\**  F  /"DO  ( ( . . . . . / /rc4|j||j||fi|S)z7 Send a command and parse the response ) send_commandparse_response)r0rf command_nameargsrs r!_send_command_parse_responsez"Redis._send_command_parse_responses1 4  "t"4AAAAArc||j$t|t|jdur|dS)z Close the connection and raise an exception if retry_on_error is not set or the error is not one of the specified error types NF) disconnectrrr(r0rferrors r!_disconnect_raisezRedis._disconnect_raisesK    '%t':!;!;<<EEKFErc j}djp |jfi jfdfdjs|SS#js|wwxYw)z.Execute a command and return a parsed responserc(jgRiSr$rlrkrjrfrr0sr!r_z'Redis.execute_command..s699,)-18rc0|Sr$)rqrprfr0s r!r_z'Redis.execute_command..sd44T5AAr)rrrrcall_with_retryrd)r0rkrpoolrjrfs``` @@r!execute_commandzRedis.execute_commands#Aw N"5$"5l"N"Ng"N"N #:--BAAAA ? # T"""" #4? # T"""" #s %A..B c t|vr|d}n|}n'#t$rt|vr|tcYSwxYw||jvr|j||fi|S|S)z'Parses a response from the Redis serverT)disable_decoding)r read_responserrr)r0rrjrr s r!rizRedis.parse_responses w&&%33T3JJ%3355   ((~....   42 2 284*<8MMWMM Ms47 AA)%rrrNNNNNNNrrNNFFNFNNrNNNFNFFNNNFrNNNN)TN)NrDTNNT)rErFrGrH classmethodrr4r&r(r+r-r2r7r5rKrNrQrSrUr^rarYrlrqrzrirrr!rrJs  *4*4[*4\  #!%    "'#!&M}Y}Y}Y}Y~FFF222666444&&&.     2H H H H T666---    / / /BBB   ###"     rrcpeZdZdZejdZejdZdZdZ dZ dZ dZ d S) rPz Monitor is useful for handling the MONITOR command to the redis server. next_command() method returns one command from monitor listen() method yields commands from monitor. z\[(\d+) (.*)\] (.*)z"(.*?)(?rclient_address client_port client_typer)rr}rrTencoderdecoder' monitor_rer*rr command_refindallreplacerrrfrer) r0r command_time command_datardb_idrrrrrs r! next_commandzMonitor.next_command sW?0022 h & & L.55hd5KKH%-^^C%;%;" l O ! !, / /&'hhjj#{G((4?227;;<<//%-- %  "NKKK  # #F + + #N%abb/K KK+6*<*.sGGT,V,,rc0|Sr$)rrws r!r_z!PubSub._execute..s$88uEEr)rrx)r0rfrrkr~s`````r!rzPubSub._executesDz)) , , , , , , E E E E E   rTrc$|j}|td||s|||j|sdS|||j}||r|xjdzc_dS|S)z3Parse the response from a publish/subscribe commandNNpubsub connection not set: did you forget to call subscribe() or psubscribe()?rrd)r RuntimeErrorrrrr}rr)r0blockrFrfr s r!rizPubSub.parse_responses <F   T]]4]PP 4==t'9::  ( ( 2 2   . .! 3 . .4rc"||j|jfvS)z Check if the response is a health check response. If there are no subscriptions redis responds to PING command with a bulk response, instead of a multi-bulk with "pong" and the response. )rrrs r!rzPubSub.is_health_check_responses"   &  (   rc|j}|td|jrKtj|jkr1|d|jd|xjdz c_dSdSdS)NrrF)rrd)rrrr>next_health_checkrhrrres r!rzPubSub.check_healths <F   % 4$)++8N*N*N   fd&?e  T T T  . .! 3 . . . . 4 4*N*Nrcx|jj|jjfd|DS)z normalize channel/pattern names to be either bytes or strings based on whether responses are automatically decoded. this saves us from coercing the value for each message coming in. c@i|]\}}||Srr)rPr2r3rrs r!rz*PubSub._normalize_keys..s1>>>Avvayy!!1>>>r)rrrr.)r0r1rrs @@r!_normalize_keyszPubSub._normalize_keyss? $$>>>>>>>>>rc|rt|d|dd}t|}|||jdg|R}||}|j||js |j d|_ |j ||S)aE Subscribe to channel patterns. Patterns supplied as keyword arguments expect a pattern name as the key and a callable as the value. A pattern's callable will be invoked automatically when a message is received on that pattern rather than producing a message via ``listen()``. rrdN PSUBSCRIBE)rr%r&rDrzrrrrrrrrdifference_update)r0rkr~ new_patternsret_vals r!rzPubSub.psubscribes  3Qabb22D}}T** F###&$&|Jl6G6G6I6IJJJ++L99  \*** 3  ! % % ' ' '12D . );;LIIIrc|rLt|d|dd}|t|}n|j}|j||jdg|RS)zj Unsubscribe from the supplied patterns. If empty, unsubscribe from all patterns. rrdN PUNSUBSCRIBE)rrr%r&rrrDrz)r0rkrs r!rzPubSub.punsubscribes  %Qabb22D++DMM$,?,?@@HH}H )00:::#t#N:T::::rc|rt|d|dd}t|}|||jdg|R}||}|j||js |j d|_ |j ||S)aR Subscribe to channels. Channels supplied as keyword arguments expect a channel name as the key and a callable as the value. A channel's callable will be invoked automatically when a message is received on that channel rather than producing a message via ``listen()`` or ``get_message()``. rrdN SUBSCRIBE)rr%r&rDrzrrrrrrrrr)r0rkr~ new_channelsrs r!rzPubSub.subscribe,s  3Qabb22D}}T** F###&$&{I\5F5F5H5HIII++L99  \*** 3  ! % % ' ' '12D . );;LIIIrc|rLt|d|dd}|t|}n|j}|j||jdg|RS)zi Unsubscribe from the supplied channels. If empty, unsubscribe from all channels rrdN UNSUBSCRIBE)rrr%r&rrrDrz)r0rkrs r!rzPubSub.unsubscribeFs  %Qabb22D++DMM$,?,?@@HH}H )00:::#t#M9D9999rc#K|jr8||d}||V|j6dSdS)zBListen for messages on channels this client has been subscribed toT)rN)rhandle_messagerirs r!rz PubSub.listenSsco **4+>+>T+>+J+JKKH#o     rc(|js[tj}|j|dur*tj|z }t d||z }ndS|d|}|r|||SdS)z Get the next message if one is available, otherwise None. If timeout is specified, the system will wait for `timeout` seconds before returning. Timeout should be specified as a floating point number. TgNF)rrF)rr>rwaitrrir)r0rrFr time_spentr s r! get_messagezPubSub.get_messageZs J$))'22d::"Y[[:5 c7Z#788t&&UG&DD  L&&x1JKK Ktrc:|dn|}|d|S)z' Ping the Redis server Nrrrz)r0rs r!r@z PubSub.pingus' ""W##FG444rc2|dSt|d}|dkr||d|d|dd}n'|dkr|dd|dd}n|d|d|dd}||jvr|d krG|d}||jvr5|j||j|dnF|d}||jvr5|j||j|d|js |js|j ||j vrY|dkr"|j |d d}n!|j |d d}|r ||dSn|dkr |s|j rdS|S) z Parses a pub/sub message. If the channel or pattern was subscribed to with a message handler, the handler is invoked instead of a parsed message being returned. Nrrrdrr)rjpatternchannelr1rArrr) rUNSUBSCRIBE_MESSAGE_TYPESrremoverr;rrrrPUBLISH_MESSAGE_TYPESr?r)r0r r message_typerrrhandlers r!rzPubSub.handle_message|s  4#HQK00 : % %$#A;#A;  GG V # #$  GG%#A;  G 49 9 9~--"1+d???5<EE-++GI,>EE    t V # #) D,J trc$|jD]\}}|td|d|jD]\}}|td|dt ||||}||S)Nz Channel: 'z' has no handler registeredz Pattern: ')daemonexception_handler)rr.rrPubSubWorkerThreadstart)r0 sleep_timerrrrrthreads r! run_in_threadzPubSub.run_in_threads $ 3 3 5 5 U U GW!"Sw"S"S"STTT $ 3 3 5 5 U U GW!"Sw"S"S"STTT$ *V?P      r)NFN)Tr)Frr$)F)rFN)!rErFrGrHrrrr4rUr^rarrYrpropertyrrzrrrrirrrrrrrrrr@rrrrr!rMrM6s4 ?2 "' 0 & & &((($..X.LLL($       *     4 4 4???4 ; ; ;4 : : :65555????B      rrMc,eZdZdfd ZdZdZxZS)rFNct||_||_||_||_t j|_dSr$) r6r4rrNrrrr_running)r0rNrrrr9s r!r4zPubSubWorkerThread.__init__sI   $!2!)) rc|jrdS|j|j}|j}|jrh |d|n6#t $r)}|j||||Yd}~nd}~wwxYw|jh|dS)NT)rrF) rrrrNrr BaseExceptionrrY)r0rNres r!runzPubSubWorkerThread.runs =   ! !  F _ m""$$ 8 8""T:"VVVV  8 8 8)1&&q&$77777777 8m""$$ 8  sA55 B(?B##B(c8|jdSr$)rrr%s r!stopzPubSubWorkerThread.stops r)FN)rErFrGr4rr rIrJs@r!rrs[******   rrceZdZdZhdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZddZdZdZdZdS)r4a_ Pipelines provide a way to transmit multiple commands to the Redis server in one transmission. This is convenient for batch processing, such as saving all the values in a list to Redis. All commands executed within a pipeline are wrapped with MULTI and EXEC calls. This guarantees all commands executed in the pipeline will be executed atomically. Any command raising an exception does *not* halt the execution of subsequent commands in the pipeline. Instead, the exception is caught and its instance is placed into the response list returned by execute(). Code iterating over the response list should be able to deal with an instance of an exception as a potential value. In general, these will be ResponseError exceptions, such as those raised when issuing a command on a key of a different datatype. >EXECDISCARDUNWATCHc||_d|_||_||_||_d|_|dS)NF)rrrr5r6watchingr)r0rrr5r6s r!r4zPipeline.__init__s@."4&$  rc|Sr$rr%s r!rUzPipeline.__enter__ rVrc.|dSr$rrZs r!r^zPipeline.__exit__ r_rcR |dS#t$rYdSwxYwr$rr%s r!razPipeline.__del__s:  JJLLLLL    DD rc*t|jSr$)r$ command_stackr%s r!__len__zPipeline.__len__s4%&&&rcdS)z1Pipeline instances should always evaluate to TrueTrr%s r!__bool__zPipeline.__bool__strcg|_t|_|jre|jr^ |jd|jn)#t$r|jYnwxYwd|_d|_ |jr(|j |jd|_dSdS)NrF) rrscriptsrrrhr}r rnexplicit_transactionrrdr%s r!rzPipeline.resetsuu  = -T_ - -,,Y777--////" - - -**,,,,, - $)! ? #  ( ( 9 9 9"DOOO # #s3A#BBcl|jrtd|jrtdd|_dS)z Start a transactional block of the pipeline after WATCH commands are issued. End the transactional block with `execute`. z"Cannot issue nested calls to MULTIz:Commands without an initial WATCH have already been issuedTN)rrrr%s r!rzPipeline.multi4sO  $ CABB B   O %)!!!rcj|js |ddkr|js |j|i|S|j|i|S)NrWATCH)rrimmediate_execute_commandpipeline_execute_command)r0rkr~s r!rzzPipeline.execute_commandAsS M CT!W//9R/1414B6BB B,t,d=f===rc||jr#|td|jrt |t s|dS)z Close the connection, reset watching state and raise an exception if we were watching, retry_on_timeout is not set, or the error is not a TimeoutError =A ConnectionError occurred on while watching one or more keysN)rnrrrrrrros r!_disconnect_reset_raisez Pipeline._disconnect_reset_raiseFsz  =  JJLLLR  % *UL*I*I  JJLLL   rcdjs'jj_jfdfdS)z Execute a command immediately, but don't auto-retry on a ConnectionError if we're already WATCHing a variable. Used when issuing WATCH or subsequent commands retrieving their values but before MULTI is called. rc(jgRiSr$rtrusr!r_z4Pipeline.immediate_execute_command..ks65D5l%)-4rc0|Sr$)r#rws r!r_z4Pipeline.immediate_execute_command..ns$66tUCCr)rrrr6rrx)r0rkrrjrfs```@@r!rz"Pipeline.immediate_execute_command\sAw  #'66|T_UUD"DOz))         D C C C C    rc>|j||f|S)ar Stage a command to be executed when execute() is next called Returns the current Pipeline object back so commands can be chained together, such as: pipe = pipe.set('foo', 'bar').incr('baz').decr('bang') At some other point, you can then run: pipe.execute(), which will execute all commands queued in the pipe. )rru)r0rkrs r!r z!Pipeline.pipeline_execute_commandqs$ !!4/222 rctdifg|difg}|d|D}||g} ||dn.#t$r!}|d|fYd}~nd}~wwxYwt |D]\}} t| dvr)||| dtf= ||dU#t$rA}|||dz| d|||fYd}~d}~wwxYw ||d} n#t$r|r|ddwxYwd|_ | td|D]\}}| ||t| t|kr(|jt d |r||| g} t#| |D]Y\} } t%| t&s*| \}}|d}||jvr|j|| fi|} | | Z| S) N)MULTI)r c*g|]\}}t|v|Sr)r)rPrkrs r!rz1Pipeline._execute_transaction..s& M M MmdG~W/L/LT/L/L/LrrrrdFzWatched variable changed.z6Wrong number of response items from pipeline execution)r pack_commandssend_packed_commandrirru enumeraterannotate_exceptionr rrinsertr$rrnraise_first_errorrrrr)r0rrxraise_on_errorcmdsall_cmdsrrrrr r1rcmdrkrrjs r!_execute_transactionzPipeline._execute_transactionsz2&'YO3DEE++ M Mt M M M   &&x000  "    C 0 0 0 0 " " " MM1a& ! ! ! ! ! ! ! ! "$H-- * *JAw++ q'!*^"<=>>>>*'' C8888$***++Aq1ugajAAAMM1a&))))))))*  **:s;;HH    #Qil"     899 9 " "DAq OOAq ! ! ! ! x==CMM ) ) O & & ( ( (K   7  " "8X 6 6 6(H--  FAsa++ L # g#Aw 4#:::=/ =aKK7KKA KKNNNN s<A&& B0B  B!C88 E7D>>EEE:c\|d|D}||g}|D]Z\}} ||j||dfi|/#t$r}||Yd}~Sd}~wwxYw|r||||S)Ncg|]\}}|Srr)rPrkrs r!rz.Pipeline._execute_pipeline..s,J,J,JgdAT,J,J,Jrr)r+r,rurirr0) r0rrxr1r3r rkrrs r!_execute_pipelinezPipeline._execute_pipelines++,J,J,J,J,JKK&&x000% # #MD' # 3 3JQ S S7 S STTTT  # # #"""""""" #  7  " "8X 6 6 6s(A(( B2B  Bct|D]B\}}t|tr(|||dz||d|CdS)Nrdr)r-rrr.)r0rxr rrs r!r0zPipeline.raise_first_errorsgh''  DAq!]++ ''1q5(1+a.AAA   rcdtt|}d|d|d|jd}|f|jddz|_dS)Nrz Command # z (z) of pipeline caused error: rrd)rrrrk)r0 exceptionnumberrr4msgs r!r.zPipeline.annotate_exceptionsrhhs8W--.. 1 1 13 1 1&^A. 1 1 )."44 rc jtj|||fi|}||jvrd|_n |dkrd|_|S)NFrT)rriUNWATCH_COMMANDSr)r0rrjrrs r!rizPipeline.parse_responsesL%dJ PPPP 40 0 0!DMM W $ $ DM rct|j}|j}d|D}|dg|R}t|s.t ||D]\}}|s|d|j|_dSdS)Ncg|] }|j Sr)sha)rPss r!rz)Pipeline.load_scripts..s'''!'''rrr)rrrallrscriptrB)r0r immediateshasexistsrCexists r! load_scriptszPipeline.load_scriptsst|$$2 ''w'''?2T2226{{ ?00 ? ?5?%ImQX>>AE ? ? ? ?rc||jrtd|jrt |t s|dS)z Close the connection, raise an exception if we were watching, and raise an exception if retry_on_timeout is not set, or the error is not a TimeoutError r"N)rnrrrrrrros r!_disconnect_raise_resetz Pipeline._disconnect_raise_resetsm  = R  % *UL*I*I  JJLLL   rTcjs jsgSjrjsjrjnjjs'j dj _ j fdfdS#wxYw)z0Execute all the commands in the current pipeliner)cSr$r)rfr=r1stacksr!r_z"Pipeline.execute..se^<<rc0|Sr$)rLrws r!r_z"Pipeline.execute.. sd::4GGr)rrrrJr5rr5r8rrrr6rrxr)r0r1rfr=rOs``@@@r!r=zPipeline.execute s" T] I <         -t8 -/GG,G #'66wPPD#DO :--<<<<<<<GGGGG JJLLLLDJJLLLLs $B::Cc0|ddS)zg Flushes all previously queued commands See: https://redis.io/commands/DISCARD r Nrr%s r!discardzPipeline.discard%s Y'''''rcJ|jrtd|jdg|RS)z$Watches the values at keys ``names``z"Cannot issue a WATCH after a MULTIr)rrrz)r0namess r!r<zPipeline.watch,s8  $ CABB B#t#G4e4444rc>|jr|dpdS)z'Unwatches all previously specified keysrT)rrzr%s r!unwatchzPipeline.unwatch2s"}@!5!5i!@!@HDHrN)T)rErFrGrHr?r4rUr^rarrrrrzr#rr r5r8r0r.rirJrLr=rRr<rVrrr!r4r4s$655 '''###. ) ) )>>> ,   *   AAAF  555 ? ? ?(6(((555 IIIIIrr4)FF)_rrrrr>r itertoolsrredis.commandsrrrrredis.connectionrr r redis.exceptionsr r r rrrrr redis.lockr redis.utilsrr SYM_EMPTYrrr"r*r%r,rYr^ryrrrrrrrrr}rrrr\rrrrrrrrrrrrrrr r rrr"r-r0rCr=rUrlr{r}rrrrrrrr StrictRedisrPrMThreadrr4rrr!r`s    WVVVVVVVVV                    ........  ! 555777$6$)))XsCs  C  # #scS33#3 c!" C#$/6    ===PPP@@@!!!!&    3 3 3:::   555<<<''' "???   ///  ***666  555 @@@OOO 333$""":KKK *(KKKRRRB&555*** """J$@ 7 7 7]]]]]]]]@cccccM. >NcccL  @&@&@&@&@&@&@&@&FSSSSSSSSl )>IIIIIIIIIIuIIIIIIIIIIr