ó
    ùÞ j×ƒ ã            
       ó²  • S SK r S SKrS SKrS SKrS SKrS SKJr  S SKJr  S SK	J
r
JrJrJrJrJrJr  S SKJrJr  S SKJr  S SKJr  S SKJrJrJrJr  S S	KJrJrJ r   S S
K!J"r"J#r#  S SK$J%r%  S SK&J'r'J(r(J)r)  S SK*J+r+J,r,  S SK-J.r.J/r/J0r0J1r1  S SK2J3r3J4r4J5r5J6r6J7r7J8r8J9r9J:r:J;r;J<r<J=r=J>r>J?r?J@r@JArA  S SKBJCrC  S SKDJErE  S SKFJGrGJHrHJIrIJJrJJKrKJLrLJMrM  S\NS\\N\O4   S\N4S jrP\H" S/SSS9S 5       rQS rRS rSS\
S\
S\\\O\O4   \\N\
4   4   4S  jrTS! rUS" rVS#rWS$rXS%rYS&rZS'r[S( r\ " S) S*\(5      r] " S+ S,5      r^ " S- S.\^\#5      r_ " S/ S05      r` " S1 S2\5      ra " S3 S45      rb " S5 S65      rc " S7 S8\5      rd " S9 S:\_5      reS;\NS\S<\
4   4S= jrfS>rg\g H3  rh\hRÓ                  S?S@5      RÕ                  5       rh\k" \e\h\f" \h5      5        M5      " SA SB5      rl " SC SD5      rmg)Eé    N)ÚOrderedDict)ÚEnum)ÚAnyÚCallableÚDictÚListÚOptionalÚTupleÚUnion)ÚCommandsParserÚEncoder)Ú
parse_scan)Údefault_backoff)ÚCacheConfigÚCacheFactoryÚCacheFactoryInterfaceÚCacheInterface)ÚCaseInsensitiveDictÚPubSubÚRedis)ÚREAD_COMMANDSÚRedisClusterCommands)Úlist_or_args)ÚConnectionPoolÚDefaultParserÚ	parse_url)ÚREDIS_CLUSTER_HASH_SLOTSÚkey_slot)Ú(AfterPooledConnectionsInstantiationEventÚ'AfterPubSubConnectionInstantiationEventÚ
ClientTypeÚEventDispatcher)ÚAskErrorÚAuthenticationErrorÚClusterCrossSlotErrorÚClusterDownErrorÚClusterErrorÚConnectionErrorÚ	DataErrorÚMasterDownErrorÚ
MovedErrorÚRedisClusterExceptionÚ
RedisErrorÚResponseErrorÚSlotNotCoveredErrorÚTimeoutErrorÚTryAgainError©ÚLock)ÚRetry)ÚHIREDIS_AVAILABLEÚdeprecated_argsÚ
dict_mergeÚlist_keys_to_dictÚmerge_resultÚsafe_strÚstr_if_bytesÚhostÚportÚreturnc                 ó   • U  SU 3$ )NÚ:© ©r<   r=   s     ÚG/var/www/html/gaurav/venv/lib/python3.13/site-packages/redis/cluster.pyÚget_node_namerD   7   s   € ØˆV�1�T�FÐÐó    Ú
redis_nodez&Use get_connection(redis_node) insteadú5.3.0)Úallowed_argsÚreasonÚversionc                 ó\   • U R                   =(       d    U R                  R                  5       $ ©N)Ú
connectionÚconnection_poolÚget_connection)rF   ÚargsÚoptionss      rC   rO   rO   ;   s$   € ð × Ñ ×O J×$>Ñ$>×$MÑ$MÓ$OÐOrE   c                 ón   • 0 n/ nUR                  5        H  u  pV[        U40 UD6u  pxXsU'   XH-  nM     X44$ rL   )Úitemsr   )	ÚcommandÚresrQ   ÚcursorsÚretÚ	node_nameÚresponseÚcursorÚrs	            rC   Úparse_scan_resultr\   D   sI   € Ø€GØ
€CØ"Ÿy™yž{Ñˆ	Ü˜xÑ3¨7Ñ3‰	ˆØ#�	ÑØ‰Šñ  +ð
 ˆ<ÐrE   c                 óö   • [        5       nUR                  5        H  nU H  u  pV X5==   U-  ss'   M     M     UR                  5        VVs/ sH  u  pWXW4PM
     nnnU$ ! [         a    XcU'    MQ  f = fs  snnf rL   )r   ÚvaluesÚKeyErrorrS   )	rT   rU   rQ   Únumsub_dÚnumsub_tupsÚchannelÚ	numsubbedÚnumsubÚ
ret_numsubs	            rC   Úparse_pubsub_numsubrf   O   s‚   € Ü‹}€HØ—z‘z–|ˆÛ"-ÑˆGð.ØÓ! YÑ.Õ!ó #.ñ $ð <D¿>¹>Ô;KÔLÑ;K©¨�7Ó#Ñ;K€JÑLØÐøô	 ó .Ø$-˜Ô!ð.üó Ms   ¦A ÁA5Á A2Á1A2ÚresprQ   c                 óä   ^
• UR                  SS5      m
S[        S[        [        [        4   4U
4S jjn0 nU  H.  nUS S u  pVnUSS  nU" U6 U V	s/ sH  o’" U	6 PM	     sn	S.X5U4'   M0     U$ s  sn	f )NÚcurrent_hostÚ rP   r>   c                  ó<   >• [        U S   5      =(       d    TU S   4$ ©Nr   é   )r;   )rP   ri   s    €rC   Ú
fix_serverÚ'parse_cluster_slots.<locals>.fix_servera   s    ø€ Ü˜D ™GÓ$×4¨°d¸1±gÐ=Ð=rE   é   )ÚprimaryÚreplicas)Úgetr   r
   Ústr)rg   rQ   rn   ÚslotsÚslotÚstartÚendrq   rr   Úreplicari   s             @rC   Úparse_cluster_slotsrz   \   s–   ø€ ð —;‘;˜~¨rÓ2€Lð>œ#ð >¤%¬¬S¨¡/÷ >ð €EÛˆØ" 2 A˜hÑˆ�GØ˜˜�8ˆá! 7Ð+Ù=EÓF¹X°'˜ WÓ-¹XÑFñ
ˆ�SˆjÓñ ð €Lùò Gs   ÁA-c                 ó   • [        U S   [        5      (       a  U $ / nU  H«  n/ / S.n[        S[        US   5      S5       H(  nUS   R	                  US   U   US   US-      45        M*     US   nU HB  n0 n[        S[        U5      S5       H  nXuS-      X‡U   '   M     US   R	                  U5        MD     UR	                  U5        M­     U$ )z 
Parse CLUSTER SHARDS response.
r   )ru   Únodesrm   é   ru   rp   r|   )Ú
isinstanceÚdictÚrangeÚlenÚappend)	rg   rQ   ÚshardsÚxÚshardÚir|   ÚnodeÚ	dict_nodes	            rC   Úparse_cluster_shardsr‰   p   sá   € ô �$�q‘'œ4× Ñ ØˆØ€FÛˆØ rÑ*ˆÜ�qœ#˜a ™d›) QÖ'ˆAØ�'‰N×!Ñ! 1 Q¡4¨¡7¨Q¨q©T°!°a±%©[Ð":Ö;ñ (à�!‘ˆÛˆDØˆIÜ˜1œc $›i¨Ö+�Ø%)¨a©%¡[�	˜q™'Ó"ñ ,à�'‰N×!Ñ! )Ö,ñ	 ð
 	�‰�eÖñ ð €MrE   c                 ó$   • U R                  S5      $ )z#
Parse CLUSTER MYSHARDID response.
úutf-8)Údecode)rg   rQ   s     rC   Úparse_cluster_myshardidr�   †   s   € ð �;‰;�wÓÐrE   rq   ry   zslot-id)&ÚcharsetÚconnection_classrN   Úconnection_pool_classÚclient_nameÚcredential_providerÚdbÚdecode_responsesÚencodingÚencoding_errorsÚerrorsr<   Úlib_nameÚlib_versionÚmax_connectionsÚ
nodes_flagÚredis_connect_funcÚpasswordr=   Úqueue_classÚretryÚretry_on_timeoutÚprotocolÚsocket_connect_timeoutÚsocket_keepaliveÚsocket_keepalive_optionsÚsocket_timeoutÚsslÚssl_ca_certsÚssl_ca_dataÚssl_certfileÚssl_cert_reqsÚssl_keyfileÚssl_passwordÚunix_socket_pathÚusernameÚcacheÚcache_configrB   c                  óˆ   • U R                  5        VVs0 sH  u  pU[        ;   d  M  U[        ;  d  M  X_M!     nnnU$ s  snnf )z1
Remove unsupported or disabled keys from kwargs
)rS   ÚREDIS_ALLOWED_KEYSÚKWARGS_DISABLED_KEYS)ÚkwargsÚkÚvÚconnection_kwargss       rC   Úcleanup_kwargsr¸   ¼   sT   € ð —L‘L”Nôá"‰DˆAØÔ"Ñ"ó 	à'(Ô0DÑ'Dó 	ˆŠÙ"ð ñ ð Ðùós   ”>§>³>c            
       óH   • \ rS rSr\" \R                  \\\	\
\\S.5      rSrg)ÚClusterParseréÉ   )ÚASKÚTRYAGAINÚMOVEDÚCLUSTERDOWNÚ	CROSSSLOTÚ
MASTERDOWNrA   N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__r7   r   ÚEXCEPTION_CLASSESr#   r1   r+   r&   r%   r*   Ú__static_attributes__rA   rE   rC   rº   rº   É   s-   † Ù"Ø×'Ñ'àØ%ØØ+Ø.Ø)ñ	
ó
ÓrE   rº   c                   óž  • \ rS rSrSrSrSrSrSrSr	\\\\\	1r
\" \" / SQ\	5      \" / S	Q\5      \" S
/\5      \" / SQ\5      5      r/ SQ4r\\\S.r\" \" SS/\5      \" S/S 5      \" / SQ\5      \" / SQS 5      \" SS/S 5      \" S/S 5      \" S/\5      \" S/S 5      \" S/S 5      \" S/S  5      5
      r\\\\4rS$S%S" jjrS#rg!)&ÚAbstractRedisClusteré×   é   Ú	primariesrr   ÚallÚrandomzdefault-node)WzACL CATzACL DELUSERz
ACL DRYRUNzACL GENPASSzACL GETUSERzACL HELPzACL LISTzACL LOGzACL LOADzACL SAVEzACL SETUSERz	ACL USERSz
ACL WHOAMIÚAUTHúCLIENT LISTzCLIENT SETINFOúCLIENT SETNAMEúCLIENT GETNAMEú
CONFIG SETúCONFIG REWRITEúCONFIG RESETSTATÚTIMEúPUBSUB CHANNELSúPUBSUB NUMPATúPUBSUB NUMSUBúPUBSUB SHARDCHANNELSúPUBSUB SHARDNUMSUBÚPINGÚINFOÚSHUTDOWNÚKEYSÚDBSIZEÚBGSAVEúSLOWLOG GETúSLOWLOG LENúSLOWLOG RESETÚWAITÚWAITAOFÚSAVEúMEMORY PURGEzMEMORY MALLOC-STATSzMEMORY STATSÚLASTSAVEzCLIENT TRACKINGINFOúCLIENT PAUSEúCLIENT UNPAUSEúCLIENT UNBLOCKz	CLIENT IDzCLIENT REPLYzCLIENT GETREDIRzCLIENT INFOúCLIENT KILLÚREADONLYzCLUSTER INFOzCLUSTER MEETúCLUSTER MYSHARDIDzCLUSTER NODESzCLUSTER REPLICASzCLUSTER RESETzCLUSTER SET-CONFIG-EPOCHúCLUSTER SLOTSúCLUSTER SHARDSzCLUSTER COUNT-FAILURE-REPORTSzCLUSTER KEYSLOTÚCOMMANDzCOMMAND COUNTzCOMMAND LISTzCOMMAND GETKEYSú
CONFIG GETÚDEBUGÚ	RANDOMKEYrî   Ú	READWRITErÖ   zTFUNCTION LOADzTFUNCTION DELETEzTFUNCTION LISTÚTFCALLÚTFCALLASYNCzGRAPH.CONFIGzLATENCY HISTORYzLATENCY LATESTzLATENCY RESETzMODULE LISTzMODULE LOADzMODULE UNLOADzMODULE LOADEX)ÚFLUSHALLÚFLUSHDBzFUNCTION DELETEzFUNCTION FLUSHzFUNCTION LISTzFUNCTION LOADzFUNCTION RESTOREzREDISGEARS_2.REFRESHCLUSTERÚSCANúSCRIPT EXISTSúSCRIPT FLUSHúSCRIPT LOADzFUNCTION DUMP)zCLUSTER COUNTKEYSINSLOTzCLUSTER DELSLOTSzCLUSTER DELSLOTSRANGEzCLUSTER GETKEYSINSLOTzCLUSTER SETSLOT)z	FT.CREATEz	FT.SEARCHzFT.AGGREGATEz
FT.EXPLAINzFT.EXPLAINCLIz
FT,PROFILEzFT.ALTERzFT.DROPINDEXzFT.ALIASADDzFT.ALIASUPDATEzFT.ALIASDELz
FT.TAGVALSz	FT.SUGADDz	FT.SUGGETz	FT.SUGDELz	FT.SUGLENzFT.SYNUPDATEz
FT.SYNDUMPzFT.SPELLCHECKz
FT.DICTADDz
FT.DICTDELzFT.DICTDUMPzFT.INFOzFT._LISTz	FT.CONFIGzFT.ADDzFT.DELzFT.DROPzFT.GETzFT.MGETz	FT.SYNADD)rð   rñ   rï   rÙ   rÛ   rØ   c                 óF   • [        [        UR                  5       5      5      $ rL   )ÚsumÚlistr^   ©rT   rU   s     rC   Ú<lambda>ÚAbstractRedisCluster.<lambda>Š  s   € ´C¼¸S¿Z¹Z»\Ó8JÔ4KrE   )rß   r×   rÚ   )rÜ   rÓ   rÔ   rÕ   rÑ   rá   rä   rç   rè   rê   rë   c                 ób   • [        U[        5      (       a  [        UR                  5       5      $ U$ rL   )r~   r   rÍ   r^   r  s     rC   r  r  �  ó$   € ´jÀÄd×6KÑ6K¤ S§Z¡Z£\Ó!2Ð!TÐQTÐ!TrE   rà   rå   c                 ób   • [        U[        5      (       a  [        UR                  5       5      $ U$ rL   )r~   r   r   r^   r  s     rC   r  r  ¡  r  rE   rì   c                 óD   • [        UR                  5       5      S:”  a  S$ S$ rl   )r   r^   r  s     rC   r  r  ¤  s   € ¼#¸c¿j¹j»lÓ:KÈaÓ:O°QÐ5VÐUVÐ5VrE   rû   rþ   c                 óP   • [        UR                  5       5      R                  5       $ rL   )r  r^   Úpopr  s     rC   r  r  ¨  s   € ´$°s·z±z³|Ó2D×2HÑ2HÔ2JrE   rü   c                 ój   • [        UR                  5       6  Vs/ sH  n[        U5      PM     sn$ s  snf rL   )Úzipr^   rÍ   )rT   rU   rµ   s      rC   r  r  «  s'   € ÄSÈ#Ï*É*Ë,ÑEWÓ4XÑEWÀ´S¸¶VÑEWÒ4XùÒ4Xs   ™0rý   c                 ó4   • [        UR                  5       5      $ rL   )rÍ   r^   r  s     rC   r  r  ­  s   € ÄÀSÇZÁZÃ\ÔARrE   Nc                 ó´  • U(       a  XR                   l        gU R                  5       nU R                  5        Vs/ sH  o3U:w  d  M
  UPM     nnU(       a&  [        R
                  " U5      U R                   l        gU R                  5        Vs/ sH  o3U:w  d  M
  UPM     nnU(       a&  [        R
                  " U5      U R                   l        ggs  snf s  snf )aG  Replace the default cluster node.
A random cluster node will be chosen if target_node isn't passed, and primaries
will be prioritized. The default node will not be changed if there are no other
nodes in the cluster.

Args:
    target_node (ClusterNode, optional): Target node to replace the default
    node. Defaults to None.
N)Únodes_managerÚdefault_nodeÚget_default_nodeÚget_primariesrÎ   ÚchoiceÚget_replicas)ÚselfÚtarget_nodeÚ	curr_noder‡   rÌ   rr   s         rC   Úreplace_default_nodeÚ)AbstractRedisCluster.replace_default_node·  s°   € ö Ø.9×ÑÕ+à×-Ñ-Ó/ˆIØ*.×*<Ñ*<Ô*>ÓTÑ*> $È)ÑBSŸÑ*>ˆIÐTÞä28·-²-À	Ó2J�×"Ñ"Õ/ð .2×->Ñ->Ô-@ÓVÑ-@ TÈIÑDUŸDÑ-@�ÐVÞÜ6<·m²mÀHÓ6M�D×&Ñ&Õ3ð ùò Uùò Ws   »CÁCÂCÂCrA   rL   )r  ÚClusterNoder>   N)rÂ   rÃ   rÄ   rÅ   ÚRedisClusterRequestTTLÚ	PRIMARIESÚREPLICASÚ	ALL_NODESÚRANDOMÚDEFAULT_NODEÚ
NODE_FLAGSr7   r8   ÚSLOT_IDÚCOMMAND_FLAGSÚSEARCH_COMMANDSrz   r‰   r�   Ú#CLUSTER_COMMANDS_RESPONSE_CALLBACKSrf   r9   r\   ÚRESULT_CALLBACKSr(   r0   r&   r/   ÚERRORS_ALLOW_RETRYr  rÇ   rA   rE   rC   rÉ   rÉ   ×   s‹  † ØÐà€IØ€HØ€IØ€FØ!€Là˜X y°&¸,ÐG€JáÙòXðr óu[	
ñx 	òð ó	
ñ" 	˜?Ð+¨VÓ4Ùòð ó		
ó_y€Mòx 	
ð"€OðJ -Ø.Ø4ñ+Ð'ñ "Ù˜?Ð,@ÐAÐCVÓWÙØÐÑKó	
ñ 	Ú?Àó	
ñ 	òñ Uó	
ñ  	Ø�vÐÙTó	
ñ 	ØÐÑ Vó	
ñ 	˜6˜(Ð$5Ó6ÙØˆOÑJó	
ñ 	ØÐÑXó	
ñ 	˜>Ð*Ñ,RÓSóM'ÐðT 	ØØØð	Ð÷Nñ NrE   rÉ   c            !       ó   • \ rS rSr\S 5       r\" S/SSS9               S@S\\   S	\	S
\\
S      S\	S\S   S\S\	S\S\S   S\S\\   S\\\\\	4   /\\\	4   4      S\\   S\\   S\\   4S jj5       rS rS rS rS rS rS rSAS  jrS! rS" rS# rS$ rSBS% jrS& rS' rS(\S   4S) jr SCS* jr!SDS+ jr"SAS, jr#SES- jr$      SFS. jr%S/ r&S(\
S   4S0 jr'S1 r(S2 r)S3 r*S4 r+S5 r,S6 r-S7 r.S8 r/S9 r0S: r1S; r2SGS< jr3S= r4S> r5S?r6g)HÚRedisClusteriÐ  c                 ó   • U " SSU0UD6$ )a5  
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@]/path/to/socket.sock?db=0[&password=password]

Three URL schemes are supported:

- `redis://` creates a TCP socket connection. See more at:
  <https://www.iana.org/assignments/uri-schemes/prov/redis>
- `rediss://` creates a SSL wrapped TCP socket connection. See more at:
  <https://www.iana.org/assignments/uri-schemes/prov/rediss>
- ``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.

ÚurlrA   rA   )Úclsr+  r´   s      rC   Úfrom_urlÚRedisCluster.from_urlÑ  s   € ñT Ñ%�sÐ%˜fÑ%Ð%rE   Úread_from_replicasz6Please configure the 'load_balancing_strategy' insteadrG   ©Úargs_to_warnrI   rJ   Nr<   r=   Ústartup_nodesr  Úcluster_error_retry_attemptsrŸ   r4   Úrequire_full_coverageÚreinitialize_stepsÚload_balancing_strategyÚLoadBalancingStrategyÚdynamic_startup_nodesr+  Úaddress_remapr¯   r°   Úevent_dispatcherc                 ó   • Uc  / nSU;   a  [        S5      eSnUb‡  Sn[        U5      nSU;   a  [        S5      eSU;   a  US   S:w  a  [        S	5      eUR                  U5        UR                  S
5      nUR                  SU5      nUR	                  [        X5      5        O;Ub  Ub  UR	                  [        X5      5        O[        U5      S:X  a  [        S5      eUR                  SS5      U l        UR                  SU R                  05        [        S0 UD6nU(       a$  XPl        UR                  SU R                  05        O%UR                  S[        [        5       S5      05        [        UR                  SS5      UR                  SS5      UR                  SS5      5      U l        UR                  SS5      nU(       d  U(       a  US;  a  [!        S5      eX@l        U R$                  R&                  R)                  5       U l        U R$                  R,                  R)                  5       U l        X€l        X�l        SU l        Xpl        Uc  [9        5       U l        OXðl        [=        SUUUU
UUUU R:                  S.UD6U l        [A        U R$                  RB                  5      U l"        [A        U R$                  RF                  5      U l$        [K        U 5      U l&        [N        RP                  " 5       U l)        g)a  
 Initialize a new RedisCluster client.

 :param startup_nodes:
     List of nodes from which initial bootstrapping can be done
 :param host:
     Can be used to point to a startup node
 :param port:
     Can be used to point to a startup node
 :param require_full_coverage:
    When set to False (default value): the client will not require a
    full coverage of the slots. However, if not all slots are covered,
    and at least one node has 'cluster-require-full-coverage' set to
    'yes,' the server will throw a ClusterDownError for some key-based
    commands. See -
    https://redis.io/topics/cluster-tutorial#redis-cluster-configuration-parameters
    When set to True: all slots must be covered to construct the
    cluster client. If not all slots are covered, RedisClusterException
    will be thrown.
:param read_from_replicas:
     @deprecated - please use load_balancing_strategy instead
     Enable read from replicas in READONLY mode. You can read possibly
     stale data.
     When set to true, read commands will be assigned between the
     primary and its replications in a Round-Robin manner.
:param load_balancing_strategy:
     Enable read from replicas in READONLY mode and defines the load balancing
     strategy that will be used for cluster node selection.
     The data read from replicas is eventually consistent
     with the data in primary nodes.
:param dynamic_startup_nodes:
     Set the RedisCluster's startup nodes to all of the discovered nodes.
     If true (default value), the cluster's discovered nodes will be used to
     determine the cluster nodes-slots mapping in the next topology refresh.
     It will remove the initial passed startup nodes if their endpoints aren't
     listed in the CLUSTER SLOTS output.
     If you use dynamic DNS endpoints for startup nodes but CLUSTER SLOTS lists
     specific IP addresses, it is best to set it to false.
:param cluster_error_retry_attempts:
     Number of times to retry before raising an error when
     :class:`~.TimeoutError` or :class:`~.ConnectionError` or
     :class:`~.ClusterDownError` are encountered
:param reinitialize_steps:
    Specifies the number of MOVED errors that need to occur before
    reinitializing the whole cluster topology. If a MOVED error occurs
    and the cluster does not need to be reinitialized on this current
    error handling, only the MOVED slot will be patched with the
    redirected node.
    To reinitialize the cluster on every MOVED error, set
    reinitialize_steps to 1.
    To avoid reinitializing the cluster on moved errors, set
    reinitialize_steps to 0.
:param address_remap:
    An optional callable which, when provided with an internal network
    address of a node, e.g. a `(host, port)` tuple, will return the address
    where the node is reachable.  This can be used to map the addresses at
    which the nodes _think_ they are, to addresses at which a client may
    reach them, such as when they sit behind a proxy.

 :**kwargs:
     Extra arguments that will be sent into Redis instance when created
     (See Official redis-py doc for supported kwargs
 [https://github.com/andymccurdy/redis-py/blob/master/redis/client.py])
     Some kwargs are not supported and will raise a
     RedisClusterException:
         - db (Redis do not support database SELECT in cluster mode)
Nr“   z4Argument 'db' is not possible to use in cluster modeFTÚpathzFRedisCluster does not currently support Unix Domain Socket connectionsr   z9A ``db`` querystring option can only be 0 in cluster moder<   r=   a5  RedisCluster requires at least one node to discover the cluster. Please provide one of the followings:
1. host and port, for example:
 RedisCluster(host='localhost', port=6379)
2. list of startup nodes, for example:
 RedisCluster(startup_nodes=[ClusterNode('localhost', 6379), ClusterNode('localhost', 6378)])rœ   rŸ   r•   r‹   r–   Ústrictr”   r¡   )rp   Ú3z4Client caching is only supported with RESP version 3)r2  r-  r4  r8  r9  r¯   r°   r:  rA   )*r,   r   Úupdaters   r‚   r  r�   r
  Úuser_on_connect_funcÚ
on_connectr¸   rŸ   r4   r   r   Úencoderr-   r3  Ú	__class__r#  ÚcopyÚcommand_flagsr!  Ú
node_flagsr/  r6  Úreinitialize_counterr5  r"   Ú_event_dispatcherÚNodesManagerr  r   r%  Úcluster_response_callbacksr&  Úresult_callbacksr   Úcommands_parserÚ	threadingr3   Ú_lock)r  r<   r=   r2  r3  rŸ   r4  r5  r/  r6  r8  r+  r9  r¯   r°   r:  r´   r-  Úurl_optionsr¡   s                       rC   Ú__init__ÚRedisCluster.__init__ý  sÆ  € ðv Ñ ØˆMà�6‹>ä'ØFóð ð
 ˆØ‰?ØˆHÜ# C›.ˆKØ˜Ó$Ü+ð)óð ð �{Ó" {°4Ñ'8¸AÓ'=ä+ØOóð ð �M‰M˜+Ô&Ø—:‘:˜fÓ%ˆDØ—:‘:˜f dÓ+ˆDØ× Ñ ¤¨TÓ!8Õ9ØÑ $Ñ"2Ø× Ñ ¤¨TÓ!8Õ9Ü�Ó 1Ó$ä'ð4óð ð %+§J¡JÐ/CÀTÓ$JˆÔ!Ø�‰Ð+¨T¯_©_Ð=Ô>ÜÑ) &Ñ)ˆÞØŒJØ�M‰M˜7 D§J¡JÐ/Õ0à�M‰M˜7¤E¬/Ó*;¸QÓ$?Ð@ÔAäØ�J‰J�z 7Ó+Ø�J‰JÐ(¨(Ó3Ø�J‰JÐ)¨5Ó1ó
ˆŒð
 —:‘:˜j¨$Ó/ˆÞžE x°xÓ'?ÜÐSÓTÐTà,HÔ)Ø!Ÿ^™^×9Ñ9×>Ñ>Ó@ˆÔØŸ.™.×3Ñ3×8Ñ8Ó:ˆŒØ"4ÔØ'>Ô$Ø$%ˆÔ!Ø"4ÔØÑ#Ü%4Ó%6ˆDÕ"à%5Ô"Ü)ð 

Ø'ØØ"7Ø"7Ø'ØØ%Ø!×3Ñ3ñ

ð ñ

ˆÔô +>Ø�N‰N×>Ñ>ó+
ˆÔ'ô !4°D·N±N×4SÑ4SÓ TˆÔä-¨dÓ3ˆÔÜ—^’^Ó%ˆ�
rE   c                 ó   • U $ rL   rA   ©r  s    rC   Ú	__enter__ÚRedisCluster.__enter__·  s   € ØˆrE   c                 ó$   • U R                  5         g rL   ©Úclose©r  Úexc_typeÚ	exc_valueÚ	tracebacks       rC   Ú__exit__ÚRedisCluster.__exit__º  ó   € Ø�
‰
�rE   c                 ó$   • U R                  5         g rL   rW  rS  s    rC   Ú__del__ÚRedisCluster.__del__½  r_  rE   c                 óÄ   • U R                  5        H;  nUR                  (       d  M   UR                  R                  R                  5         M=     g ! [         a     MM  f = frL   )Ú	get_nodesÚredis_connectionrN   Ú
disconnectÚOSError©r  r‡   s     rC   Údisconnect_connection_poolsÚ(RedisCluster.disconnect_connection_poolsÀ  sP   € Ø—N‘NÖ$ˆDØ×$×$Ñ$ðØ×)Ñ)×9Ñ9×DÑDÖFò %øô ó âðús   ¨$AÁ
AÁAc                 óB  • UR                  [        5        UR                  5         U R                  (       d  U R                  (       a9  UR                  S5        [        UR                  5       5      S:w  a  [        S5      eU R                  b  U R                  U5        gg)z}
Initialize the connection, authenticate and select a database and send
 READONLY if it is set during object initialization.
rî   ÚOKzREADONLY command failedN)
Ú
set_parserrº   rA  r/  r6  Úsend_commandr;   Úread_responser(   r@  )r  rM   s     rC   rA  ÚRedisCluster.on_connectÉ  s€   € ð
 	×ÑœmÔ,Ø×ÑÔà×"×" d×&B×&Bð ×#Ñ# JÔ/Ü˜J×4Ñ4Ó6Ó7¸4Ó?Ü%Ð&?Ó@Ð@à×$Ñ$Ñ0Ø×%Ñ% jÕ1ð 1rE   c                 ó  • UR                   (       dN  U R                     UR                   (       d  U R                  R                  U/5        S S S 5        UR                   $ UR                   $ ! , (       d  f       UR                   $ = frL   )re  rN  r  Úcreate_redis_connectionsrh  s     rC   Úget_redis_connectionÚ!RedisCluster.get_redis_connectionÞ  se   € Ø×$×$Ø—“Ø×,×,Ø×&Ñ&×?Ñ?ÀÀÔG÷ ð ×$Ñ$Ð$ˆt×$Ñ$Ð$÷ ”ð ×$Ñ$Ð$ús   ž.A,Á,
Bc                 ó:   • U R                   R                  XU5      $ rL   )r  Úget_node©r  r<   r=   rX   s       rC   rv  ÚRedisCluster.get_nodeå  s   € Ø×!Ñ!×*Ñ*¨4°yÓAÐArE   c                 ó@   • U R                   R                  [        5      $ rL   )r  Úget_nodes_by_server_typeÚPRIMARYrS  s    rC   r  ÚRedisCluster.get_primariesè  ó   € Ø×!Ñ!×:Ñ:¼7ÓCÐCrE   c                 ó@   • U R                   R                  [        5      $ rL   )r  rz  ÚREPLICArS  s    rC   r  ÚRedisCluster.get_replicasë  r}  rE   c                 ó„   • [         R                  " [        U R                  R                  R                  5       5      5      $ rL   )rÎ   r  r  r  Únodes_cacher^   rS  s    rC   Úget_random_nodeÚRedisCluster.get_random_nodeî  s+   € Ü�}Š}œT $×"4Ñ"4×"@Ñ"@×"GÑ"GÓ"IÓJÓKÐKrE   c                 ó\   • [        U R                  R                  R                  5       5      $ rL   )r  r  r‚  r^   rS  s    rC   rd  ÚRedisCluster.get_nodesñ  s"   € Ü�D×&Ñ&×2Ñ2×9Ñ9Ó;Ó<Ð<rE   c                 ó2  • U R                  U5      nU R                  R                  R                  U5      nUb  [	        U5      S:X  a  [        SU S35      eU(       a'  [	        U R                  R                  U   5      S:  a  gU(       a  SnXE   $ SnXE   $ )zz
Get the node that holds the key's slot.
If replica set to True but the slot doesn't have any replicas, None is
returned.
Nr   úSlot "z " is not covered by the cluster.r}   rm   )Úkeyslotr  Úslots_cachers   r�   r/   )r  Úkeyry   rv   Ú
slot_cacheÚnode_idxs         rC   Úget_node_from_keyÚRedisCluster.get_node_from_keyô  sš   € ð �|‰|˜CÓ ˆØ×'Ñ'×3Ñ3×7Ñ7¸Ó=ˆ
ØÑ¤ Z£°AÓ!5Ü%¨¨t¨fÐ4TÐ&UÓVÐVÞ”s˜4×-Ñ-×9Ñ9¸$Ñ?Ó@À1ÓDØÞØˆHð
 Ñ#Ð#ð ˆHàÑ#Ð#rE   c                 ó.   • U R                   R                  $ )z 
Get the cluster's default node
)r  r  rS  s    rC   r  ÚRedisCluster.get_default_node  s   € ð ×!Ñ!×.Ñ.Ð.rE   c                 ó`   • Ub  U R                  UR                  S9c  gXR                  l        g)zv
Set the default node of the cluster.
:param node: 'ClusterNode'
:return True if the default node was set, else False
©rX   FT)rv  Únamer  r  rh  s     rC   Úset_default_nodeÚRedisCluster.set_default_node  s/   € ð ‰<˜4Ÿ=™=°4·9±9˜=Ð=ÑEØØ*.×ÑÔ'ØrE   r>   c                 ó   • U R                   $ rL   )rŸ   rS  s    rC   Ú	get_retryÚRedisCluster.get_retry  s   € Ø�z‰zÐrE   c                 ót   • Xl         U R                  5        H  nUR                  R                  U5        M      g rL   )rŸ   rd  re  Ú	set_retry)r  rŸ   r‡   s      rC   r›  ÚRedisCluster.set_retry  s,   € ØŒ
Ø—N‘NÖ$ˆDØ×!Ñ!×+Ñ+¨EÖ2ò %rE   c                 ó¨   • Uc  U R                  5       nUR                  c  [        SUR                   S35      eUR                  R	                  5       $ )a1  
Returns a Monitor object for the specified target node.
The default cluster node will be selected if no target node was
specified.
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Cluster Node z has no redis_connection)r  re  r,   r”  Úmonitor)r  r  s     rC   rž  ÚRedisCluster.monitor!  s\   € ð ÑØ×/Ñ/Ó1ˆKØ×'Ñ'Ñ/Ü'Ø × 0Ñ 0Ð1Ð1IÐJóð ð ×+Ñ+×3Ñ3Ó5Ð5rE   c                 ó    • [        U 4XUS.UD6$ )zf
Allows passing a ClusterNode, or host&port, to get a pubsub instance
connected to the specified node
)r‡   r<   r=   )ÚClusterPubSub)r  r‡   r<   r=   r´   s        rC   ÚpubsubÚRedisCluster.pubsub2  s   € ô
 ˜TÐM¨¸dÑMÀfÑMÐMrE   c                 óJ  • U(       a  [        S5      eU(       a  [        S5      e[        U R                  U R                  U R                  R                  U R
                  U R                  U R                  U R                  U R                  U R                  U R                  S9
$ )a+  
Cluster impl:
    Pipelines do not work in cluster mode the same way they
    do in normal mode. Create a clone of this object so
    that simulating pipelines will work correctly. Each
    command will be called directly when used and
    when calling execute() will only return the result stack.
z(shard_hint is deprecated in cluster modez)transaction is deprecated in cluster mode)
r  rL  r2  rK  rJ  r3  r/  r6  r5  Úlock)r,   ÚClusterPipeliner  rL  r2  rK  rJ  r3  r/  r6  r5  rN  )r  ÚtransactionÚ
shard_hints      rC   ÚpipelineÚRedisCluster.pipeline9  s�   € ö Ü'Ð(RÓSÐSæÜ'Ð(SÓTÐTäØ×,Ñ,Ø ×0Ñ0Ø×,Ñ,×:Ñ:Ø!×2Ñ2Ø'+×'FÑ'FØ)-×)JÑ)JØ#×6Ñ6Ø$(×$@Ñ$@Ø#×6Ñ6Ø—‘ñ
ð 	
rE   c           
      ó,   • Uc  [         nU" U UUUUUUS9$ )aô	  
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.)ÚtimeoutÚsleepÚblockingÚblocking_timeoutÚthread_localr2   )r  r”  r¬  r­  r®  r¯  Ú
lock_classr°  s           rC   r¥  ÚRedisCluster.lockU  s2   € ð| ÑÜˆJÙØØØØØØ-Ø%ñ
ð 	
rE   c                 ó    • X R                   U'   g)zSet a custom Response CallbackN)rJ  )r  rT   Úcallbacks      rC   Úset_response_callbackÚ"RedisCluster.set_response_callbackŸ  s   € à3;×'Ñ'¨Ò0rE   c                 ó  • US   R                  5       n[        U5      S:¼  aD  US    SUS    3R                  5       U R                  ;   a  US    SUS    3R                  5       nUR                  SS 5      nUb  UnOU R                  R	                  U5      nXPR
                  R                  :X  a  U R                  5       /$ XPR
                  R                  :X  a  U R                  5       $ XPR
                  R                  :X  a  U R                  5       $ XPR
                  R                  :X  a  U R                  5       $ XPR
                  R                  :X  a  U R                  R                   /$ X0R
                  R"                  S   ;   a  U R                  R                   /$ U R$                  " U6 nU R                  R'                  UU R(                  =(       a	    U[*        ;   U[*        ;   a  U R,                  OS 5      nU/$ )Nr   r}   Ú rm   r›   )Úupperr�   rE  r
  rs   rC  r  rƒ  r  r  r  r  r  rd  r   r  r  r$  Údetermine_slotÚget_node_from_slotr/  r   r6  )r  rP   r´   rT   r›   Úcommand_flagrv   r‡   s           rC   Ú_determine_nodesÚRedisCluster._determine_nodes£  sÀ  € ð �q‘'—-‘-“/ˆÜˆt‹9˜‹>  a¡ 	¨¨4°©7¨)Ð4×:Ñ:Ó<À×@RÑ@RÓRØ˜a™˜	  4¨¡7 )Ð,×2Ñ2Ó4ˆGà—Z‘Z ¨dÓ3ˆ
ØÑ!à%‰Lð  ×-Ñ-×1Ñ1°'Ó:ˆLØŸ>™>×0Ñ0Ó0à×(Ñ(Ó*Ð+Ð+ØŸ^™^×5Ñ5Ó5à×%Ñ%Ó'Ð'ØŸ^™^×4Ñ4Ó4à×$Ñ$Ó&Ð&ØŸ^™^×5Ñ5Ó5à—>‘>Ó#Ð#ØŸ^™^×8Ñ8Ó8à×&Ñ&×3Ñ3Ð4Ð4ØŸ™×6Ñ6°qÑ9Ó9Ø×&Ñ&×3Ñ3Ð4Ð4ð ×&Ò&¨Ð-ˆDØ×%Ñ%×8Ñ8ØØ×'Ñ'×D¨G´}Ñ,DØ07¼=Ó0H�×,Ò,ÈdóˆDð
 �6ˆMrE   c                 ó\   • U R                   S:X  a  gU R                  U R                   -  S:H  $ )Nr   F)r5  rG  rS  s    rC   Ú_should_reinitializedÚ"RedisCluster._should_reinitializedÌ  s1   € ð
 ×"Ñ" aÓ'Øà×,Ñ,¨t×/FÑ/FÑFÈ!ÑKÐKrE   c                 óN   • U R                   R                  U5      n[        U5      $ )zh
Calculate keyslot for a given key.
See Keys distribution model in https://redis.io/topics/cluster-spec
)rB  Úencoder   )r  r‹  rµ   s      rC   r‰  ÚRedisCluster.keyslotÖ  s"   € ð
 �L‰L×Ñ Ó$ˆÜ˜‹{ÐrE   c                 óp   • U R                  5       R                  nU R                  R                  " U/UQ76 $ )ac  
Get the keys in the command. If the command has no keys in in, None is
returned.

NOTE: Due to a bug in redis<7.0, this function does not work properly
for EVAL or EVALSHA when the `numkeys` arg is 0.
 - issue: https://github.com/redis/redis/issues/9493
 - fix: https://github.com/redis/redis/pull/9733

So, don't use this function with EVAL or EVALSHA.
)r  re  rL  Úget_keys)r  rP   Ú
redis_conns      rC   Ú_get_command_keysÚRedisCluster._get_command_keysÞ  s4   € ð ×*Ñ*Ó,×=Ñ=ˆ
Ø×#Ñ#×,Ò,¨ZÐ?¸$Ò?Ð?rE   c                 óè  • US   nU R                   R                  U5      [        :X  a  US   $ UR                  5       S;   a`  [	        U5      S::  a  [        SU 35      e[        US   5      nUSSU-    n[	        U5      S:X  a  [        R                  " S[        5      $ UnO^U R                  " U6 nUb  [	        U5      S:X  a=  UR                  5       S;   a  [        R                  " S[        5      $ [        SU 35      e[	        U5      S:X  a  U R                  US   5      $ U Vs1 sH  o`R                  U5      iM     nn[	        U5      S:w  a  [        U S	35      eUR                  5       $ s  snf )
zÚ
Figure out what slot to use based on args.

Raises a RedisClusterException if there's a missing key and we can't
    determine what slots to map the command to; or, if the keys don't
    all map to the same key slot.
r   rm   )ÚEVALÚEVALSHAr}   zInvalid args in command: rp   )ÚFCALLÚFCALL_ROz€No way to dispatch this command to Redis Cluster. Missing key.
You can execute the command by specifying target nodes.
Command: z) - all keys must map to the same key slot)rE  rs   r"  r¹  r�   r,   ÚintrÎ   Ú	randranger   rÈ  r‰  r
  )r  rP   rT   Únum_actual_keysÚ	eval_keysÚkeysr‹  ru   s           rC   rº  ÚRedisCluster.determine_slotí  sv  € ð �q‘'ˆØ×Ñ×!Ñ! 'Ó*¬gÓ5à˜‘7ˆNð �=‰=‹?Ð1Ó1ä�4‹y˜A‹~Ü+Ð.GÈÀvÐ,NÓOÐOÜ! $ q¡'›lˆOØ˜Q  _Ñ!4Ð5ˆIô �9‹~ Ó"Ü×'Ò'¨Ô+CÓDÐDØ‰Dà×)Ò)¨4Ð0ˆDØ‰|œs 4›y¨A›~ð —=‘=“?Ð&;Ó;Ü!×+Ò+¨AÔ/GÓHÐHÜ+ð/à/3¨fð6óð ô ˆt‹9˜‹>Ø—<‘<  Q¡Ó(Ð(ñ /3Ó3©d s—‘˜cÖ"©dˆÐ3Üˆu‹:˜‹?Ü'Ø�)ÐDÐEóð ð �y‰y‹{Ðùò 4s   Ä'E/c                 ó   • U R                   $ )z
Get the connections' encoder
)rB  rS  s    rC   Úget_encoderÚRedisCluster.get_encoder&  s   € ð �|‰|ÐrE   c                 ó.   • U R                   R                  $ )z)
Get the connections' key-word arguments
)r  r·   rS  s    rC   Úget_connection_kwargsÚ"RedisCluster.get_connection_kwargs,  s   € ð ×!Ñ!×3Ñ3Ð3rE   c                 óL   • [        U[        5      =(       a    XR                  ;   $ rL   )r~   rt   rF  )r  Útarget_nodess     rC   Ú_is_nodes_flagÚRedisCluster._is_nodes_flag2  s   € Ü˜,¬Ó,×P°ÇÁÑ1PÐPrE   c                 óä   • [        U[        5      (       a  UnU$ [        U[        5      (       a  U/nU$ [        U[        5      (       a  UR	                  5       nU$ [        S[        U5       35      e)Nz°target_nodes type can be one of the following: node_flag (PRIMARIES, REPLICAS, RANDOM, ALL_NODES),ClusterNode, list<ClusterNode>, or dict<any, ClusterNode>. The passed type is )r~   r  r  r   r^   Ú	TypeErrorÚtype)r  rÜ  r|   s      rC   Ú_parse_target_nodesÚ RedisCluster._parse_target_nodes5  s„   € Ü�l¤D×)Ñ)Ø ˆEð  ˆô ˜¤k×2Ñ2à!�NˆEð ˆô ˜¤d×+Ñ+ð !×'Ñ'Ó)ˆEð ˆô ð&ô '+¨<Ó&8Ð%9ð;óð rE   c                 ó&   • U R                   " U0 UD6$ rL   )Ú_internal_execute_command©r  rP   r´   s      rC   Úexecute_commandÚRedisCluster.execute_commandI  s   € Ø×-Ò-¨tÐ>°vÑ>Ð>rE   c                 óâ  • SnSnSnUR                  SS5      nUb)  U R                  U5      (       d  U R                  U5      nSnU(       a  SOU R                  nSU-   n[	        U5       H£  n	 0 n
U(       dT  U R
                  " U0 UDSU0D6nU(       d  [        SU S	35      e[        U5      S:X  a  US   U R                  5       :X  a  SnU H%  nU R                  " U/UQ70 UD6X«R                  '   M'     U R                  " US   U
40 UD6s  $    g! [         aR  nUS:”  aE  [        U5      U R                  R                  ;   a"  U(       a  U R!                  5         US-  n SnAMý  UeSnAff = f)
aÊ  
Wrapper for ERRORS_ALLOW_RETRY error handling.

It will try the number of times specified by the config option
"self.cluster_error_retry_attempts" which defaults to 3 unless manually
configured.

If it reaches the number of times, the command will raise the exception

Key argument :target_nodes: can be passed with the following types:
    nodes_flag: PRIMARIES, REPLICAS, ALL_NODES, RANDOM
    ClusterNode
    list<ClusterNode>
    dict<Any, ClusterNode>
FNrÜ  Tr   rm   r›   ú!No targets were found to execute ú command on)r
  rÝ  râ  r3  r€   r½  r,   r�   r  Ú_execute_commandr”  Ú_process_resultÚ	Exceptionrá  rC  r'  r  )r  rP   r´   Útarget_nodes_specifiedÚis_default_noderÜ  Úpassed_targetsÚretry_attemptsÚexecute_attemptsÚ_rU   r‡   Úes                rC   rå  Ú&RedisCluster._internal_execute_commandL  s”  € ð  "'ÐØˆØˆØŸ™ N°DÓ9ˆØÑ%¨d×.AÑ.AÀ.×.QÑ.QØ×3Ñ3°NÓCˆLØ%)Ð"ö (‰A¨T×-NÑ-Nð 	ð ˜~Ñ-ÐÜÐ'Ö(ˆAðØ�Þ-à#'×#8Ò#8Øð$Ø!'ñ$Ø4Bò$�Lö (Ü3Ø?À¸vÀ[ÐQóð ô ˜LÓ)¨QÓ.Ø(¨™O¨t×/DÑ/DÓ/FÓFà*.˜Û(�DØ%)×%:Ò%:¸4Ð%QÀ$Ò%QÈ&Ñ%Q�CŸ	™	“Nñ )ð ×+Ò+¨D°©G°SÑC¸FÑCÒCò) )øô* ó Ø! AÓ%¬$¨q«'°T·^±^×5VÑ5VÓ*VÞ&à×1Ñ1Ô3ð # aÑ'�NÝð �Gûðús    Á.BDÄ
E.ÄAE)Å'E)Å)E.c                 óL  • US   nSnSnSnSnSn	[        U R                  5      n
U
S:”  GaI  U
S-  n
 U(       a  U R                  US9nOeU	(       a^  U R                  " U6 nU R                  R                  UU R                  =(       a	    U[        ;   U[        ;   a  U R                  OS5      nSn	U R                  U5      n[        U5      nU(       a'  UR                  S5        UR                  " US40 UD6  SnUR                  " U0 UD6  UR                  " Xd40 UD6nUR                  SS5        X@R                  ;   a  U R                  U   " U40 UD6nUUb  UR                  R!                  U5        $ $ [Q        S5      e! ["         a    e [$        [&        4 ak  nUb  UR)                  5         U R                  R*                  R                  UR,                  S5        SUl        U R                  R1                  5         UeSnAf[2         as  nU =R4                  S-  sl        U R7                  5       (       a"  U R                  R1                  5         SU l        OU R                  R9                  U5        Sn	 SnAOÝSnAf[:         a+    X R                  S	-  :  a  [<        R>                  " S
5         O¦[@         a*  n[C        URD                  URF                  S9nSn SnAOxSnAf[H        [J        4 a2    [<        R>                  " S5        U R                  R1                  5         e [L         a    e [N         a  nU(       a  UR)                  5         UeSnAff = fUb  UR                  R!                  U5        O$! Ub  UR                  R!                  U5        f f = fU
S:”  a  GMx  GN1)z)
Send a command to a node in the cluster
r   NFrm   r“  ÚASKINGrÓ  Tr}   gš™™™™™©?rB   g      Ð?zTTL exhausted.))rÏ  r  rv  rº  r  r»  r/  r   r6  rs  rO   rn  Úparse_responser
  rJ  rN   Úreleaser$   r(   r0   rf  r2  r”  re  Ú
initializer+   rG  rÀ  Úupdate_moved_exceptionr1   Útimer­  r#   rD   r<   r=   r&   r/   r.   rî  r'   )r  r  rP   r´   rT   rF   rM   Úredirect_addrÚaskingÚmovedÚttlrv   rY   rõ  s                 rC   rì  ÚRedisCluster._execute_command’  sb  € ð �q‘'ˆØˆ
Øˆ
ØˆØˆØˆÜ�$×-Ñ-Ó.ˆà�AŒgØ�1‰HˆCðaCÞØ"&§-¡-¸- -Ð"H‘KÞð  ×.Ò.°Ð5�DØ"&×"4Ñ"4×"GÑ"GØØ×/Ñ/×L°G¼}Ñ4Lð  '¬-Ó7ð !×8Ò8à!%ó#�Kð "�Eà!×6Ñ6°{ÓC�
Ü+¨JÓ7�
ÞØ×+Ñ+¨HÔ5Ø×-Ò-¨j¸(ÑMÀfÒMØ"�FØ×'Ò'¨Ð8°Ò8Ø%×4Ò4°ZÑSÈFÑS�ð —
‘
˜6 4Ô(à×=Ñ=Ó=Ø#×>Ñ>¸wÒGØ ñ Ø$*ñ �Hð  ð| Ñ)Ø×.Ñ.×6Ñ6°zÕBð *ô Ð+Ó,Ð,øôA 'ó ØÜ#¤\Ð2ó ð Ñ)Ø×)Ñ)Ô+ð ×"Ñ"×0Ñ0×4Ñ4°[×5EÑ5EÀtÔLà/3�Ô,Ø×"Ñ"×-Ñ-Ô/Ø�ûÜó ð ×)Ò)¨QÑ.Õ)Ø×-Ñ-×/Ñ/Ø×&Ñ&×1Ñ1Ô3à01�DÕ-à×&Ñ&×=Ñ=¸aÔ@Ø•ûÜ ó %Ø×4Ñ4°qÑ8Ó8Ü—J’J˜tÔ$ùÜó Ü -°1·6±6ÀÇÁÑ G�Ø•ûÜ$Ô&9Ð:ó ô —
’
˜4Ô Ø×"Ñ"×-Ñ-Ô/ØÜ ó ØÜó ÞØ×)Ñ)Ô+Ø�ûðúð
 Ñ)Ø×.Ñ.×6Ñ6°zÔBùð Ñ)Ø×.Ñ.×6Ñ6°zÕBð *úðE �A�gˆgsc   ²D#F  Æ MÆA&H È MÈA)I;É6M7 É;5MÊ0M7 Ê2	MÊ; K ËM7 Ë AMÌ7MÍMÍM7 Í7!Nc                 óÈ   •  U R                      U R                  (       a  U R                  R                  5         S S S 5        g ! , (       d  f       g = f! [         a     g f = frL   )rN  r  rX  ÚAttributeErrorrS  s    rC   rX  ÚRedisCluster.close  sF   € ð	Ø—“Ø×%×%Ø×&Ñ&×,Ñ,Ô.÷ —–ûô ó 	áð	ús-   ‚A Ž,AºA Á
AÁA ÁA Á
A!Á A!c                 ó¦   • XR                   ;   a  U R                   U   " X40 UD6$ [        U5      S:X  a  [        UR                  5       5      S   $ U$ )zÓ
Process the result of the executed command.
The function would return a dict or a single value.

:type command: str
:type res: dict

`res` should be in the following format:
    Dict<node_name, command_result>
rm   r   )rK  r�   r  r^   )r  rT   rU   r´   s       rC   rí  ÚRedisCluster._process_result  sS   € ð ×+Ñ+Ó+Ø×(Ñ(¨Ò1°'ÑIÀ&ÑIÐIÜ�‹X˜‹]ô ˜Ÿ
™
›Ó% aÑ(Ð(àˆJrE   c                 ó   • [        XU5        g)zé
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.
N)Úsetattr)r  ÚfuncnameÚfuncs      rC   Úload_external_moduleÚ!RedisCluster.load_external_module"  s   € ô 	� Õ%rE   )rH  rN  r3  rJ  rE  rL  rB  r6  rF  r  r/  rG  r5  rK  rŸ   r@  )Nië  Nrp   NFé   FNTNNNNN©NNN)F)rŸ   r4   r>   NrL   ©NN)Ngš™™™™™¹?TNNT©r>   N)7rÂ   rÃ   rÄ   rÅ   Úclassmethodr-  r6   r	   rt   rÏ  r   Úboolr   r
   r   r   r"   rP  rT  r]  ra  ri  rA  rs  rv  r  r  rƒ  rd  rŽ  r  r•  r˜  r›  rž  r¢  r©  r¥  rµ  r½  rÀ  r‰  rÈ  rº  rÖ  rÙ  rÝ  râ  rç  rå  rì  rX  rí  r  rÇ   rA   rE   rC   r)  r)  Ð  sM  † Øñ)&ó ð)&ñV Ø*Ð+ØGØñð #ØØ7;Ø,-Ø#'Ø&+Ø"#Ø#(ØEIØ&*Ø!ØPTØ*.Ø.2Ø6:ñ!s&à�s‰mðs&ð ðs&ð    ]Ñ 3Ñ4ð	s&ð
 '*ðs&ð ˜Ñ ðs&ð  $ðs&ð  ðs&ð !ðs&ð "*Ð*AÑ!Bðs&ð  $ðs&ð �c‰]ðs&ð   ¨%°°S°©/Ð):¸EÀ#ÀsÀ(¹OÐ)KÑ LÑMðs&ð ˜Ñ'ðs&ð ˜{Ñ+ðs&ð  # ?Ñ3ô!s&óð
s&òjòòòò2ò*%ôBòDòDòLò=ô$ò(/ò	ð˜8 GÑ,ô ô3ô
6ô"Nô
ð> ØØØØØôH
òT<ð'°4¸Ñ3Fô 'òRLòò@ò7òrò4òQòò(?òDòLq-ôfòõ(&rE   r)  c                   ó0   • \ rS rSrSS jrS rS rS rSrg)	r  i-  Nc                 óŒ   • US:X  a  [         R                  " U5      nXl        X l        [	        X5      U l        X0l        X@l        g )NÚ	localhost)ÚsocketÚgethostbynamer<   r=   rD   r”  Úserver_typere  )r  r<   r=   r  re  s        rC   rP  ÚClusterNode.__init__.  s<   € Ø�;ÓÜ×'Ò'¨Ó-ˆDàŒ	ØŒ	Ü! $Ó-ˆŒ	Ø&ÔØ 0ÕrE   c                 óŠ   • SU R                    SU R                   SU R                   SU R                   SU R                   S3$ )Nz[host=z,port=z,name=z,server_type=z,redis_connection=Ú])r<   r=   r”  r  re  rS  s    rC   Ú__repr__ÚClusterNode.__repr__8  sW   € à�T—Y‘Y�Kð  Ø—I‘I�;ð Ø—I‘I�;ð Ø×+Ñ+Ð,ð - Ø $× 5Ñ 5Ð6°að	9ð	
rE   c                 ób   • [        U[        5      =(       a    UR                  U R                  :H  $ rL   )r~   r  r”  )r  Úobjs     rC   Ú__eq__ÚClusterNode.__eq__A  s!   € Ü˜#œ{Ó+×E°·±¸D¿I¹IÑ0EÐErE   c                 óT   • U R                   b  U R                   R                  5         g g rL   )re  rX  rS  s    rC   ra  ÚClusterNode.__del__D  s%   € Ø× Ñ Ñ,Ø×!Ñ!×'Ñ'Õ)ð -rE   )r<   r”  r=   re  r  r  )	rÂ   rÃ   rÄ   rÅ   rP  r  r!  ra  rÇ   rA   rE   rC   r  r  -  s   † ô1ò
òFõ*rE   r  c                   ó    • \ rS rSrSrSrSrSrg)r7  iI  Úround_robinÚround_robin_replicasÚrandom_replicarA   N)rÂ   rÃ   rÄ   rÅ   ÚROUND_ROBINÚROUND_ROBIN_REPLICASÚRANDOM_REPLICArÇ   rA   rE   rC   r7  r7  I  s   † Ø€KØ1ÐØ%ƒNrE   r7  c            	       ó˜   • \ rS rSrSrSS\SS4S jjr\R                  4S\	S\S	\S\4S
 jjr
SS jrS\S\4S jrS\	S\S\S\4S jrSrg)ÚLoadBalanceriO  z
Round-Robin Load Balancing
Ústart_indexr>   Nc                 ó   • 0 U l         Xl        g rL   ©Úprimary_to_idxr.  )r  r.  s     rC   rP  ÚLoadBalancer.__init__T  s   € Ø ˆÔØ&ÕrE   rq   Ú	list_sizer6  c                 ó”   • U[         R                  :X  a  U R                  U5      $ U R                  UUU[         R                  :H  5      $ rL   )r7  r+  Ú_get_random_replica_indexÚ_get_round_robin_indexr*  )r  rq   r3  r6  s       rC   Úget_server_indexÚLoadBalancer.get_server_indexX  sL   € ð #Ô&;×&JÑ&JÓJØ×1Ñ1°)Ó<Ð<à×.Ñ.ØØØ'Ô+@×+UÑ+UÑUóð rE   c                 ó8   • U R                   R                  5         g rL   )r1  ÚclearrS  s    rC   ÚresetÚLoadBalancer.resetg  s   € Ø×Ñ×!Ñ!Õ#rE   c                 ó6   • [         R                  " SUS-
  5      $ )Nrm   )rÎ   Úrandint)r  r3  s     rC   r5  Ú&LoadBalancer._get_random_replica_indexj  s   € Ü�~Š~˜a ¨Q¡Ó/Ð/rE   Úreplicas_onlyc                 ó˜   • U R                   R                  XR                  5      nU(       a  US:X  a  SnUS-   U-  U R                   U'   U$ rl   )r1  Ú
setdefaultr.  )r  rq   r3  r@  Úserver_indexs        rC   r6  Ú#LoadBalancer._get_round_robin_indexm  sO   € ð ×*Ñ*×5Ñ5°g×?OÑ?OÓPˆÞ˜\¨QÓ.àˆLà(4°qÑ(8¸IÑ'Eˆ×Ñ˜GÑ$ØÐrE   r0  )r   r  )rÂ   rÃ   rÄ   rÅ   Ú__doc__rÏ  rP  r7  r)  rt   r7  r;  r5  r  r6  rÇ   rA   rE   rC   r-  r-  O  sŽ   † ññ' Cð '°õ 'ð :O×9ZÑ9Zñ	àðð ðð "7ð	ð
 
õô$ð0°3ð 0¸3ô 0ð	Øð	Ø'*ð	Ø;?ð	à	÷	rE   r-  c                   ó   • \ rS rSrSSSS\SSSSS4
S\\\\\	4   /\\\	4   4      S\\
   S\\   S\\   S	\\   4
S
 jjrS!S jrS rS r\" S/SSS9   S"S j5       rS rS rS rS rS rS rS rS#S jrS rS\S\	S\\\	4   4S jrS rg)$rI  iy  FNTr9  r¯   r°   Úcache_factoryr:  c                 óÆ  • 0 U l         0 U l        0 U l        S U l        U R	                  U5        X l        X0l        XPl        X`l        Xpl	        X€l
        X�l        X l        S U l        XÀl        [        5       U l        Uc  ["        R$                  " 5       nX@l        Uc  [)        5       U l        OX°l        U R                  R-                  SS 5      U l        U R1                  5         g )Nr’   )r‚  rŠ  r2  r  Úpopulate_startup_nodesr-  Ú_require_full_coverageÚ_dynamic_startup_nodesr�   r9  Ú_cacheÚ_cache_configÚ_cache_factoryÚ_moved_exceptionr·   r-  Úread_load_balancerrM  r3   rN  r"   rH  rs   Ú_credential_providerrû  )r  r2  r-  r4  r¥  r8  r�   r9  r¯   r°   rG  r:  r´   s                rC   rP  ÚNodesManager.__init__z  sÏ   € ð ˆÔØˆÔØˆÔØ ˆÔØ×#Ñ# MÔ2Ø ŒØ&;Ô#Ø&;Ô#Ø%:Ô"Ø*ÔØŒØ)ÔØ+ÔØ $ˆÔØ!'ÔÜ".£.ˆÔØ‰<Ü—>’>Ó#ˆDØŒ
ØÑ#Ü%4Ó%6ˆDÕ"à%5Ô"Ø$(×$:Ñ$:×$>Ñ$>Ø! 4ó%
ˆÔ!ð 	�‰ÕrE   c                 óà   • U(       aE  U(       a>  US:X  a  [         R                  " U5      nU R                  R                  [	        XS95      $ U(       a  U R                  R                  U5      $ g)zl
Get the requested node from the cluster's nodes.
nodes.
:return: ClusterNode if the node exists, else None
r  rB   N)r  r  r‚  rs   rD   rw  s       rC   rv  ÚNodesManager.get_node¥  sZ   € ö –Dà�{Ó"Ü×+Ò+¨DÓ1�Ø×#Ñ#×'Ñ'¬¸4Ñ(KÓLÐLÞØ×#Ñ#×'Ñ'¨	Ó2Ð2àrE   c                 ó   • Xl         g rL   )rO  )r  Ú	exceptions     rC   rü  Ú#NodesManager.update_moved_exceptionµ  s   € Ø )ÕrE   c                 óî  • U R                   nU R                  UR                  UR                  S9nUb  UR                  [
        La  [
        Ul        O=[        UR                  UR                  [
        5      nX R                  UR                  '   X R                  UR                     ;   a©  U R                  UR                     S   n[        Ul        U R                  UR                     R                  U5        U R                  UR                     R                  U5        X R                  UR                     S'   U R                  U:X  a  X l        OU/U R                  UR                  '   SU l         g)z0
Update the slot's node with the redirected one
rB   Nr   )rO  rv  r<   r=   r  r{  r  r‚  r”  rŠ  Úslot_idr  r‚   Úremover  )r  rõ  Úredirected_nodeÚold_primarys       rC   Ú_update_moved_slotsÚ NodesManager._update_moved_slots¸  s5  € ð ×!Ñ!ˆØŸ-™-¨Q¯V©V¸!¿&¹&˜-ÐAˆØÑ&à×*Ñ*´'Ò9ä.5�Ô+øô *¨!¯&©&°!·&±&¼'ÓBˆOØ5D×Ñ˜_×1Ñ1Ñ2Ø×.Ñ.¨q¯y©yÑ9Ó9ð ×*Ñ*¨1¯9©9Ñ5°aÑ8ˆKô '.ˆKÔ#Ø×Ñ˜QŸY™YÑ'×.Ñ.¨{Ô;ð ×Ñ˜QŸY™YÑ'×.Ñ.¨Ô?à-<×Ñ˜QŸY™YÑ'¨Ñ*Ø× Ñ  KÓ/à$3Ô!øð
 ,;Ð*;ˆD×Ñ˜QŸY™YÑ'à $ˆÕrE   r  z|In case you need select some load balancing strategy that will use replicas, please set it through 'load_balancing_strategy'rG   r0  c                 óN  • U R                   (       a6  U R                     U R                   (       a  U R                  5         SSS5        U R                  R	                  U5      b  [        U R                  U   5      S:X  a  [        SU SU R                   S35      eUSL a  Uc  [        R                  n[        U R                  U   5      S:”  aW  U(       aP  U R                  U   S   R                  nU R                  R                  U[        U R                  U   5      U5      nO\Ub&  U[        :X  d  [        U R                  U   5      S:X  a  SnO0[        R                  " S[        U R                  U   5      S-
  5      nU R                  U   U   $ ! , (       d  f       GN\= f)z)
Gets a node that servers this hash slot
Nr   rˆ  z5" not covered by the cluster. "require_full_coverage=Ú"Trm   )rO  rN  r]  rŠ  rs   r�   r/   rJ  r7  r)  r”  rP  r7  r{  rÎ   r>  )r  rv   r/  r6  r  Úprimary_namer�  s          rC   r»  ÚNodesManager.get_node_from_slotß  s€  € ð$ × × Ø—“Ø×(×(Ø×,Ñ,Ô.÷ ð ×Ñ×Ñ Ó%Ñ-´°T×5EÑ5EÀdÑ5KÓ1LÐPQÓ1QÜ%Ø˜˜ð *Ø*.×*EÑ*EÐ)FÀaðIóð ð
  Ò%Ð*AÑ*IÜ&;×&GÑ&GÐ#äˆt×Ñ Ñ%Ó&¨Ó*Ö/Fà×+Ñ+¨DÑ1°!Ñ4×9Ñ9ˆLØ×.Ñ.×?Ñ?Øœc $×"2Ñ"2°4Ñ"8Ó9Ð;Ró‰Hð ÑØœgÓ%Ü�4×#Ñ# DÑ)Ó*¨aÓ/ð ‰Hô —~’~ a¬¨T×-=Ñ-=¸dÑ-CÓ)DÀqÑ)HÓIˆHà×Ñ Ñ% hÑ/Ð/÷? –ús   ž"FÆ
F$c                 ó„   • U R                   R                  5        Vs/ sH  nUR                  U:X  d  M  UPM     sn$ s  snf )zv
Get all nodes with the specified server type
:param server_type: 'primary' or 'replica'
:return: list of ClusterNode
)r‚  r^   r  )r  r  r‡   s      rC   rz  Ú%NodesManager.get_nodes_by_server_type  sF   € ð ×(Ñ(×/Ñ/Ô1ó
á1�Ø×Ñ ;Ñ.÷ Ù1ñ
ð 	
ùò 
s   �=´=c                 óF   • U H  nX R                   UR                  '   M     g)z;
Populate all startup nodes and filters out any duplicates
N)r2  r”  )r  r|   Úns      rC   rI  Ú#NodesManager.populate_startup_nodes  s    € ó ˆAØ)*×Ñ˜qŸv™vÓ&ò rE   c                 ó@   • [        S[        5       H
  nX!;  d  M
    g   g)Nr   FT)r€   r   )r  rŠ  r†   s      rC   Úcheck_slots_coverageÚ!NodesManager.check_slots_coverage&  s$   € ô �qÔ2Ö3ˆAØÕ#Ùñ 4ð rE   c                 ón  • / nU Ho  nUR                   b  M  U R                  " SUR                  UR                  S.U R                  D6Ul         UR                  UR                   R                  5        Mq     U R                  R                  [        U[        R                  U R                  5      5        g)zF
This function will create a redis connection to all nodes in :nodes:
NrB   rA   )re  Úcreate_redis_noder<   r=   r·   r‚   rN   rH  Údispatchr   r!   ÚSYNCrQ  )r  r|   Úconnection_poolsr‡   s       rC   rr  Ú%NodesManager.create_redis_connections.  sž   € ð ÐÛˆDØ×$Ñ$Ó,Ø(,×(>Ò(>ð )ØŸ™¨¯©ñ)Ø6:×6LÑ6Lñ)�Ô%ð !×'Ñ'¨×(=Ñ(=×(MÑ(MÖNñ ð 	×Ñ×'Ñ'Ü4Ø ¤*§/¡/°4×3LÑ3Lóõ	
rE   c                 ó  • U R                   (       a^  UR                  SU05        UR                  SU05        UR                  SU R                  05        [        U R                  " S0 UD6S9nU$ [        SUUU R                  S.UD6nU$ )Nr<   r=   r¯   )rN   )r<   r=   r¯   rA   )r-  r?  rL  r   r�   )r  r<   r=   r´   r[   s        rC   rl  ÚNodesManager.create_redis_node@  sŒ   € Ø�=�=à�M‰M˜6 4˜.Ô)Ø�M‰M˜6 4˜.Ô)Ø�M‰M˜7 D§K¡KÐ0Ô1Ü d×&@Ò&@Ñ&JÀ6Ñ&JÑKˆAð ˆô ð ØØØ—k‘kñð ñ	ˆAð ˆrE   c                 óú   • [        X5      nUR                  U5      nUc[  U R                  R                  U5      nUb  UR                  c  [	        XU5      nUR
                  U:w  a  X6l        XdUR                  '   U$ rL   )rD   rs   r‚  re  r  r  r”  )r  r<   r=   ÚroleÚtmp_nodes_cacherX   r  s          rC   Ú_get_or_create_cluster_nodeÚ(NodesManager._get_or_create_cluster_nodeP  s   € Ü! $Ó-ˆ	à%×)Ñ)¨)Ó4ˆØÑð ×*Ñ*×.Ñ.¨yÓ9ˆKØÑ" k×&BÑ&BÑ&Jä)¨$°dÓ;�Ø×&Ñ&¨$Ó.Ø*.Ô'à0;˜K×,Ñ,Ñ-àÐrE   c           
      ó®  • U R                  5         0 n0 n/ nSnSnU R                  nSnU R                  R                  5        GH¦  n UR                  (       a  UR                  n	OEU R
                  " UR                  UR                  40 UD6n	X�R                  UR                     l         [        U	R                  S5      5      n
U	R                  R                  5         Sn[!        U
5      S:X  aF  [!        U
S   S   S   5      S:X  a.  [!        U R                  5      S:X  a  UR                  U
S   S   S'   U
 GH‘  nUS   n[        US   5      nUS	:X  a  UR                  n[#        US   5      nU R%                  Xï5      u  pï/ nU R'                  Xï[(        U5      nUR+                  U5        US
S nU HZ  n[        US   5      n[#        US   5      nU R%                  Xï5      u  pïU R'                  Xï[,        U5      nUR+                  U5        M\     [/        [#        US   5      [#        US   5      S-   5       H�  nUU;  a  UUU'   M  UU   S   nUR                  UR                  :w  d  M4  UR+                  UR                   SUR                   SU 35        [!        U5      S:”  d  Mr  [        SSR1                  U5       35      e   GM”     U R3                  U5      nU(       d  GM§    O   U(       d  [        S[5        U5       35      UeU R6                  cb  U R8                  bU  U R:                  c)  [=        U R8                  5      R?                  5       U l        OU R:                  R?                  5       U l        U RA                  [C        UR                  5       5      5        U(       d0  U RD                  (       a  [        S[!        U5       S[F         S35      eXl$        X l%        U RM                  [(        5      S   U l'        U RP                  (       a  Xl        SU l)        g! [         a    [        S5      ef = f! [         a  nUn SnAGM  SnAff = f)zŒ
Initializes the nodes cache, slots cache and redis connections.
:startup_nodes:
    Responsible for discovering other nodes in the cluster
FNrð   z(Cluster mode is not enabled on this nodeTrm   r   r}   rj   rp   z vs z
 on slot: r  z6startup_nodes could not agree on a valid slots cache: z, zORedis Cluster cannot be connected. Please provide at least one reachable node: z9All slots are not covered after query all startup_nodes. z of z covered...)*r;  r·   r2  r^   re  rl  r<   r=   r”  r;   rç  rN   rf  r.   r,   rî  r�   rÏ  Úremap_host_portrv  r{  r‚   r  r€   Újoinri  rt   rL  rM  rN  r   Ú	get_cacherr  r  rJ  r   r‚  rŠ  rz  r  rK  rO  )r  ru  Ú	tmp_slotsÚdisagreementsÚstartup_nodes_reachableÚfully_coveredr´   rV  Ústartup_noder[   Úcluster_slotsrõ  rv   Úprimary_noder<   r=   Únodes_for_slotr  Úreplica_nodesÚreplica_nodeÚtarget_replica_noder†   Útmp_slots                          rC   rû  ÚNodesManager.initializec  sW  € ð 	�
‰
ŒØˆØˆ	ØˆØ"'ÐØˆØ×'Ñ'ˆØˆ	Ø ×.Ñ.×5Ñ5×7ˆLðØ×0×0Ø$×5Ñ5‘Að ×.Ò.Ø$×)Ñ)¨<×+<Ñ+<ñØ@Fñ�Að NO×&Ñ& |×'8Ñ'8Ñ9ÔJðÜ$0°×1BÑ1BÀ?Ó1SÓ$T�MØ×%Ñ%×0Ñ0Ô2ð
 +/Ð'ô �MÓ" aÓ'Ü˜ aÑ(¨Ñ+¨AÑ.Ó/°1Ó4Ü˜×*Ñ*Ó+¨qÓ0à)5×):Ñ):�˜aÑ  Ñ# AÑ&ä%�Ø# A™w�Ü# L°¡OÓ4�Ø˜2“:Ø'×,Ñ,�DÜ˜<¨™?Ó+�Ø!×1Ñ1°$Ó=‘
�à!#�à"×>Ñ>Ø¤¨ó�ð ×%Ñ% kÔ2à $ Q R �Û$1�LÜ'¨°Q©Ó8�DÜ˜|¨A™Ó/�DØ!%×!5Ñ!5°dÓ!A‘J�DØ*.×*JÑ*JØ¤G¨_ó+Ð'ð #×)Ñ)Ð*=Ö>ñ %2ô œs 4¨¡7›|¬S°°a±«\¸AÑ-=Ö>�AØ 	Ó)Ø'5˜	 !›ð $-¨Q¡<°¡?˜Ø#Ÿ=™=¨K×,<Ñ,<Õ<Ø)×0Ñ0Ø#+§=¡= /°°k×6FÑ6FÐ5GÀzÐRSÐQTÐ Uôô  # =Ó1°AÕ5Ü&;ð'4Ø48·I±I¸mÓ4LÐ3Mð%Oó'"ð !"ô ?ñ3 &ðV !×5Ñ5°iÓ@ˆMß‰}ñ ñm 8öp 'Ü'ð'Ü'*¨9£~Ð&6ð8óð ðð
 �;‰;Ñ 4×#5Ñ#5Ñ#AØ×"Ñ"Ñ*Ü*¨4×+=Ñ+=Ó>×HÑHÓJ�•à"×1Ñ1×;Ñ;Ó=�”ð 	×%Ñ%¤d¨?×+AÑ+AÓ+CÓ&DÔEö  ×!<×!<ô (ØKÜ�y“>Ð" $Ô'?Ð&@ð Aðóð ð +ÔØ$Ôà ×9Ñ9¼'ÓBÀ1ÑEˆÔØ×&×&à!0Ôà $ˆÕøôY %ó Ü/ØBóð ðûô
 ó ð �	Þûð	ús1   ÁA#P<Â,4P#Ã P<Ð#P9Ð9P<Ð<
QÑQÑQr>   c                 ó®   • S U l         U R                  R                  5        H0  nUR                  (       d  M  UR                  R	                  5         M2     g rL   )r  r‚  r^   re  rX  rh  s     rC   rX  ÚNodesManager.closeí  sA   € Ø ˆÔØ×$Ñ$×+Ñ+Ö-ˆDØ×$×$Ñ$Ø×%Ñ%×+Ñ+Ö-ò .rE   c                 óZ   •  U R                   R                  5         g ! [         a     g f = frL   )rP  r;  rà  rS  s    rC   r;  ÚNodesManager.resetó  s+   € ð	Ø×#Ñ#×)Ñ)Õ+øÜó 	áð	ús   ‚ �
*©*r<   r=   c                 óN   • U R                   (       a  U R                  X45      $ X4$ )z“
Remap the host and port returned from the cluster to a different
internal value.  Useful if the client is not connecting directly
to the cluster.
)r9  )r  r<   r=   s      rC   ry  ÚNodesManager.remap_host_portú  s(   € ð ××Ø×%Ñ% t lÓ3Ð3ØˆzÐrE   )rL  rM  rN  rQ  rK  rH  rN  rO  rJ  r9  r·   r�   r  r-  r‚  rP  rŠ  r2  r  )FNNr  )rÂ   rÃ   rÄ   rÅ   r   r	   r   r
   rt   rÏ  r   r   r   r"   rP  rv  rü  r]  r6   r»  rz  rI  ri  rr  rl  rv  rû  rX  r;  ry  rÇ   rA   rE   rC   rI  rI  y  s'  † ð Ø#ØØ"Ø,ØPTØ*.Ø.2Ø9=Ø6:ñ)ð   ¨%°°S°©/Ð):¸EÀ#ÀsÀ(¹OÐ)KÑ LÑMð)ð ˜Ñ'ð)ð ˜{Ñ+ð)ð  Ð 5Ñ6ð)ð # ?Ñ3õ)ôVò *ò%%ñN Ø#�_ðVð ñð !Ø $Øó*0óð*0òX

ò+òò
ò$ò ò&H%ôT.òð Cð ¨sð °u¸SÀ#¸X±÷ rE   rI  c                   óš   ^ • \ rS rSrSr     SS\S   4U 4S jjjrSS jrS rS r	S	 r
S
 rS rS r SS jrS rS rS rS rSrU =r$ )r¡  i  zà
Wrapper for PubSub class.

IMPORTANT: before using ClusterPubSub, read about the known limitations
with pubsub in Cluster mode and learn how to workaround them:
https://redis-py-cluster.readthedocs.io/en/stable/pubsub.html
r:  r"   c                 óh  >• SU l         U R                  XX45        U R                   c  SO$UR                  U R                   5      R                  nXl        0 U l        U R                  5       U l        Uc  [        5       U l        OX`l        [        T	U ](  " SUUR                  UU R                  S.UD6  g)aô  
When a pubsub instance is created without specifying a node, a single
node will be transparently chosen for the pubsub connection on the
first command execution. The node will be determined by:
 1. Hashing the channel name in the request to find its keyslot
 2. Selecting a node that handles the keyslot: If read_from_replicas is
    set to true or load_balancing_strategy is set, a replica can be selected.

:type redis_cluster: RedisCluster
:type node: ClusterNode
:type host: str
:type port: int
N)rN   rB  Úpush_handler_funcr:  rA   )r‡   Úset_pubsub_noders  rN   ÚclusterÚnode_pubsub_mappingÚ_pubsubs_generatorr"   rH  ÚsuperrP  rB  )
r  Úredis_clusterr‡   r<   r=   r‘  r:  r´   rN   rC  s
            €rC   rP  ÚClusterPubSub.__init__  sµ   ø€ ð. ˆŒ	Ø×Ñ˜]°$Ô=ð �y‰yÑ ñ à×3Ñ3°D·I±IÓ>×NÑNð 	ð
 %ŒØ#%ˆÔ Ø"&×"9Ñ"9Ó";ˆÔØÑ#Ü%4Ó%6ˆDÕ"à%5Ô"Ü‰Òð 	
Ø+Ø!×)Ñ)Ø/Ø!×3Ñ3ñ		
ð
 ó	
rE   c                 óö   • Ub*  U R                  XUR                  UR                  5        UnOFUb'  Ub$  UR                  X4S9nU R                  XX45        UnO[	        X4/5      SL a  [        S5      eSnXPl        g)aæ  
The pubsub node will be set according to the passed node, host and port
When none of the node, host, or port are specified - the node is set
to None and will be determined by the keyslot of the channel in the
first command to be executed.
RedisClusterException will be thrown if the passed node does not exist
in the cluster.
If host is passed without port, or vice versa, a DataError will be
thrown.
:type cluster: RedisCluster
:type node: ClusterNode
:type host: str
:type port: int
NrB   Tz6Passing a host requires passing a port, and vice versa)Ú_raise_on_invalid_noder<   r=   rv  Úanyr)   r‡   )r  r“  r‡   r<   r=   Úpubsub_nodes         rC   r’  ÚClusterPubSub.set_pubsub_node;  sƒ   € ð Ñà×'Ñ'¨°t·y±yÀ$Ç)Á)ÔLØ‰KØÑ $Ñ"2à×#Ñ#¨Ð#Ð9ˆDØ×'Ñ'¨°tÔBØ‰KÜ�$�Ó $Ò&äÐTÓUÐUð ˆKà�	rE   c                 ó   • U R                   $ )z:
Get the node that is being used as the pubsub connection
)r‡   rS  s    rC   Úget_pubsub_nodeÚClusterPubSub.get_pubsub_node\  s   € ð �y‰yÐrE   c                 ób   • Ub  UR                  UR                  S9c  [        SU SU S35      eg)zT
Raise a RedisClusterException if the node is None or doesn't exist in
the cluster.
Nr“  zNode r@   z doesn't exist in the cluster)rv  r”  r,   )r  r—  r‡   r<   r=   s        rC   rš  Ú$ClusterPubSub._raise_on_invalid_nodeb  sF   € ð
 ‰<˜=×1Ñ1¸D¿I¹IÐ1ÐFÑNÜ'Ø˜�v˜Q˜t˜fÐ$AÐBóð ð OrE   c                 óÞ  • U R                   Gc¶  U R                  cË  [        U5      S:”  ap  US   nU R                  R	                  U5      nU R                  R
                  R                  UU R                  R                  U R                  R                  5      nOU R                  R                  5       nX@l
        U R                  R                  U5      nUR                  U l        U R                  R                  5       U l         U R                   R                  U R                  5        U R                  b:  [         (       d/  U R                   R"                  R%                  U R                  5        U R&                  R)                  [+        U R                   U R                  [,        R.                  U R0                  5      5        U R                   nU R2                  " XfR4                  /UQ76   g)zp
Execute a subscribe/unsubscribe command.

Taken code from redis-py and tweak to make it work within a cluster.
Nrm   )rM   rN   r�   r“  r‰  r  r»  r/  r6  rƒ  r‡   rs  rO   Úregister_connect_callbackrA  r‘  r5   Ú_parserÚset_pubsub_push_handlerrH  rm  r    r!   rn  rN  Ú_executern  )r  rP   rb   rv   r‡   re  rM   s          rC   rç  ÚClusterPubSub.execute_commandl  sn  € ð �?‰?Ò"Ø×#Ñ#Ñ+Ü�t“9˜q“=ð # 1™g�GØŸ<™<×/Ñ/°Ó8�DØŸ<™<×5Ñ5×HÑHØØŸ™×7Ñ7ØŸ™×<Ñ<ó‘Dð  Ÿ<™<×7Ñ7Ó9�DØ ”	Ø#'§<¡<×#DÑ#DÀTÓ#JÐ Ø'7×'GÑ'G�Ô$Ø"×2Ñ2×AÑAÓCˆDŒOð �O‰O×5Ñ5°d·o±oÔFØ×%Ñ%Ñ1×:KÒ:KØ—‘×'Ñ'×?Ñ?À×@VÑ@VÔWØ×"Ñ"×+Ñ+Ü7Ø—O‘O T×%9Ñ%9¼:¿?¹?ÈDÏJÉJóôð
 —_‘_ˆ
Ø�Š�j×"9Ñ"9ÐA¸DÔArE   c                 óÐ   •  U R                   UR                     $ ! [         a@    UR                  R	                  U R
                  S9nX R                   UR                  '   Us $ f = f)N)r‘  )r”  r”  r_   re  r¢  r‘  )r  r‡   r¢  s      rC   Ú_get_node_pubsubÚClusterPubSub._get_node_pubsub–  sh   € ð	Ø×+Ñ+¨D¯I©IÑ6Ð6øÜó 	Ø×*Ñ*×1Ñ1Ø"&×"8Ñ"8ð 2ð ˆFð 39×$Ñ$ T§Y¡YÑ/ØŠMð	ús   ‚ ›AA%Á$A%c                 ó¦   • [        [        U R                  5      5       H/  n[        U R                  5      nUR                  5       nUc  M-  Us  $    g rL   )r€   r�   r”  Únextr•  Úget_message)r  rô  r¢  Úmessages       rC   Ú_sharded_message_generatorÚ(ClusterPubSub._sharded_message_generator   sJ   € Ü”s˜4×3Ñ3Ó4Ö5ˆAÜ˜$×1Ñ1Ó2ˆFØ×(Ñ(Ó*ˆGØÓ"Ø’ñ	 6ð
 rE   c              #   óX   #   •  U R                   R                  5        S h  v•N   M$   N7frL   )r”  r^   rS  s    rC   r•  Ú ClusterPubSub._pubsubs_generator¨  s(   é € ØØ×/Ñ/×6Ñ6Ó8×8Ð8ñ Ù8ùs   ‚*¡(¢*c                 óì  • U(       a'  U R                   UR                     R                  XS9nOU R                  5       nUc  g [	        US   5      S:X  a¹  US   U R
                  ;   a¦  U R
                  R                  US   5        U R                  R                  US   S 5        U R                  R                  US   5      nU R                   UR                     R                  SL a%  U R                   R                  UR                  5        U R                  (       d<  U R                  (       d+  U R                  (       d  U R                  R                  5         U R                   (       d  U(       a  g U$ )N)Úignore_subscribe_messagesr¬  rá  Úsunsubscriberb   F)r”  r”  r®  r°  r;   Ú"pending_unsubscribe_shard_channelsrZ  Úshard_channelsr
  r“  rŽ  Ú
subscribedÚchannelsÚpatternsÚsubscribed_eventr:  rµ  )r  rµ  r¬  r  r¯  r‡   s         rC   Úget_sharded_messageÚ!ClusterPubSub.get_sharded_message¬  s,  € ö Ø×.Ñ.¨{×/?Ñ/?Ñ@×LÑLØ*Cð Mð ‰Gð ×5Ñ5Ó7ˆGØ‰?ØÜ˜' &™/Ó*¨nÓ<Ø�yÑ! T×%LÑ%LÓLØ×7Ñ7×>Ñ>¸wÀyÑ?QÔRØ×#Ñ#×'Ñ'¨°	Ñ(:¸DÔAØ—|‘|×5Ñ5°g¸iÑ6HÓI�Ø×+Ñ+¨D¯I©IÑ6×AÑAÀUÒJØ×,Ñ,×0Ñ0°·±Ô;Ø�}�} T§]§]¸4×;N×;Nð ×!Ñ!×'Ñ'Ô)Ø×)×)Ö-FØØˆrE   c                 ó”  • U(       a  [        US   USS  5      n[        R                  U5      nUR                  U5        UR	                  5        Hõ  u  pEU R
                  R                  U5      nU R                  U5      nU(       a  UR                  " S0 XE0D6  OUR                  U5        U R                  R                  UR                  5        U R                  R                  U R                  US 05      5        UR                  (       d  MÁ  U R                  (       a  MÔ  U R                  R                  5         SU l        M÷     g )Nr   rm   rA   )r   r   Úfromkeysr?  rS   r“  rŽ  rª  Ú
ssubscriber¸  r·  Údifference_updateÚ_normalize_keysr¹  r¼  ÚsetÚhealth_check_response_counter)r  rP   r´   Ú
s_channelsÚ	s_channelÚhandlerr‡   r¢  s           rC   rÁ  ÚClusterPubSub.ssubscribeÆ  s  € ÞÜ  Q¡¨¨a¨b¨Ó2ˆDÜ—]‘] 4Ó(ˆ
Ø×Ñ˜&Ô!Ø",×"2Ñ"2Ö"4ÑˆIØ—<‘<×1Ñ1°)Ó<ˆDØ×*Ñ*¨4Ó0ˆFÞØ×!Ò!Ñ9 YÐ$8Ó9à×!Ñ! )Ô,Ø×Ñ×&Ñ& v×'<Ñ'<Ô=Ø×3Ñ3×EÑEØ×$Ñ$ i°Ð%6Ó7ôð × × Ñ ¨¯¯©Ø×%Ñ%×)Ñ)Ô+Ø56�Ö2ò #5rE   c                 ó&  • U(       a  [        US   USS  5      nOU R                  nU He  nU R                  R                  U5      nU R	                  U5      nUR                  U5        U R                  R                  UR                  5        Mg     g rl   )r   r¸  r“  rŽ  rª  r¶  r·  r?  )r  rP   rÇ  r‡   Úps        rC   r¶  ÚClusterPubSub.sunsubscribeÚ  s}   € ÞÜ  Q¡¨¨a¨b¨Ó2‰Dà×&Ñ&ˆDãˆIØ—<‘<×1Ñ1°)Ó<ˆDØ×%Ñ% dÓ+ˆAØ�N‰N˜9Ô%Ø×3Ñ3×:Ñ:Ø×4Ñ4öò	 rE   c                 óJ   • U R                   b  U R                   R                  $ g)z8
Get the Redis connection of the pubsub connected node.
N)r‡   re  rS  s    rC   rs  Ú"ClusterPubSub.get_redis_connectionè  s#   € ð �9‰9Ñ Ø—9‘9×-Ñ-Ð-ð !rE   c                 óÐ   • U R                   (       a  U R                   R                  5         U R                  R                  5        H  nUR                   R                  5         M     g)z#
Disconnect the pubsub connection.
N)rM   rf  r”  r^   )r  r¢  s     rC   rf  ÚClusterPubSub.disconnectï  sF   € ð �?�?Ø�O‰O×&Ñ&Ô(Ø×.Ñ.×5Ñ5Ö7ˆFØ×Ñ×(Ñ(Ö*ò 8rE   )rH  r•  r“  rM   rN   rÅ  r‡   r”  )NNNNNr  )Fg        N)rÂ   rÃ   rÄ   rÅ   rE  r	   rP  r’  rŸ  rš  rç  rª  r°  r•  r½  rÁ  r¶  rs  rf  rÇ   Ú__classcell__©rC  s   @rC   r¡  r¡    s   ø† ñð ØØØØ8<ñ+
ð #Ð#4Ñ5÷+
ð +
ôZ òBòò(BòTòò9ð
 IMôò47ò(ò.÷+ð +rE   r¡  c                   óf  ^ • \ rS rSrSr\\\\\	4r
        S-SSSSS\\\\4      S\\\\4      S	\\S
      S\S\\   S\S\4S jjrS rS rS rS rS rS rS rS rS rS rS.S\S\\   4S jjrS r  S/S jr! S/U 4S jjr"S  r#S! r$S" r%S# r&S$ r'S% r(S& r)S' r*S( r+S) r,S* r-S+ r.S,r/U =r0$ )0r¦  iù  z,
Support for Redis pipeline
in cluster mode
r  rI  rL  r   rK  rJ  r2  r  r/  r6  r3  r5  c                 ó  • / U l         Xl        X l        SU l        U=(       d$    U R                  R
                  R                  5       U l        U(       a  UO/ U l        X`l	        Xpl
        U R                  R                  R                  5       U l        X@l        X€l        SU l        X�l        [#        UR%                  SS5      UR%                  SS5      UR%                  SS5      5      U l        U
c  [(        R*                  " 5       n
X l        g)	rj   Fr   r•   r‹   r–   r=  r”   N)Úcommand_stackr  rL  Úrefresh_table_asaprC  r&  rD  rK  r2  r/  r6  r#  rE  rJ  r3  rG  r5  r   rs   rB  rM  r3   rN  )r  r  rL  rK  rJ  r2  r/  r6  r3  r5  r¥  r´   s               rC   rP  ÚClusterPipeline.__init__  sâ   € ð  ˆÔØ*ÔØ.ÔØ"'ˆÔà×F §¡× ?Ñ ?× DÑ DÓ Fð 	Ôö /<™]ÀˆÔØ"4ÔØ'>Ô$Ø!Ÿ^™^×9Ñ9×>Ñ>Ó@ˆÔØ*DÔ'Ø,HÔ)Ø$%ˆÔ!Ø"4ÔÜØ�J‰J�z 7Ó+Ø�J‰JÐ(¨(Ó3Ø�J‰JÐ)¨5Ó1ó
ˆŒð
 ‰<Ü—>’>Ó#ˆDØ�
rE   c                 ó.   • [        U 5      R                   $ ©rj   )rá  rÂ   rS  s    rC   r  ÚClusterPipeline.__repr__.  s   € ä�t“*×%Ñ%Ð&Ð'rE   c                 ó   • U $ rÙ  rA   rS  s    rC   rT  ÚClusterPipeline.__enter__2  s   € àˆrE   c                 ó$   • U R                  5         g©rj   N)r;  rY  s       rC   r]  ÚClusterPipeline.__exit__6  s   € à�
‰
�rE   c                 óF   •  U R                  5         g ! [         a     g f = frL   )r;  rî  rS  s    rC   ra  ÚClusterPipeline.__del__:  s"   € ð	Ø�J‰J�LøÜó 	Ùð	ús   ‚ “
 Ÿ c                 ó,   • [        U R                  5      $ rÙ  )r�   rÕ  rS  s    rC   Ú__len__ÚClusterPipeline.__len__@  s   € ä�4×%Ñ%Ó&Ð&rE   c                 ó   • g)z?Pipeline instances should  always evaluate to True on Python 3+TrA   rS  s    rC   Ú__bool__ÚClusterPipeline.__bool__D  s   € àrE   c                 ó&   • U R                   " U0 UD6$ )z/
Wrapper function for pipeline_execute_command
)Úpipeline_execute_commandræ  s      rC   rç  ÚClusterPipeline.execute_commandH  s   € ð ×,Ò,¨dÐ=°fÑ=Ð=rE   c           	      óv   • U R                   R                  [        X[        U R                   5      5      5        U $ )z>
Appends the executed command to the pipeline's command stack
)rÕ  r‚   ÚPipelineCommandr�   ©r  rP   rQ   s      rC   ré  Ú(ClusterPipeline.pipeline_execute_commandN  s4   € ð 	×Ñ×!Ñ!Ü˜D¬3¨t×/AÑ/AÓ+BÓCô	
ð ˆrE   c                 ó®   • U HO  nUR                   n[        U[        5      (       d  M&  U R                  X2R                  S-   UR
                  5        Ue   g)z(
Raise the first exception on the stack
rm   N)Úresultr~   rî  Úannotate_exceptionÚpositionrP   )r  ÚstackÚcr[   s       rC   Úraise_first_errorÚ!ClusterPipeline.raise_first_errorW  sE   € ó ˆAØ—‘ˆAÜ˜!œY×'Ó'Ø×'Ñ'¨¯:©:¸©>¸1¿6¹6ÔBØ�ò	 rE   c                 ó¢   • SR                  [        [        U5      5      nSU SU SUR                  S    3nU4UR                  SS -   Ul        g)zC
Provides extra context to the exception prior to it being handled
r¸  z
Command # z (z) of pipeline caused error: r   rm   N)rz  Úmapr:   rP   )r  rV  ÚnumberrT   ÚcmdÚmsgs         rC   rñ  Ú"ClusterPipeline.annotate_exceptiona  s[   € ð �h‰h”sœ8 WÓ-Ó.ˆà˜˜  3 %Ð'CÀIÇNÁNÐSTÑDUÐCVÐWð 	ð ˜ )§.¡.°°Ð"4Ñ4ˆ	�rE   Úraise_on_errorr>   c                 óˆ   • U R                   n U R                  X!5      U R                  5         $ ! U R                  5         f = f)z2
Execute all the commands in the current pipeline
)rÕ  Úsend_cluster_commandsr;  )r  rý  ró  s      rC   ÚexecuteÚClusterPipeline.executek  s5   € ð ×"Ñ"ˆð	Ø×-Ñ-¨eÓDà�J‰J�LøˆD�J‰J�Lús	   Ž/ ¯Ac                 óL   • / U l         [        5       U l        SU l        SU l        g)z
Reset back to empty pipeline.
FN)rÕ  rÄ  ÚscriptsÚwatchingÚexplicit_transactionrS  s    rC   r;  ÚClusterPipeline.resetu  s&   € ð  ˆÔä“uˆŒð  ˆŒØ$)ˆÕ!rE   c                 óª   • U(       d  / $ U R                   n  U R                  UUUS9$ ! [        [        4 a  nUS:”  a
  US-  n SnAO
UeSnAff = fM>  )a«  
Wrapper for CLUSTERDOWN error handling.

If the cluster reports it is down it is assumed that:
 - connection_pool was disconnected
 - connection_pool was reseted
 - refereh_table_asap set to True

It will try the number of times specified by
the config option "self.cluster_error_retry_attempts"
which defaults to 3 unless manually configured.

If it reaches the number of times, the command will
raises ClusterDownException.
)rý  Úallow_redirectionsr   rm   N)r3  Ú_send_cluster_commandsr&   r(   )r  ró  rý  r  rò  rõ  s         rC   rÿ  Ú%ClusterPipeline.send_cluster_commands•  sx   € ö$ ØˆIØ×:Ñ:ˆØðØ×2Ñ2ØØ#1Ø'9ð 3ð ð øô
 %¤oÐ6ó Ø! AÓ%ð # aÑ'�NÜà�Gûðúñ s   ˜) ©A¹AÁ	AÁAc                 óN  >• [        US S9nSn0 nU GH1  n UR                  R                  SS5      nU(       a(  U R                  U5      (       d  U R	                  U5      n	O<U R
                  " UR                  SU06n	U	(       d  [        SUR                   S	35      e[        U	5      S
:”  a  [        SUR                   35      eU	S   n
X R                  5       :X  a  SnU
R                  nX¶;  a@  U R                  U
5      n [        U5      n[-        UR.                  UR                   U5      Xk'   Xk   R1                  U5        GM4     UR                  5       n UR                  5       nU H  nUR3                  5         M     U H  nUR5                  5         M     UR                  5        H(  nUR                   R#                  UR$                  5        M*     [        S U 5       S S9nU(       a•  U(       aŽ  U =R6                  S
-  sl        U R9                  5       (       a1  U R&                  R)                  5         U(       a  U R+                  5         U H-  n [:        TU ]x  " UR                  0 UR                  D6Ul        M/     / n[        US S9 H“  nUR                  S   U RB                  ;   aX  UR                  R                  SS5        U RB                  UR                  S      " UR>                  40 UR                  D6Ul        UR1                  UR>                  5        M•     U(       a  U RE                  U5        U$ ! [        [        4 ao    UR                  5        H(  nUR                   R#                  UR$                  5        M*     U R&                  R)                  5         U(       a  U R+                  5         e f = f! UR                  5        H(  nUR                   R#                  UR$                  5        M*     f = f! [@         a  nUUl         SnAGMÊ  SnAff = f)zÊ
Send a bunch of cluster commands to the redis cluster.

`allow_redirections` If the pipeline should follow
`ASK` & `MOVED` responses automatically. If set
to false it will raise RedisClusterException.
c                 ó   • U R                   $ rL   ©rò  ©r„   s    rC   r  Ú8ClusterPipeline._send_cluster_commands.<locals>.<lambda>È  s   € ¨a¯jªjrE   )r‹  FTrÜ  NÚ	node_flagrê  rë  rm   zToo many targets for command r   c              3   óz   #   • U H2  n[        UR                  [        R                  5      (       d  M.  Uv •  M4     g 7frL   )r~   rð  r¦  r'  )Ú.0rô  s     rC   Ú	<genexpr>Ú9ClusterPipeline._send_cluster_commands.<locals>.<genexpr>0	  s-   é € ð á �AÜ˜aŸh™h¬×(JÑ(J×K÷ ‘Ú ùs   ‚,;²	;c                 ó   • U R                   $ rL   r  r  s    rC   r  r  5	  s   € ˜!Ÿ*š*rE   c                 ó   • U R                   $ rL   r  r  s    rC   r  r  Z	  s   € ¨Q¯ZªZrE   rÓ  )#ÚsortedrQ   r
  rÝ  râ  r½  rP   r,   r�   r  r”  rs  rO   r(   r0   r^   rN   rú  rM   r  rû  r  ÚNodeCommandsrù  r‚   ÚwriteÚreadrG  rÀ  r–  rç  rð  r-   rJ  rõ  )r  ró  rý  r  Úattemptrð  r|   rô  rñ  rÜ  r‡   rX   rF   rM   rf  Únode_commandsrõ  rY   rC  s                     €rC   r	  Ú&ClusterPipeline._send_cluster_commandsº  sª  ø€ ô ˜Ñ$8Ñ9ˆØˆàˆô
 ˆAØð
 "#§¡§¡¨~¸tÓ!D�Þ!¨$×*=Ñ*=¸n×*MÑ*MØ#'×#;Ñ#;¸NÓ#K‘Là#'×#8Ò#8ØŸ™ð$Ø+9ñ$�Lö (Ü3Ø?ÀÇÁ¸xÀ{ÐSóð ô �|Ó$ qÓ(Ü/Ø7¸¿¹°xÐ@óð ð $ A‘�Ø×0Ñ0Ó2Ó2Ø&*�Oð
 !ŸI™I�	ØÓ)Ø!%×!:Ñ!:¸4Ó!@�Jð
Ü%3°JÓ%?˜
ô (4Ø"×1Ñ1Ø"×2Ñ2Ø"ó(�EÑ$ð
 Ñ ×'Ñ'¨Ô*Úñc ðv Ÿ™›ˆð	8Ø!ŸL™L›NˆMÛ"�Ø—‘–	ñ #ó #�Ø—‘–ñ #ð* —\‘\–^�Ø×!Ñ!×)Ñ)¨!¯,©,Ö7ñ $ô ñá óñ
 %ñ
ˆö Ö)ð& ×%Ò%¨Ñ*Õ%Ø×)Ñ)×+Ñ+Ø×"Ñ"×-Ñ-Ô/Þ"Ø×-Ñ-Ô/Û�ð!ô  %™wÒ6¸¿¹ÐLÀ!Ç)Á)ÑL�A–Hñ	 ð ˆÜ˜Ñ#7Ô8ˆAØ�v‰v�a‰y˜D×;Ñ;Ó;à—	‘	—‘˜f dÔ+Ø×:Ñ:¸1¿6¹6À!¹9ÒEØ—H‘HñØ !§	¡	ñ�”ð �O‰O˜AŸH™HÖ%ñ 9ö Ø×"Ñ" 5Ô)àˆøôi ,¬\Ð:ó Ø!&§¡¦˜AØ×-Ñ-×5Ñ5°a·l±lÖCñ "0ð ×*Ñ*×5Ñ5Ô7Þ*Ø ×5Ñ5Ô7Øðûðh —\‘\–^�Ø×!Ñ!×)Ñ)¨!¯,©,Ö7ò $ûô\ "ó !Ø �A—H“Hûð!ús2   ÄMÅAO É)PÍA?OÏ>PÐ
P$ÐPÐP$c                 ó(   • U(       d  [        S5      eg)rj   z4ASK & MOVED redirection not allowed in this pipelineN©r,   )r  r  s     rC   Ú_fail_on_redirectÚ!ClusterPipeline._fail_on_redirecth	  s   € æ!Ü'ØFóð ð "rE   c                 ó(   • U R                   " S/UQ76 $ )NÚEXISTS)rç  )r  rÓ  s     rC   ÚexistsÚClusterPipeline.existso	  s   € Ø×#Ò# HÐ4¨tÒ4Ð4rE   c                 ó   • [        S5      e)rj   z method eval() is not implementedr  rS  s    rC   ÚevalÚClusterPipeline.evalr	  s   € ä#Ð$FÓGÐGrE   c                 ó   • [        S5      e)rj   z!method multi() is not implementedr  rS  s    rC   ÚmultiÚClusterPipeline.multiv	  ó   € ä#Ð$GÓHÐHrE   c                 ó   • [        S5      e)rj   z5method immediate_execute_command() is not implementedr  rí  s      rC   Úimmediate_execute_commandÚ)ClusterPipeline.immediate_execute_commandz	  s   € ä#ØCó
ð 	
rE   c                 ó   • [        S5      e)rj   z0method _execute_transaction() is not implementedr  ræ  s      rC   Ú_execute_transactionÚ$ClusterPipeline._execute_transaction€	  s   € ä#Ð$VÓWÐWrE   c                 ó   • [        S5      e)rj   z(method load_scripts() is not implementedr  rS  s    rC   Úload_scriptsÚClusterPipeline.load_scripts„	  s   € ä#Ð$NÓOÐOrE   c                 ó   • [        S5      e)rj   z!method watch() is not implementedr  ©r  Únamess     rC   ÚwatchÚClusterPipeline.watchˆ	  r,  rE   c                 ó   • [        S5      e)rj   z#method unwatch() is not implementedr  rS  s    rC   ÚunwatchÚClusterPipeline.unwatchŒ	  s   € ä#Ð$IÓJÐJrE   c                 ó   • [        S5      e)rj   z4method script_load_for_pipeline() is not implementedr  ræ  s      rC   Úscript_load_for_pipelineÚ(ClusterPipeline.script_load_for_pipeline�	  s   € ä#ØBó
ð 	
rE   c                 ó`   • [        U5      S:w  a  [        S5      eU R                  SUS   5      $ )z'
"Delete a key specified by ``names``"
rm   z=deleting multiple keys is not implemented in pipeline commandÚDELr   ©r�   r,   rç  r7  s     rC   ÚdeleteÚClusterPipeline.delete–	  s8   € ô ˆu‹:˜‹?Ü'ØOóð ð ×#Ñ# E¨5°©8Ó4Ð4rE   c                 ó`   • [        U5      S:w  a  [        S5      eU R                  SUS   5      $ )z'
"Unlink a key specified by ``names``"
rm   z>unlinking multiple keys is not implemented in pipeline commandÚUNLINKr   rC  r7  s     rC   ÚunlinkÚClusterPipeline.unlink¡	  s8   € ô ˆu‹:˜‹?Ü'ØPóð ð ×#Ñ# H¨e°A©hÓ7Ð7rE   )rN  r3  rJ  rE  rÕ  rL  rB  r  r6  r  r/  rÖ  rG  r5  rK  r  r2  r  )NNNFNrp   r  N)T)TT)1rÂ   rÃ   rÄ   rÅ   rE  r(   r0   r+   r#   r1   r'  r	   r   rt   r   r   r  r7  rÏ  rP  r  rT  r]  ra  rã  ræ  rç  ré  rõ  rñ  r   r   r;  rÿ  r	  r   r$  r'  r*  r.  r1  r4  r9  r<  r?  rD  rH  rÇ   rÑ  rÒ  s   @rC   r¦  r¦  ù  st  ø† ñð 	ØØØØðÐð ;?ØDHØ7;Ø#(ØCGØ,-Ø"#Øñ%à%ð%ð *ð%ð # 4¨¨X¨Ñ#6Ñ7ð	%ð
 %-¨T°#°x°-Ñ-@Ñ$Að%ð    ]Ñ 3Ñ4ð%ð !ð%ð "*Ð*?Ñ!@ð%ð '*ð%ð  õ%òN(òòòò'òò>òòò5ñ dð °d¸3±iõ ò*ðB >Bô#ðL >B÷lò\ò5òHòIò
òXòPòIòKò
ò	5÷	8ð 	8rE   r¦  r”  .c                 ó   ^ • U 4S jnU$ )z]
Prints error because some pipelined commands should
be blocked when running in cluster-mode
c                  ó"   >• [        ST S35      e)Nz"ERROR: Calling pipelined function z1 is blocked when running redis in cluster mode...r  )rP   r´   r”  s     €rC   ÚinnerÚ%block_pipeline_command.<locals>.inner³	  s!   ø€ Ü#Ø0°°ð 74ð 5ó
ð 	
rE   rA   )r”  rL  s   ` rC   Úblock_pipeline_commandrN  ­	  s   ø€ õ
ð €LrE   )EÚBGREWRITEAOFrá   ÚBITOPÚ
BRPOPLPUSHrÒ   rí   rÐ   rÑ   ÚCLIENTró   rÕ   rÔ   rÓ   ÚCONFIGrà   ÚECHOrÌ  rù   rú   rÝ   rß   ré   ÚMGETzMGET NONATOMICÚMOVEÚMSETzMSET NONATOMICÚMSETNXÚPFCOUNTÚPFMERGErÜ   ÚPUBLISHrõ   rî   rö   ÚRENAMEÚRENAMENXÚ	RPOPLPUSHrç   rû   rü   rý   zSCRIPT KILLrþ   ÚSCRIPTÚSDIFFÚ
SDIFFSTOREz SENTINEL GET MASTER ADDR BY NAMEzSENTINEL MASTERzSENTINEL MASTERSzSENTINEL MONITORzSENTINEL REMOVEzSENTINEL SENTINELSzSENTINEL SETzSENTINEL SLAVESÚSENTINELrÞ   ÚSINTERÚSINTERSTOREÚSLAVEOFrâ   rã   rä   ÚSLOWLOGÚSMOVEÚSORTÚSUNIONÚSUNIONSTORErÖ   r¸  rô  c                   ó"   • \ rS rSrSrSS jrSrg)rì  i

  rj   Nc                 ó\   • Xl         Uc  0 nX l        X0l        S U l        S U l        SU l        g )NF)rP   rQ   rò  rð  r‡   rÿ  )r  rP   rQ   rò  s       rC   rP  ÚPipelineCommand.__init__
  s0   € ØŒ	Ø‰?ØˆGØŒØ ŒØˆŒØˆŒ	Øˆ�rE   )rP   rÿ  r‡   rQ   rò  rð  r  )rÂ   rÃ   rÄ   rÅ   rE  rP  rÇ   rA   rE   rC   rì  rì  

  s
   † Ù÷rE   rì  c                   ó0   • \ rS rSrSrS rS rS rS rSr	g)	r  i
  rj   c                 ó6   • Xl         X l        X0l        / U l        grÞ  )rù  rN   rM   Úcommands)r  rù  rN   rM   s       rC   rP  ÚNodeCommands.__init__
  s   € à,ÔØ.ÔØ$ŒØˆ�rE   c                 ó:   • U R                   R                  U5        grÞ  )rp  r‚   )r  rô  s     rC   r‚   ÚNodeCommands.append"
  s   € à�‰×Ñ˜QÕrE   c                 ó*  • U R                   nU R                  nU H
  nSUl        M      UR                  UR	                  U Vs/ sH  o3R
                  PM     sn5      5        gs  snf ! [        [        4 a  nU H	  nXCl        M      SnAgSnAff = f)z-
Code borrowed from Redis so it can be fixed
N)rM   rp  rð  Úsend_packed_commandÚpack_commandsrP   r(   r0   )r  rM   rp  rô  rõ  s        rC   r  ÚNodeCommands.write&
  s‚   € ð —_‘_ˆ
Ø—=‘=ˆó ˆAØˆAŽHñ ð
	Ø×*Ñ*Ø×(Ñ(¹(Ó)C¹(°Q¯&¬&¹(Ñ)CÓDõùÚ)Cøä¤Ð.ó 	Û�Ø–ö ûð	ús)   ªA) ÁA$ÁA) Á$A) Á)BÁ9BÂBc                 ó€  • U R                   nU R                   HB  nUR                  b  M   U R                  " XR                  S   40 UR
                  D6Ul        MD     g! [        [        4 a$  nU R                   H	  nX2l        M      SnA  gSnAf[         a!    [        R                  " 5       S   Ul         M£  f = f)rj   Nr   rm   )rM   rp  rð  rù  rP   rQ   r(   r0   r-   ÚsysÚexc_info)r  rM   rô  rõ  s       rC   r  ÚNodeCommands.read<
  s”   € à—_‘_ˆ
Ø—”ˆAð& �x‰xÓð1Ø#×2Ò2°:¿v¹vÀa¹yÑVÈAÏIÉIÑV�A–Hò+ øô, (¬Ð6ó Ø!Ÿ]œ]˜Ø#$žñ +åûÜ!ó 1Ü"Ÿ|š|›~¨aÑ0�A—Hð1ús   ¬/A Á B=Á0BÂ*B=Â<B=)rp  rM   rN   rù  N)
rÂ   rÃ   rÄ   rÅ   rE  rP  r‚   r  r  rÇ   rA   rE   rC   r  r  
  s   † Ùòò òõ,1rE   r  )nrÎ   r  ry  rM  rý  Úcollectionsr   Úenumr   Útypingr   r   r   r   r	   r
   r   Úredis._parsersr   r   Úredis._parsers.helpersr   Úredis.backoffr   Úredis.cacher   r   r   r   Úredis.clientr   r   r   Úredis.commandsr   r   Úredis.commands.helpersr   Úredis.connectionr   r   r   Ú	redis.crcr   r   Úredis.eventr   r    r!   r"   Úredis.exceptionsr#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   Ú
redis.lockr3   Úredis.retryr4   Úredis.utilsr5   r6   r7   r8   r9   r:   r;   rt   rÏ  rD   rO   r\   rf   rz   r‰   r�   r{  r  r"  r²   r³   r¸   rº   rÉ   r)  r  r7  r-  rI  r¡  r¦  rN  ÚPIPELINE_BLOCKED_COMMANDSrT   ÚreplaceÚlowerr	  rì  r  rA   rE   rC   Ú<module>r�     s(  ðÛ Û Û 
Û Û Ý #Ý ß D× DÑ Dç 2Ý -Ý )ß XÓ Xß ;Ñ ;ß >Ý /ß EÑ Eß 8÷ó ÷÷ ÷ ÷ ñ õ" Ý ÷÷ ñ ð˜ð  5¨¨c¨¡?ð °sô ñ Ø�Ø3Øññ
Póð
Pòò
ðØ
ðØðà	ˆ%��S�‰/˜4  S ™>Ð
)Ñ*ôò(ò, ð €Ø
€Ø
€ð'Ð ðP (Ð ò
ô�Mô ÷vNñ vNôrZ&Ð'Ð)=ô Z&÷z*ñ *ô8&˜Dô &÷'ñ '÷TIñ IôXq+�Fô q+ôhq8�lô q8ðh ð ¨°#°s°(Ñ);ô ð FÐ óN )€GØ�o‰o˜c 3Ó'×-Ñ-Ó/€GáˆO˜WÑ&<¸WÓ&EÖFñ )÷ñ ÷B1ò B1rE   