Ë
    §ŒjÈs ã            
       óÖ  — d dl Z d dlZd dlZd dlZd dlZd dlZd dlmZmZ d dl	m
Z
 d dlmZ d dlmZ d dlmZ d dlmZmZmZmZmZmZmZmZmZ d dlmZmZ d d	lmZmZm Z  d d
l!m"Z" d dl#m$Z$m%Z% d dl&m'Z'm(Z(m)Z)m*Z* d dl+m,Z,m-Z-m.Z.m/Z/ d dl0m1Z1m2Z2 d dl3m4Z4 d dl5m6Z6m7Z7 d dl8m9Z9m:Z:m;Z; d dl<m=Z=m>Z> d dl?m@Z@mAZAmBZBmCZC d dlDmEZEmFZFmGZGmHZHmIZImJZJmKZKmLZLmMZMmNZNmOZOmPZPmQZQmRZRmSZSmTZTmUZUmVZV d dlWmXZX d dlYmZZZm[Z[ d dl\m]Z]m^Z^ d dl_m`Z` d dlambZbmcZcmdZdmeZemfZfmgZgmhZhmiZimjZj  e jÖ                  el«      Zmd„ Zndeodeeoepf   deofd„Zq ecdgd d!¬"«      de/de9fd#„«       Zrd$„ Zsd%„ Ztd&ed'edeeepepf   eeoef   f   fd(„Zud)„ Zvd*„ Zwd+Zxd,Zyd-Zzd.Z{d/Z|d0„ Z} G d1„ d2«      Z~ G d3„ d4«      Z G d5„ d6ee~e2«      Z€ G d7„ d8«      Z� G d9„ d:e«      Z‚ G d;„ d<«      Zƒ G d=„ d>«      Z„ G d?„ d@e.«      Z… G dA„ dBe€«      Z†dCeodedDef   fdE„Z‡dFZˆeˆD ]4  Z‰e‰�j                  dGdH«      �j                  «       Z‰ eŒe†e‰ e‡e‰«      «       Œ6  G dI„ dJ«      Z� G dK„ dL«      ZŽ G dM„ dNe«      Z� G dO„ dPe�«      Z� G dQ„ dRe�«      Z‘ G dS„ dTe�«      Z’y)Ué    N)ÚABCÚabstractmethod)ÚOrderedDict)Úcopy)ÚEnum)Úchain)	ÚAnyÚCallableÚDictÚListÚLiteralÚOptionalÚSetÚTupleÚUnion)ÚCommandsParserÚEncoder)ÚCommandPoliciesÚRequestPolicyÚResponsePolicy)Ú
parse_scan)ÚExponentialWithJitterBackoffÚ	NoBackoff)ÚCacheConfigÚCacheFactoryÚCacheFactoryInterfaceÚCacheInterface)ÚEMPTY_RESPONSEÚCaseInsensitiveDictÚPubSubÚRedis)ÚREAD_COMMANDSÚRedisClusterCommands)Úlist_or_args)ÚPolicyResolverÚStaticPolicyResolver)Ú
ConnectionÚConnectionPoolÚ	parse_url)ÚREDIS_CLUSTER_HASH_SLOTSÚkey_slot)Ú(AfterPooledConnectionsInstantiationEventÚ'AfterPubSubConnectionInstantiationEventÚ
ClientTypeÚEventDispatcher)ÚAskErrorÚAuthenticationErrorÚClusterDownErrorÚClusterErrorÚConnectionErrorÚCrossSlotTransactionErrorÚ	DataErrorÚExecAbortErrorÚInvalidPipelineStackÚMaxConnectionsErrorÚ
MovedErrorÚRedisClusterExceptionÚ
RedisErrorÚResponseErrorÚSlotNotCoveredErrorÚTimeoutErrorÚTryAgainErrorÚ
WatchError©ÚLock)ÚMaintNotificationsConfigÚOSSMaintNotificationsHandler)Úrecord_error_countÚrecord_operation_duration)ÚRetry)	Úcheck_protocol_versionÚdeprecated_argsÚdeprecated_functionÚ
dict_mergeÚlist_keys_to_dictÚmerge_resultÚsafe_strÚstr_if_bytesÚtruncate_textc                  óH   — t         j                  t        j                  «      S ©N)ÚloggerÚisEnabledForÚloggingÚDEBUG© ó    úW/var/www/html/Fitness-lenito-AI-main/venv/lib/python3.12/site-packages/redis/cluster.pyÚis_debug_log_enabledr[   Z   s   € Ü×ÑœwŸ}™}Ó-Ð-rY   ÚhostÚportÚreturnc                 ó   — | › d|› �S )NÚ:rX   ©r\   r]   s     rZ   Úget_node_namerb   ^   s   € ØˆV�1�T�FÐÐrY   Ú
redis_nodez&Use get_connection(redis_node) insteadú5.3.0)Úallowed_argsÚreasonÚversionc                 óR   — | j                   xs | j                  j                  «       S rS   )Ú
connectionÚconnection_poolÚget_connection)rc   ÚargsÚoptionss      rZ   rk   rk   b   s$   € ð × Ñ ÒO J×$>Ñ$>×$MÑ$MÓ$OÐOrY   c                 ót   — i }g }|j                  «       D ]  \  }}t        |fi |¤Ž\  }}|||<   ||z  }Œ  ||fS rS   )Úitemsr   )	ÚcommandÚresrm   ÚcursorsÚretÚ	node_nameÚresponseÚcursorÚrs	            rZ   Úparse_scan_resultrx   k   sS   € Ø€GØ
€CØ"Ÿy™yž{Ñˆ	�8Ü˜xÑ3¨7Ñ3‰	ˆ�Ø#ˆ�	ÑØˆq‰‰ð  +ð
 �Cˆ<ÐrY   c                 óð   — t        «       }|j                  «       D ]  }|D ]  \  }}	 ||xx   |z  cc<   Œ Œ |j                  «       D ��cg c]	  \  }}||f‘Œ }}}|S # t        $ r |||<   Y ŒNw xY wc c}}w rS   )r   ÚvaluesÚKeyErrorro   )	rp   rq   rm   Únumsub_dÚnumsub_tupsÚchannelÚ	numsubbedÚnumsubÚ
ret_numsubs	            rZ   Úparse_pubsub_numsubr‚   v   sŒ   € Ü‹}€HØ—z‘z–|ˆÛ"-ÑˆG�Yð.Ø˜Ó! YÑ.Ô!ñ #.ð $ð <D¿>¹>Ô;KÔLÑ;K©¨°�7˜FÒ#Ð;K€JÑLØÐøô	 ò .Ø$-�˜Ó!ð.üó Ms   §AÁA2ÁA/Á.A/Úresprm   c                 óÞ   ‡
— |j                  dd«      Š
dt        dt        t        t        f   fˆ
fd„}i }| D ].  }|d d \  }}}|dd  } ||Ž |D �	cg c]  }	 ||	Ž ‘Œ	 c}	dœ|||f<   Œ0 |S c c}	w )NÚcurrent_hostÚ rl   r^   c                  ó2   •— t        | d   «      xs ‰| d   fS ©Nr   é   )rP   )rl   r…   s    €rZ   Ú
fix_serverz'parse_cluster_slots.<locals>.fix_serverˆ   s    ø€ Ü˜D ™GÓ$Ò4¨°d¸1±gÐ=Ð=rY   é   )ÚprimaryÚreplicas)Úgetr	   r   Ústr)rƒ   rm   rŠ   ÚslotsÚslotÚstartÚendrŒ   r�   Úreplicar…   s             @rZ   Úparse_cluster_slotsr•   ƒ   sš   ø€ ð —;‘;˜~¨rÓ2€Lð>œ#ð >¤%¬¬S¨¡/õ >ð €EÛˆØ" 2 A˜hÑˆˆs�GØ˜˜�8ˆá! 7Ð+Ù=EÓF¹X°'™ WÒ-¸XÑFñ
ˆˆe�SˆjÒð ð €Lùò Gs   ÁA*c                 óŠ  — t        | d   t        «      r| S g }| D ]¦  }g g dœ}t        dt        |d   «      d«      D ]'  }|d   j	                  |d   |   |d   |dz      f«       Œ) |d   }|D ]A  }i }t        dt        |«      d«      D ]  }||dz      |||   <   Œ |d   j	                  |«       ŒC |j	                  |«       Œ¨ |S )z(
    Parse CLUSTER SHARDS response.
    r   )r�   Únodesr‰   é   r�   r‹   r—   )Ú
isinstanceÚdictÚrangeÚlenÚappend)	rƒ   rm   ÚshardsÚxÚshardÚir—   ÚnodeÚ	dict_nodes	            rZ   Úparse_cluster_shardsr¤   —   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Õð ð €MrY   c                 ó$   — | j                  d«      S )z+
    Parse CLUSTER MYSHARDID response.
    úutf-8)Údecode)rƒ   rm   s     rZ   Úparse_cluster_myshardidr¨   ­   s   € ð �;‰;�wÓÐrY   rŒ   r”   zslot-id)*Úconnection_classrj   Úconnection_pool_classÚclient_nameÚcredential_providerÚdbÚdecode_responsesÚencodingÚencoding_errorsr\   Úlib_nameÚlib_versionÚmax_connectionsÚ
nodes_flagÚredis_connect_funcÚpasswordr]   ÚtimeoutÚ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_ca_pathÚssl_certfileÚssl_cert_reqsÚssl_include_verify_flagsÚssl_exclude_verify_flagsÚssl_keyfileÚssl_passwordÚssl_check_hostnameÚunix_socket_pathÚusernameÚcacheÚcache_configÚmaint_notifications_config)r\   r]   r¹   c                  óx   — | j                  «       D ��ci c]  \  }}|t        v r|t        vr||“Œ }}}|S c c}}w )z9
    Remove unsupported or disabled keys from kwargs
    )ro   ÚREDIS_ALLOWED_KEYSÚKWARGS_DISABLED_KEYS)ÚkwargsÚkÚvÚconnection_kwargss       rZ   Úcleanup_kwargsr×   ç   sP   € ð —L‘L”Nôá"‰DˆAˆqØÔ"Ñ" qÔ0DÑ'Dð 	
ˆ1‰Ø"ð ñ ð Ðùós   ”6c                   ó.   — e Zd ZdZdee   fd„Zdefd„Zy)Ú&MaintNotificationsAbstractRedisClustera+  
    Abstract class for handling maintenance notifications logic.
    This class is expected to be used as base class together with RedisCluster.

    This class is intended to be used with multiple inheritance!

    All logic related to maintenance notifications is encapsulated in this class.
    rÏ   c                 ó  — t        |j                  d«      d«      }|r|j                  r|st        d«      ‚|€|r
t	        «       }|| _        | j
                  rª| j
                  j                  r”t        | | j
                  «      | _        | j                  | j                  «       | j                  «       D ]J  }|j                  €Œ|j                  j                  j                  | j
                  | j                  ¬«       ŒL y d | _        y )Nr»   r‹   zWMaintenance notifications handlers on connection are only supported with RESP version 3)Ú'oss_cluster_maint_notifications_handler)rI   rŽ   Úenabledr<   rD   rÏ   rE   Ú(_oss_cluster_maint_notifications_handlerÚ1_update_connection_kwargs_for_maint_notificationsÚ	get_nodesÚredis_connectionrj   Ú!update_maint_notifications_config)ÚselfrÏ   rÓ   Úis_protocol_supportedr¢   s        rZ   Ú__init__z/MaintNotificationsAbstractRedisCluster.__init__þ   sþ   € ô !7°v·z±zÀ*Ó7MÈqÓ QÐñ 'Ø*×2Ò2Ù)äØióð ð &Ð-Ñ2GÜ)AÓ)CÐ&à*DˆÔ'à×*Ò*¨t×/NÑ/N×/VÒ/Vä,¨T°4×3RÑ3RÓSð Ô9ð ×BÑBØ×=Ñ=ôð Ÿ™Ö(�Ø×(Ñ(Ð0ØØ×%Ñ%×5Ñ5×WÑWØ×3Ñ3Ø<@×<iÑ<ið Xõ ñ )ð =AˆDÕ9rY   rÛ   c                 óR   — | j                   j                  j                  d|i«       y)zJ
        Update the connection kwargs for all future connections.
        rÛ   N)Únodes_managerrÖ   Úupdate)râ   rÛ   s     rZ   rÞ   zXMaintNotificationsAbstractRedisCluster._update_connection_kwargs_for_maint_notifications&  s)   € ð 	×Ñ×,Ñ,×3Ñ3à9Ð;bðõ	
rY   N)	Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   rD   rä   rE   rÞ   rX   rY   rZ   rÙ   rÙ   ô   s*   „ ñð&Aà$,Ð-EÑ$Fó&AðP

Ø7Sô

rY   rÙ   c                   ó’  — e Zd ZdZdZdZdZdZdZeeeeehZ	 e
 eg d¢e«       eg d¢e«       ed	ge«       eg d
¢e«      «      Zg d¢fZeeedœZ e
 eddge«       edgd„ «       eg d¢e«       eg d¢d„ «       eddgd„ «       edgd„ «       edge«       edgd„ «       edgd„ «       edgd„ «      «
      ZeeeefZd"d#d!„Zy )$ÚAbstractRedisClusteré   Ú	primariesr�   ÚallÚrandomzdefault-node)Vz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 GETrW   Ú	RANDOMKEYr  Ú	READWRITErù   zTFUNCTION LOADzTFUNCTION DELETEzTFUNCTION LISTÚTFCALLÚTFCALLASYNCz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 RESTOREÚ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   — t        t        |j                  «       «      «      S rS   )ÚsumÚlistrz   ©rp   rq   s     rZ   Ú<lambda>zAbstractRedisCluster.<lambda>ä  s   € ´C¼¸S¿Z¹Z»\Ó8JÔ4KrY   )r  rú   rý   )rÿ   rö   r÷   rø   rô   r  r  r
  r  r  r  c                 óX   — t        |t        «      rt        |j                  «       «      S |S rS   )r™   rš   rð   rz   r$  s     rZ   r%  zAbstractRedisCluster.<lambda>÷  ó!   € ´jÀÄdÔ6K¤ S§Z¡Z£\Ó!2Ð!TÐQTÐ!TrY   r  r  c                 óX   — t        |t        «      rt        |j                  «       «      S |S rS   )r™   rš   r"  rz   r$  s     rZ   r%  zAbstractRedisCluster.<lambda>û  r'  rY   r  c                 óB   — t        |j                  «       «      dkD  rdS dS rˆ   )r"  rz   r$  s     rZ   r%  zAbstractRedisCluster.<lambda>þ  s   € ¼#¸c¿j¹j»lÓ:KÈaÒ:O°QÐ5VÐUVÐ5VrY   r  r   c                 óP   — t        |j                  «       «      j                  «       S rS   )r#  rz   Úpopr$  s     rZ   r%  zAbstractRedisCluster.<lambda>  s   € ´$°s·z±z³|Ó2D×2HÑ2HÔ2JrY   r  c                 óf   — t        |j                  «       Ž D �cg c]  }t        |«      ‘Œ c}S c c}w rS   )Úziprz   rð   )rp   rq   rÔ   s      rZ   r%  zAbstractRedisCluster.<lambda>  s'   € ÄSÈ#Ï*É*Ë,ÑEWÓ4XÑEWÀ´S¸µVÐEWÒ4XùÒ4Xs   ™.r  c                 ó4   — t        |j                  «       «      S rS   )rð   rz   r$  s     rZ   r%  zAbstractRedisCluster.<lambda>  s   € ÄÀSÇZÁZÃ\ÔARrY   Nc                 óˆ  — |r|| j                   _        y| j                  «       }| j                  «       D �cg c]
  }||k7  sŒ	|‘Œ }}|r%t	        j
                  |«      | j                   _        y| j                  «       D �cg c]
  }||k7  sŒ	|‘Œ }}|r%t	        j
                  |«      | j                   _        yyc c}w c c}w )a  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)ræ   Údefault_nodeÚget_default_nodeÚget_primariesrñ   ÚchoiceÚget_replicas)râ   Útarget_nodeÚ	curr_noder¢   rï   r�   s         rZ   Úreplace_default_nodez)AbstractRedisCluster.replace_default_node  s¶   € ñ Ø.9ˆD×ÑÕ+à×-Ñ-Ó/ˆIØ*.×*<Ñ*<Ô*>ÓTÑ*> $À$È)ÓBSšÐ*>ˆIÐTÙä28·-±-À	Ó2J�×"Ñ"Õ/ð .2×->Ñ->Ô-@ÓVÑ-@ TÀDÈIÓDUšDÐ-@�ÐVÙÜ6<·m±mÀHÓ6M�D×&Ñ&Õ3ð ùò Uùò Ws   ·
B:ÁB:Â
B?ÂB?rS   )r5  ÚClusterNoder^   N)rè   ré   rê   ÚRedisClusterRequestTTLÚ	PRIMARIESÚREPLICASÚ	ALL_NODESÚRANDOMÚDEFAULT_NODEÚ
NODE_FLAGSrL   rM   ÚSLOT_IDÚCOMMAND_FLAGSÚSEARCH_COMMANDSr•   r¤   r¨   Ú#CLUSTER_COMMANDS_RESPONSE_CALLBACKSr‚   rN   rx   ÚRESULT_CALLBACKSr4   r?   r2   r>   ÚERRORS_ALLOW_RETRYr7  rX   rY   rZ   rí   rí   3  s…  „ ØÐà€IØ€HØ€IØ€FØ!€Là˜X y°&¸,ÐG€JáÙòWðp ósZ	
ñv 	òð ó	
ñ  	˜?Ð+¨VÓ4Ùòð ó		
ó[w€Mòt 	
ð"€OðJ -Ø.Ø4ñ+Ð'ñ "Ù˜?Ð,@ÐAÐCVÓWÙØÐÑKó	
ñ 	Ú?Àó	
ñ 	òñ Uó	
ñ  	Ø�vÐÙTó	
ñ 	ØÐÑ Vó	
ñ 	˜6˜(Ð$5Ó6ÙØˆOÑJó	
ñ 	ØÐÑXó	
ñ 	˜>Ð*Ñ,RÓSóM'ÐðT 	ØØØð	ÐõNrY   rí   c            &       ó  — e Zd Zedededd fd„«       Z edgdd¬«       ed	gd
d¬«      ddddddddddddddd e«       dfde	e   de
de	ed      d	e
de	d   dede
dede	d   dede	e   de	eeee
f   geee
f   f      de	e   de	e   d e	e   d!ed"e	e   f"d#„«       «       Zd$„ Zd%„ Zd&„ Zd'„ Zd(„ Zd)ddefd*„Zd\d+„Zd,„ Zd-„ Zd.„ Zd/„ Z d0„ Z!d]d1„Z"d2„ Z#d3efd4„Z$de%e&   fd5„Z'de	e%d      fd6„Z(d^d7„Z)d8„ Z*d9„ Z+de,ddfd:„Z-d_d;„Z.d\d<„Z/d`d=„Z0	 	 	 	 	 	 	 dad>efd?„Z1d@„ Z2dAe3ded   fdB„Z4dC„ Z5dD„ Z6dE„ Z7de	e
   fdF„Z8dG„ Z9dH„ Z:dI„ Z;dJ„ Z<dK„ Z=dL„ Z>dM„ Z?	 d_dNedOe@dPeAfdQ„ZB	 	 dbdReCdPeAdSedTe	e
   fdU„ZDdPe	eA   de	e
   fdV„ZEdcdW„ZFdXeGfdY„ZHdZ„ ZId[„ ZJy)dÚRedisClusterÚurlrÓ   r^   c                 ó   —  | dd|i|¤ŽS )a  
        Return a Redis client object configured from the given URL

        For example::

            redis://[[username]:[password]]@localhost:6379/0
            rediss://[[username]:[password]]@localhost:6379/0
            unix://[username@]/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.

        rH  rX   rX   )ÚclsrH  rÓ   s      rZ   Úfrom_urlzRedisCluster.from_url-  s   € ñT Ñ%�sÐ%˜fÑ%Ð%rY   Úread_from_replicasz6Please configure the 'load_balancing_strategy' insteadrd   ©Úargs_to_warnrf   rg   Úcluster_error_retry_attemptsú+Please configure the 'retry' object insteadú6.0.0Nië  r‹   Té   Fr\   r]   Ústartup_nodesr8  r¹   rH   Úrequire_full_coverageÚreinitialize_stepsÚload_balancing_strategyÚLoadBalancingStrategyÚdynamic_startup_nodesÚaddress_remaprÍ   rÎ   Úevent_dispatcherÚpolicy_resolverrÏ   c                 ó¾	  ‡ — |€g }d|v rt        d«      ‚d|v rt        d«      ‚d}|�ƒd}t        |«      }d|v rt        d	«      ‚d|v r|d   d
k7  rt        d«      ‚|j                  |«       |j                  d«      }|j                  d|«      }|j	                  t        ||«      «       n9|�|�|j	                  t        ||«      «       nt        |«      d
k(  rt        d«      ‚|j                  dd«      ‰ _        |j                  d‰ j                  i«       t        d$i |¤Ž}|r|‰ _        nt        t        dd¬«      |¬«      ‰ _        t        |j                  dd«      |j                  dd«      |j                  dd«      «      ‰ _        |j                  dd«      }|s|rt!        |d«      st#        d«      ‚|rt!        |d«      st#        d«      ‚t!        |d«      r|€
t%        «       }‰ j&                  j(                  j+                  «       ‰ _        ‰ j&                  j.                  j+                  «       ‰ _        |‰ _        |	‰ _        d
‰ _        |‰ _        |€t;        «       ‰ _        n|‰ _        |‰ _        tA        d$||||
|||‰ j<                  |dœ	|¤Ž‰ _!        tE        ‰ j&                  jF                  «      ‰ _$        tE        ‰ j&                  jJ                  «      ‰ _&        ‰ j&                  jN                  tP        jR                  ‰ j&                  jT                  tP        jV                  ‰ j&                  jX                  tP        jX                  ‰ j&                  jZ                  tP        j\                  ‰ j&                  j^                  tP        j^                  t`        tP        jb                  i‰ _2        tP        jR                  ˆ fd„tP        jb                  ˆ fd„tP        j^                  ˆ fd „tP        jV                  ‰ jf                  tP        jX                  ‰ jh                  tP        j\                  ‰ jj                  tP        jl                  ˆ fd!„tP        jn                  ‰ jp                  tr        jR                  d"„ tr        jb                  d#„ i
‰ _:        |‰ _;        ty        ‰ «      ‰ _=        d‰ _>        t        j€                  «       ‰ _A        t…        j†                  ‰ |fi |¤Ž y)%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:
            @deprecated - Please configure the 'retry' object instead
            In case 'retry' object is set - this argument is ignored!

            Number of times to retry before raising an error when
            :class:`~.TimeoutError` or :class:`~.ConnectionError`, :class:`~.SlotNotCoveredError` or
            :class:`~.ClusterDownError` are encountered
        :param retry:
            A retry object that defines the retry strategy and the number of
            retries for the cluster client.
            In current implementation for the cluster client (starting form redis-py version 6.0.0)
            the retry object is not yet fully utilized, instead it is used just to determine
            the number of retries for the cluster client.
            In the future releases the retry object will be used to handle the cluster client retries!
        :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.

        :param maint_notifications_config:
            Configures the nodes connections to support maintenance notifications - see
            `redis.maint_notifications.MaintNotificationsConfig` for details.
            Only supported with RESP3.
            If not provided and protocol is RESP3, the maintenance notifications
            will be enabled by default (logic is included in the NodesManager
            initialization).
        :**kwargs:
            Extra arguments that will be sent into Redis instance when created
            (See Official redis-py doc for supported kwargs - the only limitation
            is that you can't provide 'retry' object as part of 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 moder¹   zKThe 'retry' argument cannot be used in kwargs when running in cluster mode.FTÚ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‰   é
   ©ÚbaseÚcap©ÚbackoffÚretriesr¯   r¦   r°   Ústrictr®   r»   r‹   z4Client caching is only supported with RESP version 3z@Maintenance notifications are only supported with RESP version 3)	rS  rK  rT  rX  rY  rÍ   rÎ   rZ  rÏ   c                 ó(   •— ‰j                  | «      gS rS   ©Úget_random_primary_or_all_nodes©Úcommand_namerâ   s    €rZ   r%  z'RedisCluster.__init__.<locals>.<lambda>L  ó   ø€ Ø×4Ñ4°\ÓBñArY   c                 ó*   •—  ‰j                   | g|¢­Ž S rS   ©Úget_nodes_from_slot©rp   rl   râ   s     €rZ   r%  z'RedisCluster.__init__.<locals>.<lambda>O  ó   ø€ Ø+�4×+Ñ+¨GÐ;°dÓ;rY   c                  ó&   •— ‰ j                  «       gS rS   ©r1  ©râ   s   €rZ   r%  z'RedisCluster.__init__.<locals>.<lambda>Q  ó   ø€ °×1FÑ1FÓ1HÑ0IrY   c                  ó(   •—  ‰j                   | i |¤ŽS rS   ©Ú_split_multi_shard_command©rl   rÓ   râ   s     €rZ   r%  z'RedisCluster.__init__.<locals>.<lambda>U  ó   ø€ Ø5�d×5Ñ5°tÐF¸vÒFrY   c                 ó   — | S rS   rX   ©rq   s    rZ   r%  z'RedisCluster.__init__.<locals>.<lambda>X  ó   € ¹rY   c                 ó   — | S rS   rX   r{  s    rZ   r%  z'RedisCluster.__init__.<locals>.<lambda>Y  ó   € ±crY   rX   )Dr;   r)   rç   rŽ   r�   r8  rœ   r+  Úuser_on_connect_funcÚ
on_connectr×   r¹   rH   r   r   ÚencoderrI   r<   rD   Ú	__class__rA  r   Úcommand_flagsr?  Ú
node_flagsrL  rV  Úreinitialize_counterrU  r/   Ú_event_dispatcherrS  ÚNodesManagerræ   r   rC  Úcluster_response_callbacksrD  Úresult_callbacksr=  r   ÚDEFAULT_KEYLESSr:  Ú
ALL_SHARDSr<  r;  ÚALL_REPLICASr>  r@  ÚDEFAULT_KEYEDÚ_command_flags_mappingr2  rß   r4  ÚMULTI_SHARDÚSPECIALÚget_special_nodesr   Ú_policies_callback_mappingÚ_policy_resolverr   Úcommands_parserÚ_aggregate_nodesÚ	threadingÚRLockÚ_lockrÙ   rä   )râ   r\   r]   rS  rO  r¹   rT  rU  rL  rV  rX  rH  rY  rÍ   rÎ   rZ  r[  rÏ   rÓ   rK  Úurl_optionsr»   s   `                     rZ   rä   zRedisCluster.__init__Y  sm  ø€ ðl Ð ØˆMà�6‰>ä'ØFóð ð �fÑô
 (Ø]óð ð
 ˆØˆ?ØˆHÜ# C›.ˆKØ˜Ñ$Ü+ð)óð ð �{Ñ" {°4Ñ'8¸AÒ'=ä+ØOóð ð �M‰M˜+Ô&Ø—:‘:˜fÓ%ˆDØ—:‘:˜f dÓ+ˆDØ× Ñ ¤¨T°4Ó!8Õ9ØÐ $Ð"2Ø× Ñ ¤¨T°4Ó!8Õ9Ü�Ó 1Ò$ä'ð4óð ð %+§J¡JÐ/CÀTÓ$JˆÔ!Ø�‰Ð+¨T¯_©_Ð=Ô>ÜÑ) &Ñ)ˆÙØˆD�JäÜ4¸!ÀÔDØ4ôˆDŒJô
 Ø�J‰J�z 7Ó+Ø�J‰JÐ(¨(Ó3Ø�J‰JÐ)¨5Ó1ó
ˆŒð
 —:‘:˜j¨$Ó/ˆÙ™EÔ+AÀ(ÈAÔ+NÜÐSÓTÐTá%Ô.DÀXÈqÔ.QÜØRóð ô " (¨AÔ.Ð3MÐ3UÜ)AÓ)CÐ&à!Ÿ^™^×9Ñ9×>Ñ>Ó@ˆÔØŸ.™.×3Ñ3×8Ñ8Ó:ˆŒØ"4ˆÔØ'>ˆÔ$Ø$%ˆÔ!Ø"4ˆÔØÐ#Ü%4Ó%6ˆDÕ"à%5ˆDÔ"Ø*ˆÔä)ð 
Ø'ØØ"7Ø"7Ø'ØØ%Ø!×3Ñ3Ø'Añ
ð ñ
ˆÔô +>Ø�N‰N×>Ñ>ó+
ˆÔ'ô !4°D·N±N×4SÑ4SÓ TˆÔð �N‰N×!Ñ!¤=×#@Ñ#@Ø�N‰N×$Ñ$¤m×&>Ñ&>Ø�N‰N×$Ñ$¤m×&=Ñ&=Ø�N‰N×#Ñ#¤]×%?Ñ%?Ø�N‰N×'Ñ'¬×)CÑ)CÜ”]×0Ñ0ðX
ˆÔ#ô ×)Ñ)ó ,ô ×'Ñ'ó *<ä×&Ñ&Ó(IÜ×$Ñ$ d×&8Ñ&8Ü×#Ñ# T§^¡^Ü×&Ñ&¨×(9Ñ(9Ü×%Ñ%ó (Gä×!Ñ! 4×#9Ñ#9Ü×*Ñ*©OÜ×(Ñ(©/ð
ð 	Ô'ð& !0ˆÔÜ-¨dÓ3ˆÔð !%ˆÔÜ—_‘_Ó&ˆŒ
ä.×7Ñ7ØÐ,ñ	
Ø06ó	
rY   c                 ó   — | S rS   rX   rs  s    rZ   Ú	__enter__zRedisCluster.__enter__g  s   € ØˆrY   c                 ó$   — | j                  «        y rS   )Úclose©râ   Úexc_typeÚ	exc_valueÚ	tracebacks       rZ   Ú__exit__zRedisCluster.__exit__j  ó   € Ø�
‰
�rY   c                 óD   — 	 | j                  «        y # t        $ r Y y w xY wrS   )r�  Ú	Exceptionrs  s    rZ   Ú__del__zRedisCluster.__del__m  ó"   € ð	Ø�J‰J�LøÜò 	Ùð	úó   ‚ “	žc                 ó°   — | j                  «       D ]4  }|j                  sŒ	 |j                  j                  j                  «        Œ6 y # t        $ r Y ŒCw xY wrS   )rß   rà   rj   Ú
disconnectÚOSError©râ   r¢   s     rZ   Údisconnect_connection_poolsz(RedisCluster.disconnect_connection_poolss  sM   € Ø—N‘NÖ$ˆDØ×$Ó$ðØ×)Ñ)×9Ñ9×DÑDÕFñ %øô ò áðús   ¢$A	Á		AÁAc                 ó   — |j                  «        | j                  s| j                  r8|j                  d«       t	        |j                  «       «      dk7  rt        d«      ‚| j                  �| j                  |«       yy)z•
        Initialize the connection, authenticate and select a database and send
         READONLY if it is set during object initialization.
        r  ÚOKzREADONLY command failedN)r€  rL  rV  Úsend_commandrP   Úread_responser4   r  )râ   ri   s     rZ   r€  zRedisCluster.on_connect|  sr   € ð
 	×ÑÔà×"Ò" d×&BÒ&Bð ×#Ñ# JÔ/Ü˜J×4Ñ4Ó6Ó7¸4Ò?Ü%Ð&?Ó@Ð@à×$Ñ$Ð0Ø×%Ñ% jÕ1ð 1rY   r¢   c                 óò   — |j                   sI| j                  5  |j                   s| j                  j                  |g«       d d d «       |j                   S |j                   S # 1 sw Y   |j                   S xY wrS   )rà   r˜  ræ   Úcreate_redis_connectionsr¬  s     rZ   Úget_redis_connectionz!RedisCluster.get_redis_connection�  sc   € Ø×$Ò$Ø—“Ø×,Ò,Ø×&Ñ&×?Ñ?ÀÀÔG÷ ð ×$Ñ$Ð$ˆt×$Ñ$Ð$÷ ð ×$Ñ$Ð$ús   ™)A"Á"A6c                 ó<   — | j                   j                  |||«      S rS   )ræ   Úget_node©râ   r\   r]   rt   s       rZ   r¶  zRedisCluster.get_node—  s   € Ø×!Ñ!×*Ñ*¨4°°yÓAÐArY   c                 ó@   — | j                   j                  t        «      S rS   )ræ   Úget_nodes_by_server_typeÚPRIMARYrs  s    rZ   r2  zRedisCluster.get_primariesš  ó   € Ø×!Ñ!×:Ñ:¼7ÓCÐCrY   c                 ó@   — | j                   j                  t        «      S rS   )ræ   r¹  ÚREPLICArs  s    rZ   r4  zRedisCluster.get_replicas�  r»  rY   c                 ó‚   — t        j                  t        | j                  j                  j                  «       «      «      S rS   )rñ   r3  r#  ræ   Únodes_cacherz   rs  s    rZ   Úget_random_nodezRedisCluster.get_random_node   s+   € Ü�}‰}œT $×"4Ñ"4×"@Ñ"@×"GÑ"GÓ"IÓJÓKÐKrY   c                 ój   — | j                   r|t        v r| j                  «       S | j                  «       S )zO
        Returns random primary or all nodes depends on READONLY mode.
        )rL  r"   rÀ  Úget_random_primary_node)râ   rj  s     rZ   rh  z,RedisCluster.get_random_primary_or_all_nodes£  s2   € ð ×"Ò" |´}Ñ'DØ×'Ñ'Ó)Ð)à×+Ñ+Ó-Ð-rY   c                 ó\   — t        | j                  j                  j                  «       «      S rS   )r#  ræ   r¿  rz   rs  s    rZ   rß   zRedisCluster.get_nodes¬  s"   € Ü�D×&Ñ&×2Ñ2×9Ñ9Ó;Ó<Ð<rY   c                 ó  — | j                  |«      }| j                  j                  j                  |«      }|�t	        |«      dk(  rt        d|› d�«      ‚|r&t	        | j                  j                  |   «      dk  ry|rd}||   S d}||   S )zš
        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˜   r‰   )Úkeyslotræ   Úslots_cacherŽ   rœ   r>   )râ   Úkeyr”   r‘   Ú
slot_cacheÚnode_idxs         rZ   Úget_node_from_keyz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à˜(Ñ#Ð#rY   c                 ó.   — | j                   j                  S )z0
        Get the cluster's default node
        )ræ   r0  rs  s    rZ   r1  zRedisCluster.get_default_nodeÃ  s   € ð ×!Ñ!×.Ñ.Ð.rY   rp   c                 ó°   —  | j                   |Ž }| j                  j                  || j                  xr |t        v |t        v r| j
                  nd«      }|gS )zN
        Returns a list of nodes that hold the specified keys' slots.
        N)Údetermine_slotræ   Úget_node_from_slotrL  r"   rV  )râ   rp   rl   r‘   r¢   s        rZ   rn  z RedisCluster.get_nodes_from_slotÉ  s]   € ð
 #ˆt×"Ñ" DÐ)ˆØ×!Ñ!×4Ñ4ØØ×#Ñ#Ò@¨´=Ð(@Ø,3´}Ñ,DˆD×(Ò(È$ó
ˆð
 ˆvˆrY   c                 óh   —  | j                   |Ž }g }|D ]  }|j                  |d   |f|dœ«       Œ |S )zV
        Splits the command with Multi-Shard policy, to the multiple commands
        r   )rl   rÓ   )Ú_get_command_keysr�   )râ   rl   rÓ   ÚkeysÚcommandsrÈ  s         rZ   rw  z'RedisCluster._split_multi_shard_commandÖ  sK   € ð &ˆt×%Ñ% tÐ,ˆØˆãˆCØ�O‰Oà! !™W c˜NØ$ñõð ð ˆrY   c                 óH   — | j                   st        d«      ‚| j                   S )zM
        Returns a list of nodes for commands with a special policy.
        z6Cannot execute FT.CURSOR commands without FT.AGGREGATE)r•  r;   rs  s    rZ   r‘  zRedisCluster.get_special_nodesç  s+   € ð ×$Ò$Ü'ØHóð ð ×$Ñ$Ð$rY   c                 óH   — t        j                  | j                  «       «      S )z/
        Returns a random primary node
        )rñ   r3  r2  rs  s    rZ   rÂ  z$RedisCluster.get_random_primary_nodeò  s   € ô �}‰}˜T×/Ñ/Ó1Ó2Ð2rY   c                 óÜ   — d}t        |t        «      r)|j                  «       D ]  \  }}|r|�Œ||i}Œ|dic S  |S |D ]+  }|r|�Œ t        |«      |«      }Œ t        |«      d«      c S  |S )zT
        Evaluate the result of a command with ResponsePolicy.ALL_SUCCEEDED
        NF)r™   rš   ro   Útype)râ   rq   Úfirst_successful_responserÈ  Úvalueru   s         rZ   Ú_evaluate_all_succeededz$RedisCluster._evaluate_all_succeededø  sŒ   € ð %)Ð!ä�cœ4Ô Ø!Ÿi™ižk‘
��UÙØ0Ñ8Ø58¸%°LÑ1à ˜<Ò'ð *ð )Ð(ó  �ÙØ0Ñ8à4B´D¸³NÀ8Ó4LÑ1à)œ4 ›>¨%Ó0Ò0ð  ð )Ð(rY   c                 ód   — |�| j                  |j                  ¬«      €y|| j                  _        y)z–
        Set the default node of the cluster.
        :param node: 'ClusterNode'
        :return True if the default node was set, else False
        ©rt   FT)r¶  Únameræ   r0  r¬  s     rZ   Úset_default_nodezRedisCluster.set_default_node  s1   € ð ˆ<˜4Ÿ=™=°4·9±9˜=Ó=ÐEØØ*.ˆ×ÑÔ'ØrY   c                 ó   — || _         y rS   )r¹   )râ   r¹   s     rZ   Ú	set_retryzRedisCluster.set_retry  s	   € Øˆ�
rY   c                 ó¤   — |€| j                  «       }|j                  €t        d|j                  › d�«      ‚|j                  j	                  «       S )ai  
        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)r1  rà   r;   rÝ  Úmonitor)râ   r5  s     rZ   râ  zRedisCluster.monitor  s\   € ð ÐØ×/Ñ/Ó1ˆKØ×'Ñ'Ð/Ü'Ø × 0Ñ 0Ð1Ð1IÐJóð ð ×+Ñ+×3Ñ3Ó5Ð5rY   c                 ó"   — t        | f|||dœ|¤ŽS )z~
        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        rZ   ÚpubsubzRedisCluster.pubsub/  s   € ô
 ˜TÐM¨°4¸dÑMÀfÑMÐMrY   c                 ó:  — |rt        d«      ‚t        | j                  | j                  | j                  j                  | j
                  | j                  | j                  | j                  | j                  | j                  | j                  || j                  ¬«      S )ac  
        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 mode)ræ   r”  rS  r‰  rˆ  rL  rV  rU  r¹   ÚlockÚtransactionrZ  )r;   ÚClusterPipelineræ   r”  rS  r‰  rˆ  rL  rV  rU  r¹   r˜  r†  )râ   rè  Ú
shard_hints      rZ   ÚpipelinezRedisCluster.pipeline6  sˆ   € ñ Ü'Ð(RÓSÐSäØ×,Ñ,Ø ×0Ñ0Ø×,Ñ,×:Ñ:Ø!×2Ñ2Ø'+×'FÑ'FØ#×6Ñ6Ø$(×$@Ñ$@Ø#×6Ñ6Ø—*‘*Ø—‘Ø#Ø!×3Ñ3ô
ð 	
rY   Úraise_on_release_errorc	           
      ó2   — |€t         } || |||||||¬«      S )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.

        ``raise_on_release_error`` indicates whether to raise an exception when
        the lock is no longer owned when exiting the context manager. By default,
        this is True, meaning an exception will be raised. If False, the warning
        will be logged and the exception will be suppressed.

        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.)r·   ÚsleepÚblockingÚblocking_timeoutÚthread_localrì  rB   )	râ   rÝ  r·   rî  rï  rð  Ú
lock_classrñ  rì  s	            rZ   rç  zRedisCluster.lockQ  s5   € ðH ÐÜˆJÙØØØØØØ-Ø%Ø#9ô	
ð 		
rY   c                 ó"   — || j                   |<   y)zSet a custom Response CallbackN)rˆ  )râ   rp   Úcallbacks      rZ   Úset_response_callbackz"RedisCluster.set_response_callback¢  s   € à3;ˆ×'Ñ'¨Ò0rY   Úrequest_policyc                ó€  — |d   j                  «       }t        |«      dk\  rB|d   › d|d   › �j                  «       | j                  v r|d   › d|d   › �j                  «       }|j                  dd«      }|�|}n| j                  j	                  |«      }|| j
                  v r| j
                  |   }| j                  |   }|t        j                  k(  r
 ||g|¢­Ž }nB|t        j                  k(  r	 ||i |¤Ž}n&|t        j                  k(  r ||d   «      }n |«       }|d   j                  «       dk(  r|| _        |S )zG
        Determines a nodes the command should be executed on.
        r   r˜   Ú r‰   r´   Núft.aggregate)Úupperrœ   rƒ  r+  rŽ   rŽ  r’  r   r�  r�  rŠ  Úlowerr•  ©	râ   rö  rl   rÓ   rp   r´   Úcommand_flagÚpolicy_callbackr—   s	            rZ   Ú_determine_nodeszRedisCluster._determine_nodes¦  sF  € ð �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à˜4×6Ñ6Ñ6Ø!×8Ñ8¸ÑFˆNà×9Ñ9¸.ÑIˆàœ]×8Ñ8Ò8Ù# GÐ3¨dÒ3‰EØœ}×8Ñ8Ò8Ù# TÐ4¨VÑ4‰EØœ}×<Ñ<Ò<Ù# D¨¡GÓ,‰Eá#Ó%ˆEà�‰7�=‰=‹?˜nÒ,Ø$)ˆDÔ!àˆrY   c                 óZ   — | j                   dk(  ry| j                  | j                   z  dk(  S )Nr   F)rU  r…  rs  s    rZ   Ú_should_reinitializedz"RedisCluster._should_reinitializedË  s1   € ð
 ×"Ñ" aÒ'Øà×,Ñ,¨t×/FÑ/FÑFÈ!ÑKÐKrY   c                 óN   — | j                   j                  |«      }t        |«      S )z€
        Calculate keyslot for a given key.
        See Keys distribution model in https://redis.io/topics/cluster-spec
        )r�  Úencoder+   )râ   rÈ  rÔ   s      rZ   rÆ  zRedisCluster.keyslotÕ  s"   € ð
 �L‰L×Ñ Ó$ˆÜ˜‹{ÐrY   c                 óp   — | j                  «       j                  } | j                  j                  |g|¢­Ž S )a£  
        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.
        )r1  rà   r”  Úget_keys)râ   rl   Ú
redis_conns      rZ   rÑ  zRedisCluster._get_command_keysÝ  s6   € ð ×*Ñ*Ó,×=Ñ=ˆ
Ø,ˆt×#Ñ#×,Ñ,¨ZÐ?¸$Ò?Ð?rY   c                 óô  — |d   }| j                   j                  |«      t        k(  r|d   S |j                  «       dk(  ry|j                  «       dv r]t	        |«      dk  rt        d|› �«      ‚t        |d   «      }|dd|z    }t	        |«      dk(  rt        j                  dt        «      S |}nY | j                  |Ž }|�t	        |«      dk(  r:|j                  «       d	v rt        j                  dt        «      S t        d
|› �«      ‚t	        |«      dk(  r| j                  |d   «      S |D �ch c]  }| j                  |«      ’Œ }}t	        |«      dk7  rt        |› d�«      ‚|j                  «       S c c}w )a  
        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   r‰   zCLIENT TRACKINGN)ÚEVALÚEVALSHAr˜   zInvalid args in command: r‹   )Ú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)rƒ  rŽ   r@  rú  rœ   r;   Úintrñ   Ú	randranger*   rÑ  rÆ  r+  )râ   rl   rp   Únum_actual_keysÚ	eval_keysrÒ  rÈ  r�   s           rZ   rÎ  zRedisCluster.determine_slotì  sŽ  € ð �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×)Ñ)¨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   Ä/E5c                 ó   — | j                   S )z.
        Get the connections' encoder
        )r�  rs  s    rZ   Úget_encoderzRedisCluster.get_encoder+  s   € ð �|‰|ÐrY   c                 ó.   — | j                   j                  S )z9
        Get the connections' key-word arguments
        )ræ   rÖ   rs  s    rZ   Úget_connection_kwargsz"RedisCluster.get_connection_kwargs1  s   € ð ×!Ñ!×3Ñ3Ð3rY   c                 óB   — t        |t        «      xr || j                  v S rS   )r™   r�   r„  ©râ   Útarget_nodess     rZ   Ú_is_nodes_flagzRedisCluster._is_nodes_flag7  s   € Ü˜,¬Ó,ÒP°ÀÇÁÐ1PÐPrY   c                 óÆ   — t        |t        «      r|}|S t        |t        «      r|g}|S t        |t        «      r|j	                  «       }|S t        dt        |«      › �«      ‚©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#  r8  rš   rz   Ú	TypeErrorr×  ©râ   r  r—   s      rZ   Ú_parse_target_nodesz RedisCluster._parse_target_nodes:  ó{   € Ü�l¤DÔ)Ø ˆEð  ˆô ˜¤kÔ2à!�NˆEð ˆô ˜¤dÔ+ð !×'Ñ'Ó)ˆEð ˆô ð&ô '+¨<Ó&8Ð%9ð;óð rY   c                 ó&   —  | j                   |i |¤ŽS rS   )Ú_internal_execute_command©râ   rl   rÓ   s      rZ   Úexecute_commandzRedisCluster.execute_commandN  s   € Ø-ˆt×-Ñ-¨tÐ>°vÑ>Ð>rY   c                 ó  — d}d}d}|j                  dd«      }| j                  j                  |d   j                  «       «      }|�$| j	                  |«      s| j                  |«      }d}|�s|�s|d   j                  «       }t        |«      dk\  rB|d   › d|d   › �j                  «       | j                  v r|d   › d|d   › �j                  «       }| j                  j                  |«      }	|	sY| j                  «       sd}
n | j                  |Ž }
|
€t        «       }nkt        t        j                  t        j                  ¬	«      }nA|	| j                   v rt        | j                   |	   ¬
«      }nt        «       }n|s|r
t        «       }|rdn| j"                  j%                  «       }d|z   }d}t'        j(                  «       }t+        |«      D ]È  }	 i }|sT | j,                  ||j.                  |dœŽ}|st1        d|› d�«      ‚t        |«      dk(  r|d   | j                  «       k(  rd}|D ]D  } | j2                  |g|¢­i |¤Ž||j4                  <   |j6                  t        j8                  k(  sŒD n  | j:                  |d   |fd|j6                  i|¤Žc S  y# t<        $ rÛ}|dkD  r¤t?        |«      | j@                  jB                  v rƒ|r| jE                  «        |dz  }|dz  }tG        |d«      rU| jI                  |d   t'        j(                  «       |z
  |jJ                  |¬«       | jM                  ||jJ                  |¬«       Y d}~�Œ~tG        |d«      r| jM                  ||jJ                  |d¬«       |‚d}~ww xY w)a!  
        Wrapper for ERRORS_ALLOW_RETRY error handling.

        It will try the number of times specified by the retries property from
        config option "self.retry" 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  r   Tr˜   rø  r‰   ©rö  Úresponse_policy©rö  )rö  r´   ú!No targets were found to execute ú command onr%  ri   ©rj  Úduration_secondsri   Úerror)r+  ri   Úretry_attempts)r+  ri   r,  Úis_internal)'r+  r“  Úresolverû  r  r  rú  rœ   rƒ  rŽ   r1  rÎ  r   r   r�  r   rŽ  r¹   Úget_retriesÚtimeÚ	monotonicr›   rÿ  rö  r;   Ú_execute_commandrÝ  r%  ÚONE_SUCCEEDEDÚ_process_resultr¥  r×  r‚  rE  r7  ÚhasattrÚ_record_command_metricri   Ú_record_error_metric)râ   rl   rÓ   Útarget_nodes_specifiedÚis_default_noder  Úpassed_targetsÚcommand_policiesrp   rý  r‘   r,  Úexecute_attemptsÚfailure_countÚ
start_timeÚ_rq   r¢   Úes                      rZ   r   z&RedisCluster._internal_execute_commandQ  s°  € ð  "'ÐØˆØˆØŸ™ N°DÓ9ˆØ×0Ñ0×8Ñ8¸¸a¹¿¹»ÓIÐàÐ%¨d×.AÑ.AÀ.Ô.QØ×3Ñ3°NÓCˆLØ%)Ð"âÒ(>Ø˜1‘g—m‘m“oˆGÜ�4‹y˜AŠ~ T¨!¡W I¨Q¨t°A©w¨iÐ"8×">Ñ">Ó"@ÀD×DVÑDVÑ"VØ! !™W˜I Q t¨A¡w iÐ0×6Ñ6Ó8�ð  ×-Ñ-×1Ñ1°'Ó:ˆLÙà×,Ñ,Ô.Ø‘Dà.˜4×.Ñ.°Ð5�DØ�<Ü'6Ó'8Ñ$ä'6Ü'4×'BÑ'BÜ(6×(DÑ(Dô(Ñ$ð
   4×#>Ñ#>Ñ>Ü'6Ø'+×'BÑ'BÀ<Ñ'Pô(Ñ$ô (7Ó'8Ñ$Ù!Ñ&<Ü.Ó0Ðñ 5™¸$¿*¹*×:PÑ:PÓ:Rˆà˜~Ñ-ÐØˆô —^‘^Ó%ˆ
äÐ'Ö(ˆAðAØ�Ù-à#8 4×#8Ñ#8ØØ'7×'FÑ'FØ#1ò$�Lñ (Ü3Ø?À¸vÀ[ÐQóð ô ˜LÓ)¨QÒ.Ø(¨™O¨t×/DÑ/DÓ/FÒFà*.˜Û(�DØ%: T×%:Ñ%:¸4Ð%QÀ$Ò%QÈ&Ñ%Q�C˜Ÿ	™	‘Nà'×7Ñ7¼>×;WÑ;WÓWÙð	 )ð ,�t×+Ñ+Ø˜‘GØñð %5×$DÑ$Dðð ñ	ò ñ7 )øôB ò !Ø! AÒ%¬$¨q«'°T·^±^×5VÑ5VÑ*VÙ&à×1Ñ1Ô3ð # aÑ'�NØ! QÑ&�Mä˜q ,Ô/Ø×3Ñ3Ø)-¨a©Ü-1¯^©^Ó-=À
Ñ-JØ'(§|¡|Ø"#ð	 4ô ð ×1Ñ1Ø"#Ø'(§|¡|Ø+8ð 2ô õ
 ô ˜q ,Ô/Ø×1Ñ1Ø"#Ø'(§|¡|Ø+8Ø(-ð	 2ô ð �GûðC!ús&   ÇBJÉ1%JÊ	M?Ê$B#M:Í-M:Í:M?c                 óî  — |d   }d}d}d}d}d}	t        | j                  «      }
t        j                  «       }|
dkD  �r]|
dz  }
	 |r| j	                  |¬«      }nX|	rV | j
                  |Ž }| j                  j                  || j                  xr |t        v |t        v r| j                  nd«      }d}	| j                  |«      }t        |«      }|r'|j                  d«        |j                  |dfi |¤Ž d} |j                  |i |¤Ž  |j                  ||fi |¤Ž}|j                  dd«       || j                   v r | j                   |   |fi |¤Ž}| j#                  |t        j                  «       |z
  |¬«       ||�|j$                  j'                  |«       S S tu        d«      }||_        | j#                  |t        j                  «       |z
  ||¬	«       |‚# t(        $ rE}|�|n||_        | j#                  |t        j                  «       |z
  |j*                  |¬	«       ‚ d}~wt,        $ rA}||_        | j#                  |t        j                  «       |z
  |j*                  |¬	«       ‚ d}~wt.        t0        f$ �r{}t3        «       r|| j5                  |«      }t7        d
j9                  t;        t<        |«      «      «      }t>        jA                  tC        |«      jD                  › d|› d|jF                  › d|› d|› d|› �«       |r|n||_        |�|jI                  «        |jJ                  }|�P|j$                  }|�B|jL                  5  |jO                  «        |jQ                  «        ddd«       n# 1 sw Y   nxY w| j                  jS                  |jF                  «       | j                  jU                  «        | j#                  |t        j                  «       |z
  |j*                  |¬	«       |‚d}~wtV        $ �r6}t3        «       rg| j5                  |«      }t7        d
j9                  t;        t<        |«      «      «      }t>        jA                  d|› d|jF                  › d|› d|› d|› �
«       | xjX                  dz  c_,        | j[                  «       r;| j                  jU                  |j\                  |j^                  fg¬«       d| _,        n| j                  ja                  |«       d}	| j#                  |t        j                  «       |z
  ||¬	«       | jc                  ||¬«       Y d}~�nûd}~wtd        $ rÝ}t3        «       rd| j5                  |«      }t7        d
j9                  t;        t<        |«      «      «      }t>        jA                  d|› d|jF                  › d|› d|› �«       |
| j                  dz  k  rt        jf                  d«       | j#                  |t        j                  «       |z
  ||¬	«       | jc                  ||¬«       Y d}~�nd}~wth        $ rÜ}t3        «       rg| j5                  |«      }t7        d
j9                  t;        t<        |«      «      «      }t>        jA                  d|› d|jF                  › d|› d|› d|› �
«       tk        |j\                  |j^                  ¬«      }d}| j#                  |t        j                  «       |z
  ||¬	«       | jc                  ||¬«       Y d}~�n4d}~wtl        tn        f$ rt}t        jf                  d«       | j                  jU                  «        |r|n||_        | j#                  |t        j                  «       |z
  |j*                  |¬	«       ‚ d}~wtp        $ rE}|r|n||_        | j#                  |t        j                  «       |z
  |j*                  |¬	«       ‚ d}~wtr        $ rX}|r|jI                  «        |r|n||_        | j#                  |t        j                  «       |z
  |j*                  |¬	«       |‚d}~ww xY w|�?|j$                  j'                  |«       n## |�|j$                  j'                  |«       w w xY w|
dkD  r�Œ6�ŒÛ)z9
        Send a command to a node in the cluster
        r   NFr‰   rÜ  ÚASKINGrÒ  )rj  r*  ri   r)  rø  z received for command z
, on node z, and connection: z using local socket address: z	, error: z!MOVED error received for command )Úadditional_startup_nodes_infoT)r+  ri   z$TRYAGAIN error received for command r˜   gš™™™™™©?zASK error received for command ra   g      Ð?zTTL exhausted.);r  r9  r0  r1  r¶  rÎ  ræ   rÏ  rL  r"   rV  r´  rk   r°  Úparse_responser+  rˆ  r6  rj   Úreleaser1   ri   r9   r4   r?   r[   Ú_extracts_socket_addressrQ   ÚjoinÚmaprO   rT   Údebugr×  rè   rÝ  rª  rà   r˜  Ú'update_active_connections_for_reconnectÚdisconnect_free_connectionsÚ move_node_to_end_of_cached_nodesÚ
initializer:   r…  r  r\   r]   Ú	move_slotr7  r@   rî  r0   rb   r2   r>   r=   r¥  r3   )râ   r5  rl   rÓ   rp   rc   ri   Úredirect_addrÚaskingÚmovedÚttlr>  r‘   ru   r@  Úsocket_addressÚargs_log_strr  Úpools                      rZ   r2  zRedisCluster._execute_commandÞ  s~  € ð �q‘'ˆØˆ
Øˆ
ØˆØˆØˆÜ�$×-Ñ-Ó.ˆô —^‘^Ó%ˆ
à�A‹gØ�1‰HˆCðoCÙØ"&§-¡-¸- -Ó"H‘KÙð /˜4×.Ñ.°Ð5�DØ"&×"4Ñ"4×"GÑ"GØØ×/Ñ/ÒL°G¼}Ð4Là"¤mÑ3ð ×4Ò4à!ó#�Kð "�Eà!×6Ñ6°{ÓC�
Ü+¨JÓ7�
ÙØ×+Ñ+¨HÔ5Ø-�J×-Ñ-¨j¸(ÑMÀfÒMØ"�FØ'�
×'Ñ'¨Ð8°Ò8Ø4˜:×4Ñ4°ZÀÑSÈFÑS�ð —
‘
˜6 4Ô(à˜d×=Ñ=Ñ=ØG˜t×>Ñ>¸wÑGØ ñ Ø$*ñ �Hð ×+Ñ+Ø!(Ü%)§^¡^Ó%5¸
Ñ%BØ)ð ,ô ð
  ðP Ð)Ø×.Ñ.×6Ñ6°zÕBð *ô Ð)Ó*ˆð
 "ˆŒØ×#Ñ#Ø Ü!Ÿ^™^Ó-°
Ñ:Ø!Øð	 	$ô 	
ð ˆøôm 'ò Ø-7Ð-C™zÈ�”Ø×+Ñ+Ø!(Ü%)§^¡^Ó%5¸
Ñ%BØ Ÿ|™|Øð	 ,ô ð ûÜ&ò ð  +�”Ø×+Ñ+Ø!(Ü%)§^¡^Ó%5¸
Ñ%BØ Ÿ|™|Øð	 ,ô ð ûÜ#¤\Ð2ó )Ü'Ô)Ø%)×%BÑ%BÀ:Ó%N�NÜ#0°·±¼#¼hÈÓ:MÓ1NÓ#O�LÜ—L‘LÜ ›7×+Ñ+Ð,Ð,BÀ<À.ÐPZÐ[f×[kÑ[kÐZlð m+Ø+5¨,Ð6SÐTbÐScÐclÐmnÐloðqôñ
 .8™z¸[�”ð
 Ð)Ø×)Ñ)Ô+ð
 )×9Ñ9�
ØÐ)Ø%×5Ñ5�DØÐ'Ø!ŸZ›Zà ×HÑHÔJà ×<Ñ<Ô>÷	 (ŸZ™Zúð ×"Ñ"×CÑCÀK×DTÑDTÔUð ×"Ñ"×-Ñ-Ô/Ø×+Ñ+Ø!(Ü%)§^¡^Ó%5¸
Ñ%BØ Ÿ|™|Øð	 ,ô ð �ûÜó %Ü'Ô)Ø%)×%BÑ%BÀ:Ó%N�NÜ#0°·±¼#¼hÈÓ:MÓ1NÓ#O�LÜ—L‘LØ;¸L¸>ÈÐT_×TdÑTdÐSeð f+Ø+5¨,Ð6SÐTbÐScÐclÐmnÐloðqôð ×)Ò)¨QÑ.Õ)Ø×-Ñ-Ô/ð ×&Ñ&×1Ñ1Ø89¿¹ÀÇÁÐ7GÐ6Hð 2ô ð 12�DÕ-à×&Ñ&×0Ñ0°Ô3Ø�Ø×+Ñ+Ø!(Ü%)§^¡^Ó%5¸
Ñ%BØ)Øð	 ,ô ð ×)Ñ)ØØ)ð *÷ ò ûô !ò Ü'Ô)Ø%)×%BÑ%BÀ:Ó%N�NÜ#0°·±¼#¼hÈÓ:MÓ1NÓ#O�LÜ—L‘LØ>¸|¸nÈJÐWb×WgÑWgÐVhð i+Ø+5¨,Ð6SÐTbÐScðeôð ˜×4Ñ4°qÑ8Ò8Ü—J‘J˜tÔ$à×+Ñ+Ø!(Ü%)§^¡^Ó%5¸
Ñ%BØ)Øð	 ,ô ð ×)Ñ)ØØ)ð *÷ ò ûô ò Ü'Ô)Ø%)×%BÑ%BÀ:Ó%N�NÜ#0°·±¼#¼hÈÓ:MÓ1NÓ#O�LÜ—L‘LØ9¸,¸ÀzÐR]×RbÑRbÐQcð d+Ø+5¨,Ð6SÐTbÐScÐclÐmnÐloðqôô !.°1·6±6ÀÇÁÔ G�Ø�à×+Ñ+Ø!(Ü%)§^¡^Ó%5¸
Ñ%BØ)Øð	 ,ô ð ×)Ñ)ØØ)ð *÷ ò ûô %Ô&9Ð:ò ô —
‘
˜4Ô Ø×"Ñ"×-Ñ-Ô/ñ
 .8™z¸[�”Ø×+Ñ+Ø!(Ü%)§^¡^Ó%5¸
Ñ%BØ Ÿ|™|Øð	 ,ô ð ûÜ ò ñ .8™z¸[�”Ø×+Ñ+Ø!(Ü%)§^¡^Ó%5¸
Ñ%BØ Ÿ|™|Øð	 ,ô ð ûÜò ÙØ×)Ñ)Ô+ñ
 .8™z¸[�”Ø×+Ñ+Ø!(Ü%)§^¡^Ó%5¸
Ñ%BØ Ÿ|™|Øð	 ,ô ð �ûðúð  Ð)Ø×.Ñ.×6Ñ6°zÕBøð Ð)Ø×.Ñ.×6Ñ6°zÕBð *úða �AŒgùs¸   ÁD8G Ç	`*Ç#A H#È#`*È/<I+É+`*É>CO4Í	!M3Í*	O4Í3M<	Í8A<O4Ï4`*ÐD+T2Ô,a Ô2`*Ô>CXØa Ø`*Ø"C[9Û3a Û9`*ÜA/]:Ý:`*ÞA _ß`*ßA`%à%`*à*a á a+rj  r*  ri   c                 ó°   — |r|j                   nd}|r|j                  nd}|r!t        |d«      rt        |j                  «      nd}t        ||||||¬«       y)z=
        Records operation duration metric directly.
        Úunknownr   r­   Ú0©rj  r*  Úserver_addressÚserver_portÚdb_namespacer+  N)r\   r]   r5  r�   r­   rG   )râ   rj  r*  ri   r+  r\   r]   r­   s           rZ   r6  z#RedisCluster._record_command_metricî  sT   € ñ #-ˆz�Š°)ˆÙ",ˆz�Š°!ˆÙ#-´'¸*ÀdÔ2KŒS�—‘ÔÐQTˆä!Ø%Ø-ØØØØö	
rY   r+  r-  r,  c           	      ó€   — t        |j                  |j                  |j                  |j                  ||�|nd|¬«       y)z6
        Records error count metric directly.
        Nr   ©rZ  r[  Únetwork_peer_addressÚnetwork_peer_portÚ
error_typer,  r-  )rF   r\   r]   )râ   r+  ri   r-  r,  s        rZ   r7  z!RedisCluster._record_error_metric  s8   € ô 	Ø%Ÿ?™?Ø"Ÿ™Ø!+§¡Ø(Ÿo™oØØ-;Ð-G™>ÈQØ#ö	
rY   c                 ó    — |€y 	 |j                   r|j                   j                  «       nd }|r|d   }|S d }|S # t        t        f$ r Y S w xY w©Nr‰   )Ú_sockÚgetsocknameÚAttributeErrorr«  )râ   ri   rS  s      rZ   rF  z%RedisCluster._extracts_socket_address  sz   € ð ÐØð	à2<×2BÒ2B�
× Ñ ×,Ñ,Ô.Èð ñ 3A˜^¨AÑ.ˆNð Ðð GKˆNð Ðøô ¤Ð(ò 	ØØÐð	ús   …/: ¶: ºAÁAc                 ó²   — 	 | j                   5  | j                  r| j                  j                  «        d d d «       y # 1 sw Y   y xY w# t        $ r Y y w xY wrS   )r˜  ræ   r�  rf  rs  s    rZ   r�  zRedisCluster.close'  sF   € ð	Ø—“Ø×%Ò%Ø×&Ñ&×,Ñ,Ô.÷ —‘ûô ò 	áð	ús+   ‚A
 Ž'>µA
 ¾AÁA
 ÁA
 Á
	AÁAr%  c                 óÌ   — || j                   v r | j                   |   ||fi |¤Ž}n*t        |«      dk(  rt        |j                  «       «      d   } | j                  |   |«      S )a  
        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>
        r‰   r   )r‰  rœ   r#  rz   r’  )râ   rp   rq   r%  rÓ   s        rZ   r4  zRedisCluster._process_result0  sj   € ð �d×+Ñ+Ñ+Ø0�$×'Ñ'¨Ñ0°¸#ÑHÀÑH‰CÜ�‹X˜Š]ô �s—z‘z“|Ó$ QÑ'ˆCà?ˆt×.Ñ.¨Ñ?ÀÓDÐDrY   c                 ó   — t        | ||«       y)a  
        This function can be used to add externally defined redis modules,
        and their namespaces to the redis client.

        ``funcname`` - A string containing the name of the function to create
        ``func`` - The function, being added to this class.
        N)Úsetattr)râ   ÚfuncnameÚfuncs      rZ   Úload_external_modulez!RedisCluster.load_external_moduleD  s   € ô 	��h Õ%rY   c                 óx  — |j                  dd«      }|j                  dd«      }|j                  dd«      }| j                  d|«      5 }	 	 |r |j                  |Ž   ||«      }|j                  «       }	|r|n|		 cddd«       S # t        $ r |�|dkD  rt        j                  |«       Y Œbw xY w# 1 sw Y   yxY w)zç
        Convenience method for executing the callable `func` as a transaction
        while watching all keys specified in `watches`. The 'func' callable
        should expect a single argument which is a Pipeline object.
        rê  NÚvalue_from_callableFÚwatch_delayTr   )r+  rë  ÚwatchÚexecuterA   r0  rî  )
râ   rl  ÚwatchesrÓ   rê  ro  rp  ÚpipeÚ
func_valueÚ
exec_values
             rZ   rè  zRedisCluster.transactionN  sº   € ð —Z‘Z ¨dÓ3ˆ
Ø$Ÿj™jÐ)>ÀÓFÐØ—j‘j °Ó5ˆØ�]‰]˜4 Ô,°Øð	ÙØ"˜Ÿ
™
 GÑ,Ù!% d£�JØ!%§¡£�JÙ)<™:À*ÐL÷ -Ñ,øô "ò Ø"Ð.°;À²?ÜŸ
™
 ;Ô/Ùðú÷ -Ð,ús*   Á	B0Á.BÂ%B-Â*B0Â,B-Â-B0Â0B9©NNN)F)r^   r8  rS   ©NN)Ngš™™™™™¹?TNNTT)TN©r^   N)Krè   ré   rê   Úclassmethodr�   r	   rK  rJ   r&   r   r  r   Úboolr
   r   r   r   r/   r%   rD   rä   r›  r¢  r¦  r­  r€  r!   r´  r¶  r2  r4  rÀ  rh  rß   rË  r1  rn  r#  rš   rw  r‘  rÂ  rÚ  rÞ  rH   rà  râ  rå  rë  rç  rõ  r   rÿ  r  rÆ  rÑ  rÎ  r  r  r  r  r"  r   r2  Úfloatr'   r6  r¥  r7  rF  r�  r   r4  rm  rè  rX   rY   rZ   rG  rG  *  sŸ  „ ð ð)&˜3ð )&¨#ð )&°.ò )&ó ð)&ñV Ø*Ð+ØGØôñ
 à*ð
ð =Øôð #ØØ7;Ø,-Ø#'Ø&*Ø"#Ø#(ØEIØ&*Ø!ØPTØ*.Ø.2Ø6:Ù*>Ó*@ØIMñ%@
à�s‰mð@
ð ð@
ð    ]Ñ 3Ñ4ð	@
ð
 '*ð@
ð ˜Ñ ð@
ð  $ð@
ð  ð@
ð !ð@
ð "*Ð*AÑ!Bð@
ð  $ð@
ð �c‰]ð@
ð   ¨%°°S°©/Ð):¸EÀ#ÀsÀ(¹OÐ)KÑ LÑMð@
ð ˜Ñ'ð@
ð ˜{Ñ+ð@
ð  # ?Ñ3ð!@
ð" (ð#@
ð$ %-Ð-EÑ$Fò%@
óóð@
òDòòòò2ð(%¨ð %¸5ó %óBòDòDòLò.ò=ó$ò(/ð¨3ó ð¸TÀ$¹Zó ð"	% 8¨D°Ñ,?Ñ#@ó 	%ó3ò)ò0	ð˜uð ¨ó ó6ó"Nó
ð< ØØØØØØ'+ñO
ð !%óO
òb<ð#Ø%2ð#à	ˆmÑ	ó#òJLòò@ð= x°¡}ó =ò~ò4òQòò(?òKòZNðj ñ
àð
ð  ð
ð ó	
ð6 !Ø(,ñ
àð
ð ð
ð ð	
ð
 ! ™ó
ð(Ø" :Ñ.ðà	�#‰óóðE¸^ó Eò(&órY   rG  c                   ó&   — e Zd Zdd„Zd„ Zd„ Zd„ Zy)r8  Nc                 ó’   — |dk(  rt        j                  |«      }|| _        || _        t	        ||«      | _        || _        || _        y )NÚ	localhost)ÚsocketÚgethostbynamer\   r]   rb   rÝ  Úserver_typerà   )râ   r\   r]   r‚  rà   s        rZ   rä   zClusterNode.__init__f  sF   € Ø�;ÒÜ×'Ñ'¨Ó-ˆDàˆŒ	ØˆŒ	Ü! $¨Ó-ˆŒ	Ø&ˆÔØ 0ˆÕrY   c                 óŠ   — d| j                   › d| j                  › d| j                  › d| j                  › d| j                  › d�S )Nz[host=z,port=z,name=z,server_type=z,redis_connection=Ú])r\   r]   rÝ  r‚  rà   rs  s    rZ   Ú__repr__zClusterNode.__repr__p  sW   € à�T—Y‘Y�Kð  Ø—I‘I�;ð Ø—I‘I�;ð Ø×+Ñ+Ð,ð - Ø $× 5Ñ 5Ð6°að	9ð	
rY   c                 óX   — t        |t        «      xr |j                  | j                  k(  S rS   )r™   r8  rÝ  )râ   Úobjs     rZ   Ú__eq__zClusterNode.__eq__y  s!   € Ü˜#œ{Ó+ÒE°·±¸D¿I¹IÑ0EÐErY   c                 ó,   — t        | j                  «      S rS   )ÚhashrÝ  rs  s    rZ   Ú__hash__zClusterNode.__hash__|  s   € Ü�D—I‘I‹ÐrY   rx  )rè   ré   rê   rä   r…  rˆ  r‹  rX   rY   rZ   r8  r8  e  s   „ ó1ò
òFórY   r8  c                   ó   — e Zd ZdZdZdZy)rW  Úround_robinÚround_robin_replicasÚrandom_replicaN)rè   ré   rê   ÚROUND_ROBINÚROUND_ROBIN_REPLICASÚRANDOM_REPLICArX   rY   rZ   rW  rW  €  s   „ Ø€KØ1ÐØ%�NrY   rW  c            	       ó‚   — e Zd ZdZddeddfd„Zej                  fdedededefd	„Z	dd
„Z
dedefd„Zdedededefd„Zy)ÚLoadBalancerz$
    Round-Robin Load Balancing
    Ústart_indexr^   Nc                 óR   — i | _         || _        t        j                  «       | _        y rS   )Úprimary_to_idxr•  r–  rC   r˜  )râ   r•  s     rZ   rä   zLoadBalancer.__init__‹  s    € Ø.0ˆÔØ +ˆÔÜ%.§^¡^Ó%5ˆ�
rY   rŒ   Ú	list_sizerV  c                 ó’   — |t         j                  k(  r| j                  |«      S | j                  |||t         j                  k(  «      S rS   )rW  r’  Ú_get_random_replica_indexÚ_get_round_robin_indexr‘  )râ   rŒ   r˜  rV  s       rZ   Úget_server_indexzLoadBalancer.get_server_index�  sL   € ð #Ô&;×&JÑ&JÒJØ×1Ñ1°)Ó<Ð<à×.Ñ.ØØØ'Ô+@×+UÑ+UÑUóð rY   c                 óz   — | j                   5  | j                  j                  «        d d d «       y # 1 sw Y   y xY wrS   )r˜  r—  Úclearrs  s    rZ   ÚresetzLoadBalancer.resetŸ  s%   € Ø�Z‹ZØ×Ñ×%Ñ%Ô'÷ �Z‰Zús   �1±:c                 ó4   — t        j                  d|dz
  «      S rc  )rñ   Úrandint)râ   r˜  s     rZ   rš  z&LoadBalancer._get_random_replica_index£  s   € Ü�~‰~˜a ¨Q¡Ó/Ð/rY   Úreplicas_onlyc                 óÒ   — | j                   5  | j                  j                  || j                  «      }|r|dk(  rd}|dz   |z  | j                  |<   |cd d d «       S # 1 sw Y   y xY wrˆ   )r˜  r—  Ú
setdefaultr•  )râ   rŒ   r˜  r¢  Úserver_indexs        rZ   r›  z#LoadBalancer._get_round_robin_index¦  s_   € ð �Z‹ZØ×.Ñ.×9Ñ9¸'À4×CSÑCSÓTˆLÙ °Ò!2à �à,8¸1Ñ,<À	Ñ+IˆD×Ñ Ñ(Ø÷ �ZŠZús   �AAÁA&)r   ry  )rè   ré   rê   rë   r  rä   rW  r�  r�   rœ  rŸ  rš  r{  r›  rX   rY   rZ   r”  r”  †  sŽ   „ ññ6 Cð 6°ó 6ð :O×9ZÑ9Zñ	àðð ðð "7ð	ð
 
óó(ð0°3ð 0¸3ó 0ð
 Øð
 Ø'*ð
 Ø;?ð
 à	ô
 rY   r”  c                   ó&  — e Zd Zddddeddddddfdee   deej                     dee	e
eef   ge
eef   f      dee   dee   d	ee   d
ee   dee   fd„Z	 	 	 d0dee   dee   dee   dee   fd„Zdeeef   fd„Z edgdd¬«      	 	 	 d1dededee   deed      def
d„«       Zded   fd„Z edd¬ «      d!„ «       Zdeddfd"„Z d#„ Z!d$„ Z"d%„ Z#d&„ Z$defd'„Z%	 	 d2d(ee&e
eef         d)efd*„Z'd3d+„Z(d,„ Z)dedede
eef   fd-„Z*d.e+dee   fd/„Z,y)4r‡  FNTrS  rç  rY  rÍ   rÎ   Úcache_factoryrZ  rÏ   c                 ó¤  — i | _         i | _        |D �ci c]  }|j                  |“Œ c}| _        d | _        d| _        || _        || _        || _        || _	        || _
        d | _        |r|| _        n8|
�|
j                  «       | _        n |	�t        |	«      j                  «       | _        || _        t        «       | _        |€t#        j$                  «       | _        n|| _        t#        j$                  «       | _        |€t+        «       | _        n|| _        | j                  j/                  dd «      | _        || _        | j5                  «        y c c}w )Nr   r¬   )r¿  rÇ  rÝ  rS  r0  Ú_epochrK  Ú_require_full_coverageÚ_dynamic_startup_nodesrª   rY  Ú_cacheÚ	get_cacher   rÖ   r”  Úread_load_balancerr–  r—  r˜  Ú_initialization_lockr/   r†  rŽ   Ú_credential_providerrÏ   rM  )râ   rS  rK  rT  rç  rX  rª   rY  rÍ   rÎ   r§  rZ  rÏ   rÓ   Úns                  rZ   rä   zNodesManager.__init__´  s=  € ð  46ˆÔØ9;ˆÔÙIVÓ5WÉÀA°a·f±f¸a±iÈÑ5WˆÔØ37ˆÔØˆŒØ ˆŒØ&;ˆÔ#Ø&;ˆÔ#Ø%:ˆÔ"Ø*ˆÔØ04ˆŒÙØˆD�KØÐ&Ø'×1Ñ1Ó3ˆD�KØÐ%Ü& |Ó4×>Ñ>Ó@ˆDŒKØ!'ˆÔÜ".£.ˆÔð ˆ<Ü"Ÿ™Ó*ˆD�JàˆDŒJô
 6?·_±_Ó5FˆÔ!àÐ#Ü%4Ó%6ˆDÕ"à%5ˆDÔ"Ø$(×$:Ñ$:×$>Ñ$>Ø! 4ó%
ˆÔ!ð +EˆÔ'à�‰ÕùòM 6Xs   “Er\   r]   rt   r^   c                 óN  — |rX|rV|dk(  rt        j                  |«      }| j                  5  | j                  j	                  t        ||¬«      «      cddd«       S |r1| j                  5  | j                  j	                  |«      cddd«       S y# 1 sw Y   yxY w# 1 sw Y   yxY w)zŒ
        Get the requested node from the cluster's nodes.
        nodes.
        :return: ClusterNode if the node exists, else None
        r  ra   N)r€  r�  r˜  r¿  rŽ   rb   r·  s       rZ   r¶  zNodesManager.get_nodeî  s„   € ñ ‘Dà�{Ò"Ü×+Ñ+¨DÓ1�Ø—“Ø×'Ñ'×+Ñ+¬M¸tÈ$Ô,OÓP÷ ‘áØ—“Ø×'Ñ'×+Ñ+¨IÓ6÷ ‘ð ÷ �ú÷ �ús   «&BÁ)BÂBÂB$r@  c                 óh  — | j                   5  | j                  |j                  |j                  ¬«      }|�|j                  t
        urJt
        |_        n>t        |j                  |j                  t
        «      }|| j                  |j                  <   | j                  |j                     }||vr|g| j                  |j                  <   nT||d   urM|d   }t        |_        |j                  |«       |j                  |«       ||d<   | j                  |k(  r|| _        ddd«       y# 1 sw Y   yxY w)z@
        Update the slot's node with the redirected one
        ra   Nr   )r˜  r¶  r\   r]   r‚  rº  r8  r¿  rÝ  rÇ  Úslot_idr½  r�   Úremover0  )râ   r@  Úredirected_nodeÚ
slot_nodesÚold_primarys        rZ   rN  zNodesManager.move_slot  s  € ð �Z‹ZØ"Ÿm™m°·±¸a¿f¹f˜mÓEˆOØÐ*à"×.Ñ.´gÑ=ä29�OÕ/ô #.¨a¯f©f°a·f±f¼gÓ"F�Ø9H�× Ñ  ×!5Ñ!5Ñ6à×)Ñ)¨!¯)©)Ñ4ˆJØ jÑ0ð 0?Ð.?�× Ñ  §¡Ò+Ø ¨
°1©Ñ5ð )¨™m�ô +2�Ô'Ø×!Ñ! +Ô.ð ×!Ñ! /Ô2à /�
˜1‘Ø×$Ñ$¨Ò3à(7�DÔ%÷C �Z‰Zús   �DD(Ä(D1r‚  z|In case you need select some load balancing strategy that will use replicas, please set it through 'load_balancing_strategy'rd   rM  r‘   rL  rV  )rŒ   r”   c                 óÌ  — |du r|€t         j                  }| j                  5  | j                  j	                  |«      �t        | j                  |   «      dk(  r t        d|› d�d| j                  › d�z   «      ‚t        | j                  |   «      dkD  rR|rP| j                  |   d   j                  }| j                  j                  |t        | j                  |   «      |«      }nX|�$|t        k(  st        | j                  |   «      dk(  rd}n/t        j                  dt        | j                  |   «      dz
  «      }| j                  |   |   cddd«       S # 1 sw Y   yxY w)	z9
        Gets a node that servers this hash slot
        TNr   rÅ  z" not covered by the cluster. z"require_full_coverage=Ú"r‰   )rW  r�  r˜  rÇ  rŽ   rœ   r>   rª  rÝ  r®  rœ  rº  rñ   r¡  )râ   r‘   rL  rV  r‚  Úprimary_namerÊ  s          rZ   rÏ  zNodesManager.get_node_from_slot-  s`  € ð&  Ñ%Ð*AÐ*IÜ&;×&GÑ&GÐ#à�Z‹ZØ×Ñ×#Ñ# DÓ)Ð1´S¸×9IÑ9IÈ$Ñ9OÓ5PÐTUÒ5UÜ)Ø˜T˜FÐ"@ÐAØ/°×0KÑ0KÐ/LÈAÐNñOóð ô
 �4×#Ñ# DÑ)Ó*¨QÒ.Ñ3Jà#×/Ñ/°Ñ5°aÑ8×=Ñ=�Ø×2Ñ2×CÑCØ ¤# d×&6Ñ&6°tÑ&<Ó"=Ð?Vó‘ð Ð#Ø¤'Ò)Ü�t×'Ñ'¨Ñ-Ó.°!Ò3ð ‘ô "Ÿ>™>¨!¬S°×1AÑ1AÀ$Ñ1GÓ-HÈ1Ñ-LÓM�à×#Ñ# DÑ)¨(Ñ3÷3 �ZŠZús   £D-EÅE#c                 ó¾   — | j                   5  | j                  j                  «       D �cg c]  }|j                  |k(  r|‘Œ c}cddd«       S c c}w # 1 sw Y   yxY w)z–
        Get all nodes with the specified server type
        :param server_type: 'primary' or 'replica'
        :return: list of ClusterNode
        N)r˜  r¿  rz   r‚  )râ   r‚  r¢   s      rZ   r¹  z%NodesManager.get_nodes_by_server_type^  sY   € ð �Z‹Zð !×,Ñ,×3Ñ3Ô5óá5�DØ×#Ñ# {Ò2ò Ø5ñ÷ ‰Zùò÷ ˆZús   �AªAÁAÁAÁAzZThis method is not used anymore internally. The startup nodes are populated automatically.z7.0.2)rf   rg   c                 óˆ   — | j                   5  |D ]  }|| j                  |j                  <   Œ 	 ddd«       y# 1 sw Y   yxY w)zK
        Populate all startup nodes and filters out any duplicates
        N)r˜  rS  rÝ  )râ   r—   r±  s      rZ   Úpopulate_startup_nodesz#NodesManager.populate_startup_nodesk  s3   € ð �Z‹ZÛ�Ø-.�×"Ñ" 1§6¡6Ò*ñ ÷ �Z‰Zús	   �!8¸Ac                 óH  — || j                   v rBt        | j                   «      dkD  r*| j                   j                  |«      }|| j                   |<   || j                  v rDt        | j                  «      dkD  r+| j                  j                  |«      }|| j                  |<   yyy)zí
        Move a failing node to the end of startup_nodes and nodes_cache so it's
        tried last during reinitialization and when selecting the default node.
        If the node is not in the respective list, nothing is done.
        r‰   N)rS  rœ   r+  r¿  )râ   rt   r¢   s      rZ   rL  z-NodesManager.move_node_to_end_of_cached_nodesw  s›   € ð ˜×*Ñ*Ñ*¬s°4×3EÑ3EÓ/FÈÒ/JØ×%Ñ%×)Ñ)¨)Ó4ˆDØ,0ˆD×Ñ˜yÑ)ð ˜×(Ñ(Ñ(¬S°×1AÑ1AÓ-BÀQÒ-FØ×#Ñ#×'Ñ'¨	Ó2ˆDØ*.ˆD×Ñ˜YÒ'ð .GÐ(rY   c                 ó:   — t        dt        «      D ]  }||vsŒ y y)Nr   FT)r›   r*   )râ   rÇ  r¡   s      rZ   Úcheck_slots_coveragez!NodesManager.check_slots_coverageˆ  s&   € ô �qÔ2Ö3ˆAØ˜Ò#Ùð 4ð rY   c                 ó|  — g }|D ]w  }|j                   �Œ | j                  d|j                  |j                  | j                  dœ| j
                  ¤Ž|_         |j                  |j                   j                  «       Œy | j                  j                  t        |t        j                  | j                  «      «       y)zV
        This function will create a redis connection to all nodes in :nodes:
        N)r\   r]   rÏ   rX   )rà   Úcreate_redis_noder\   r]   rÏ   rÖ   r�   rj   r†  Údispatchr,   r.   ÚSYNCr°  )râ   r—   Úconnection_poolsr¢   s       rZ   r³  z%NodesManager.create_redis_connections�  s¬   € ð ÐÛˆDØ×$Ñ$Ñ,Ø(>¨×(>Ñ(>ð )ØŸ™ØŸ™Ø/3×/NÑ/Nñ)ð ×,Ñ,ñ	)�Ô%ð !×'Ñ'¨×(=Ñ(=×(MÑ(MÕNð ð 	×Ñ×'Ñ'Ü4Ø ¤*§/¡/°4×3LÑ3Lóõ	
rY   c                 óp  — t        t        «       dt        f¬«      }| j                  rt|j	                  d|i«       |j	                  d|i«       |j	                  d| j
                  i«       |j	                  d|i«       t         | j                  d	i |¤Ž¬«      }|S t        d	||| j
                  |dœ|¤Ž}|S )
Nr   )rc  rd  Úsupported_errorsr\   r]   rÍ   r¹   )rj   )r\   r]   rÍ   r¹   rX   )rH   r   r4   rK  rç   r¬  r!   rª   )râ   r\   r]   rÓ   Únode_retry_configrw   s         rZ   rÃ  zNodesManager.create_redis_node¥  s¿   € ô "Ü“K¨¼oÐ=Oô
Ðð �=Š=à�M‰M˜6 4˜.Ô)Ø�M‰M˜6 4˜.Ô)Ø�M‰M˜7 D§K¡KÐ0Ô1Ø�M‰M˜7Ð$5Ð6Ô7ÜÐ&@ d×&@Ñ&@Ñ&JÀ6Ñ&JÔKˆAð ˆô ð ØØØ—k‘kØ'ñ	ð
 ñˆAð ˆrY   c                 ó  — t        ||«      }|j                  |«      }|€]d }| j                  5  | j                  j                  |«      }|r|j                  }d d d «       t        ||||«      }|||j                  <   |S # 1 sw Y   Œ(xY wrS   )rb   rŽ   r˜  r¿  rà   r8  rÝ  )	râ   r\   r]   ÚroleÚtmp_nodes_cachert   r5  rà   Úprevious_nodes	            rZ   Ú_get_or_create_cluster_nodez(NodesManager._get_or_create_cluster_nodeÉ  sŽ   € Ü! $¨Ó-ˆ	à%×)Ñ)¨)Ó4ˆØÐð 15ÐØ—“Ø $× 0Ñ 0× 4Ñ 4°YÓ ?�Ù Ø'4×'EÑ'EÐ$÷ ô & d¨D°$Ð8HÓIˆKà0;ˆO˜K×,Ñ,Ñ-àÐ÷ �ús   ®*A?Á?Bc                 ó^   — | j                   5  | j                  cddd«       S # 1 sw Y   yxY w)z�
        Get the current epoch value. This method exists primarily to allow
        tests to mock the epoch fetch and control race condition timing.
        N)r˜  r©  rs  s    rZ   Ú
_get_epochzNodesManager._get_epochÞ  s   € ð
 �Z‹ZØ—;‘;÷ �ZŠZús   �#£,rC  Údisconnect_startup_nodes_poolsc                 ó>  — | j                  «        i }i }g }d}d}| j                  }d}	| j                  «       }
|€g }| j                  5  | j                  5  |
| j
                  k7  r	 ddd«       ddd«       y	 ddd«       | j                  5  t        | j                  j                  «       «      }ddd«       |D ��cg c]  \  }}t        ||«      ‘Œ }}}t        «       rKt        j                  d|D �cg c]  }|j                  ‘Œ c}› dD �cg c]  }|j                  ‘Œ c}› �«       g ¢|¢­D �]ˆ  }	 |j                  r|j                  }�n t        «       r€|j                  dd«      }|j                  dd«      }| j                   r| j                   j"                  nd}t        j                  d|j$                  › d	|j&                  › d
|› d|› d|› �
«        | j(                  |j$                  |j&                  fd| j                   i|¤Ž}|| j                  j                  «       v r|| j                  |j                     _        n||_        	 t+        |j-                  d«      «      }|rS|j.                  j                  5  |j.                  j1                  «        |j.                  j3                  «        ddd«       d}t;        |«      dk(  rDt;        |d   d   d   «      dk(  r-t;        | j                  «      dk(  r|j$                  |d   d   d<   |D �]‹  }|d   }t+        |d   «      }|dk(  r|j$                  }t=        |d   «      }| j?                  ||«      \  }}g }| jA                  ||tB        |«      }|jE                  |«       |dd }|D ]\  }t+        |d   «      }t=        |d   «      }| j?                  ||«      \  }}| jA                  ||tF        |«      }|jE                  |«       Œ^ tI        t=        |d   «      t=        |d   «      dz   «      D ]†  }||vr|||<   Œ||   d   }|j                  |j                  k7  sŒ/|jE                  |j                  › d|j                  › d|› �«       t;        |«      dkD  sŒkt7        ddjK                  |«      › �«      ‚ �ŒŽ | jM                  |«      }|s�Œ‰ n |st7        dtO        |	«      › �«      |	‚| jQ                  tS        |j                  «       «      «       |s+| jT                  rt7        dt;        |«      › dtV        › d�«      ‚| j                  5  || _,        || _-        | j]                  tB        «      d   | _/        | j`                  r|| _        | xj
                  dz  c_        ddd«       ddd«       y# 1 sw Y   �Œ(xY w# 1 sw Y   �ŒýxY wc c}}w c c}w c c}w # 1 sw Y   �ŒxY w# t4        $ r t7        d«      ‚w xY w# t8        $ r}|}	Y d}~�ŒÌd}~ww xY w# 1 sw Y   ŒzxY w# 1 sw Y   yxY w)aß  
        Initializes the nodes cache, slots cache and redis connections.
        :startup_nodes:
            Responsible for discovering other nodes in the cluster
        :disconnect_startup_nodes_pools:
            Whether to disconnect the connection pool of the startup nodes
            after the initialization is complete. This is useful when the
            startup nodes are not part of the cluster and we want to avoid
            keeping the connection open.
        :additional_startup_nodes_info:
            Additional nodes to add temporarily to the startup nodes.
            The additional nodes will be used just in the process of extraction of the slots
            and nodes information from the cluster.
            This is useful when we want to add new nodes to the cluster
            and initialize the client
            with them.
            The format of the list is a list of tuples, where each tuple contains
            the host and port of the node.
        FNz*Topology refresh: using additional nodes: z; and startup nodes: r¿   znot setr¼   z3Topology refresh: Creating new Redis connection to r`   z; with socket_timeout: z, and socket_connect_timeout: z#, and maint_notifications enabled: rÏ   r  z(Cluster mode is not enabled on this nodeTr‰   r   r˜   r†   r‹   z vs z
 on slot: rR  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...)1rŸ  rÖ   rÐ  r¯  r˜  r©  ÚtuplerS  rz   r8  r[   rT   rI  rÝ  rà   rŽ   rÏ   rÜ   r\   r]   rÃ  rP   r"  rj   rJ  rK  r=   r;   r¥  rœ   r  Úremap_host_portrÎ  rº  r�   r½  r›   rG  rÁ  r�   r³  r#  rª  r*   r¿  rÇ  r¹  r0  r«  ) râ   rC  rÑ  rÌ  Ú	tmp_slotsÚdisagreementsÚstartup_nodes_reachableÚfully_coveredrÓ   Ú	exceptionÚepochrS  r\   r]   Úadditional_startup_nodesr¢   Ústartup_noderw   r¿   r¼   Úmaint_enabledÚcluster_slotsr@  r‘   Úprimary_nodeÚnodes_for_slotr5  Úreplica_nodesÚreplica_nodeÚtarget_replica_noder¡   Útmp_slots                                    rZ   rM  zNodesManager.initializeæ  sa  € ð0 	�
‰
ŒØˆØˆ	ØˆØ"'ÐØˆØ×'Ñ'ˆØˆ	Ø—‘Ó!ˆØ(Ð0Ø,.Ð)à×&Ó&Ø—“Ø˜DŸK™KÒ'ð ÷	 ÷ 'Ð&à'÷ ð —“Ü % d×&8Ñ&8×&?Ñ&?Ó&AÓ B�÷ ñ ;Xô(Ù:W©J¨D°$”˜D $Õ'Ð:Wð %ñ (ô $Ô%Ü—‘Ø@ÑXpÓAqÑXpÐPTÀ$Ç)Ã)ÐXpÑAqÐ@rð s*ÙANÓ*OÁ¸¨4¯9«9ÀÑ*OÐ)PðRôð
 !L -Ð KÐ2JÕ K�ð6Ø#×4Ò4Ø(×9Ñ9šô 0Ô1Ø-3¯Z©ZÐ8HÈ)Ó-T˜NØ5;·Z±ZØ 8¸)ó6Ð2ð
 $(×#BÒ#Bð !%× ?Ñ ?× GÒ Gà%*ð *ô
 #ŸL™LØ UØ#/×#4Ñ#4Ð"5°Q°|×7HÑ7HÐ6Ið J8Ø8FÐ7Gð H;Ø;QÐ:Rð SDà#0 /ð!3ôð 3˜D×2Ñ2Ø(×-Ñ-Ø(×-Ñ-ñð 8<×7VÑ7Vðð %ñ	˜ð (¨4×+=Ñ+=×+DÑ+DÓ+FÑFØUV˜D×.Ñ.¨|×/@Ñ/@ÑAÕRà<=˜LÔ9ðä(4°Q×5FÑ5FÀÓ5WÓ(X˜Ù9Ø!"×!2Ñ!2×!8Ó!8ð !"× 1Ñ 1× YÑ YÔ [à !× 1Ñ 1× MÑ MÔ O÷ "9ð /3Ð+ô ˜Ó&¨!Ò+Ü˜M¨!Ñ,¨QÑ/°Ñ2Ó3°qÒ8Ü˜D×.Ñ.Ó/°1Ò4à-9×->Ñ->�M !Ñ$ QÑ'¨Ñ*ä)�DØ#'¨¡7�LÜ'¨°Q©Ó8�DØ˜r’zØ+×0Ñ0˜Ü˜|¨A™Ó/�DØ!%×!5Ñ!5°d¸DÓ!A‘J�D˜$à%'�Nà"&×"BÑ"BØ˜d¤G¨_ó#�Kð #×)Ñ)¨+Ô6à$(¨¨ H�MÛ(5˜Ü+¨L¸©OÓ<˜Ü" <°¡?Ó3˜Ø%)×%9Ñ%9¸$ÀÓ%E™
˜˜dØ.2×.NÑ.NØ  $¬°ó/Ð+ð '×-Ñ-Ð.AÕBð )6ô #¤3 t¨A¡w£<´°T¸!±W³ÀÑ1AÖB˜Ø IÑ-Ø+9˜I ašLð (1°¡|°A¡˜HØ'Ÿ}™}°×0@Ñ0@Ó@Ø -× 4Ñ 4Ø'/§}¡} o°T¸+×:JÑ:JÐ9KÈ:ÐVWÐUXÐ$Yô!"ô $' }Ó#5¸Ó#9Ü*?ð+8Ø8<¿	¹	À-Ó8PÐ7Qð)Só+&ð %&ò Cð3 *ðV !%× 9Ñ 9¸)Ó D�Û ñ ðm !Lñp +Ü+ð+Ü+.¨y«>Ð*:ð<óð !ð!ð ×)Ñ)¬$¨×/EÑ/EÓ/GÓ*HÔIñ ! T×%@Ò%@ô ,ØOÜ˜9“~Ð& dÔ+CÐ*Dð E!ð"óð ð —“Ø#2�Ô Ø#,�Ô à$(×$AÑ$AÄ'Ó$JÈ1Ñ$M�Ô!Ø×.Ò.à)8�DÔ&à—’˜qÑ •÷ ÷ 'Ð&ß‘ú÷ ‘üó(ùò
 BrùÚ*O÷T "9Ñ!8ûô )ò Ü3ØFóð ðûô
 !ò ð !"�IÝûð	ú÷r �ú÷ 'Ð&úsî   Á	XÁVÁ'XÁ9XÂ$V,Â1XÂ>V9Ã!XÃ5V?ÄXÄWÄ#XÄ8DW.É2WÊ5W	Ê:WËW.ËFXÑ
;XÒ4XÒ<A>XÔ:AXÖXÖV)	Ö$XÖ,V6	Ö1X×	W×W×W+×+W.×.	X×7W?×9X×?XØXØX	ØXØXc                 óö   — | j                   5  d | _        t        | j                  j	                  «       «      }d d d «       D ])  }|j
                  sŒ|j
                  j                  «        Œ+ y # 1 sw Y   Œ8xY wrS   )r˜  r0  rÓ  r¿  rz   rà   r�  )râ   r—   r¢   s      rZ   r�  zNodesManager.close´	  s^   € Ø�Z‹ZØ $ˆDÔÜ˜$×*Ñ*×1Ñ1Ó3Ó4ˆE÷ ó ˆDØ×$Ó$Ø×%Ñ%×+Ñ+Õ-ñ ÷ ˆZús   �+A/Á/A8c                 óX   — 	 | j                   j                  «        y # t        $ r Y y w xY wrS   )r®  rŸ  r  rs  s    rZ   rŸ  zNodesManager.reset¼	  s+   € ð	Ø×#Ñ#×)Ñ)Õ+øÜò 	áð	ús   ‚ �	)¨)c                 óH   — | j                   r| j                  ||f«      S ||fS )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.
        )rY  )râ   r\   r]   s      rZ   rÔ  zNodesManager.remap_host_portÃ	  s,   € ð ×ÒØ×%Ñ% t¨T lÓ3Ð3Ø�TˆzÐrY   ri   c           	      ó¦  — t        |j                  |j                  «      }| j                  5  t	        | j
                  j                  «       «      D ]i  }|j                  sŒ|j                  j                  j                  }|t        |j                  d«      |j                  d«      «      k(  sŒ^|c cd d d «       S  	 d d d «       y # 1 sw Y   y xY w)Nr\   r]   )rb   r\   r]   r˜  rÓ  r¿  rz   rà   rj   rÖ   rŽ   )râ   ri   rt   r¢   Ú	conn_argss        rZ   Úfind_connection_ownerz"NodesManager.find_connection_ownerÍ	  s¢   € Ü! *§/¡/°:·?±?ÓCˆ	Ø�Z‹ZÜ˜d×.Ñ.×5Ñ5Ó7Ö8�Ø×(Ó(Ø $× 5Ñ 5× EÑ E× WÑ W�IØ ¤MØ!Ÿ™ fÓ-¨y¯}©}¸VÓ/Dó%ó ð  $™÷ ‰ZÙ8÷ ð ÷ ð ús   ­3CÁ!ACÂ/CÂ<CÃCrw  )FNN)NTry  )-rè   ré   rê   r(   r#  r8  r   r–  r—  r
   r   r�   r  r   r   r   r/   rD   rä   r¶  r   r0   r:   rN  rJ   r{  rW  r   rÏ  r¹  rK   r¾  rL  rÁ  r³  rÃ  rÎ  rÐ  r   rM  r�  rŸ  rÔ  r'   rê  rX   rY   rZ   r‡  r‡  ³  sx  „ ð Ø#Ø*.Ø"Ø,ØPTØ*.Ø.2Ø9=Ø6:ØIMñ8à˜KÑ(ð8ð
 �y—‘Ñ'ð8ð   ¨%°°S°©/Ð):¸EÀ#ÀsÀ(¹OÐ)KÑ LÑMð8ð ˜Ñ'ð8ð ˜{Ñ+ð8ð  Ð 5Ñ6ð8ð # ?Ñ3ð8ð %-Ð-EÑ$Fó8ðx #Ø"Ø#'ñ	à�s‰mðð �s‰mðð ˜C‘=ð	ð
 
�+Ñ	óð.%8˜5 ¨:Ð!5Ñ6ó %8ñP Ø#�_ðVð ôð $)ØCGØ?Cñ'4àð'4ð !ð'4ð "*Ð*?Ñ!@ð	'4ð
 ˜gÐ&:Ñ;Ñ<ð'4ð 
ò'4óð'4ðR°GÐ<PÑ4Qó ñ ØkØôñ/ó	ð/ð/¸#ð /À$ó /ò"ò
ò*"òHð*˜Có ð JNØ/3ñL!à'/°°U¸3À¸8±_Ñ0EÑ'FðL!ð )-óL!ó\.òð Cð ¨sð °u¸SÀ#¸X±ó ð
°
ð 
¸xÈÑ?Tô 
rY   r‡  c                   óˆ   ‡ — e Zd ZdZ	 	 	 	 	 dded   fˆ fd„Zdd„Zd„ Zd„ Zd„ Z	d	„ Z
d
„ Zd„ Z	 dd„Zd„ Zd„ Zd„ Zd„ Zˆ xZS )rä  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
    rZ  r/   c                 ój  •— d| _         | j                  ||||«       | j                   €dn$|j                  | j                   «      j                  }|| _        i | _        | j                  «       | _        |€t        «       | _        n|| _        t        ‰	| �(  d||j                  || j                  dœ|¤Ž y)aL  
        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)rj   r�  Úpush_handler_funcrZ  rX   )r¢   Úset_pubsub_noder´  rj   ÚclusterÚnode_pubsub_mappingÚ_pubsubs_generatorr/   r†  Úsuperrä   r�  )
râ   Úredis_clusterr¢   r\   r]   rí  rZ  rÓ   rj   r‚  s
            €rZ   rä   zClusterPubSub.__init__ã	  s½   ø€ ð. ˆŒ	Ø×Ñ˜]¨D°$¸Ô=ð �y‰yÐ ñ à×3Ñ3°D·I±IÓ>×NÑNð 	ð
 %ˆŒØ#%ˆÔ Ø"&×"9Ñ"9Ó";ˆÔØÐ#Ü%4Ó%6ˆDÕ"à%5ˆDÔ"Ü‰Ñð 	
Ø+Ø!×)Ñ)Ø/Ø!×3Ñ3ñ		
ð
 ó	
rY   c                 ó  — |�2| j                  |||j                  |j                  «       |}|| _        y|�3|�1|j                  ||¬«      }| j                  ||||«       |}|| _        yt	        ||g«      du rt        d«      ‚d}|| _        y)aN  
        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
        Nra   Tz6Passing a host requires passing a port, and vice versa)Ú_raise_on_invalid_noder\   r]   r¶  Úanyr6   r¢   )râ   rï  r¢   r\   r]   Úpubsub_nodes         rZ   rî  zClusterPubSub.set_pubsub_node
  s¥   € ð Ðà×'Ñ'¨°°t·y±yÀ$Ç)Á)ÔLØˆKð  ˆ�	ð Ð $Ð"2à×#Ñ#¨°DÐ#Ó9ˆDØ×'Ñ'¨°°t¸TÔBØˆKð  ˆ�	ô �$˜�Ó $Ñ&äÐTÓUÐUð ˆKàˆ�	rY   c                 ó   — | j                   S )zJ
        Get the node that is being used as the pubsub connection
        )r¢   rs  s    rZ   Úget_pubsub_nodezClusterPubSub.get_pubsub_node1
  s   € ð �y‰yÐrY   c                 ód   — |�|j                  |j                  ¬«      €t        d|› d|› d�«      ‚y)zl
        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)r¶  rÝ  r;   )râ   ró  r¢   r\   r]   s        rZ   rõ  z$ClusterPubSub._raise_on_invalid_node7
  sF   € ð
 ˆ<˜=×1Ñ1¸D¿I¹IÐ1ÓFÐNÜ'Ø˜�v˜Q˜t˜fÐ$AÐBóð ð OrY   c                 óÄ  — | j                   �€©| j                  €Ët        |«      dkD  rp|d   }| j                  j	                  |«      }| j                  j
                  j                  || j                  j                  | j                  j                  «      }n| j                  j                  «       }|| _
        | j                  j                  |«      }|j                  | _        | j                  j                  «       | _         | j                   j                  | j                  «       | j                  �/| j                   j                   j#                  | j                  «       | j$                  j'                  t)        | j                   | j                  t*        j,                  | j.                  «      «       | j                   } | j0                  ||j2                  g|¢­Ž  y)zˆ
        Execute a subscribe/unsubscribe command.

        Taken code from redis-py and tweak to make it work within a cluster.
        Nr‰   )ri   rj   rœ   rï  rÆ  ræ   rÏ  rL  rV  rÀ  r¢   r´  rk   Úregister_connect_callbackr€  rí  Ú_parserÚset_pubsub_push_handlerr†  rÄ  r-   r.   rÅ  r˜  Ú_executer°  )râ   rl   r~   r‘   r¢   rà   ri   s          rZ   r"  zClusterPubSub.execute_commandA
  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Ø—‘×'Ñ'×?Ñ?À×@VÑ@VÔWØ×"Ñ"×+Ñ+Ü7Ø—O‘O T×%9Ñ%9¼:¿?¹?ÈDÏJÉJóôð
 —_‘_ˆ
Øˆ�‰�j *×"9Ñ"9ÐA¸DÔArY   c                 óÖ   — 	 | j                   |j                     S # t        $ rD |j                  j	                  | j
                  ¬«      }|| j                   |j                  <   |cY S w xY w)N)rí  )rð  rÝ  r{   rà   rå  rí  )râ   r¢   rå  s      rZ   Ú_get_node_pubsubzClusterPubSub._get_node_pubsubk
  sj   € ð	Ø×+Ñ+¨D¯I©IÑ6Ð6øÜò 	Ø×*Ñ*×1Ñ1Ø"&×"8Ñ"8ð 2ó ˆFð 39ˆD×$Ñ$ T§Y¡YÑ/ØŠMð	ús   ‚ ›A
A(Á'A(c                 ó    — t        t        | j                  «      «      D ]-  }t        | j                  «      }|j                  «       }|€Œ+|c S  y rS   )r›   rœ   rð  Únextrñ  Úget_message)râ   r?  rå  Úmessages       rZ   Ú_sharded_message_generatorz(ClusterPubSub._sharded_message_generatoru
  sJ   € Ü”s˜4×3Ñ3Ó4Ö5ˆAÜ˜$×1Ñ1Ó2ˆFØ×(Ñ(Ó*ˆGØÑ"Ø’ð	 6ð
 rY   c              #   ól   K  — 	 t        | j                  j                  «       «      }|E d {  –—†  Œ.7 Œ­wrS   )r#  rð  rz   )râ   Úcurrent_nodess     rZ   rñ  z ClusterPubSub._pubsubs_generator}
  s3   è ø€ ØÜ  ×!9Ñ!9×!@Ñ!@Ó!BÓCˆMØ$×$Ð$ð à$ús   ‚*4¬2­4c                 ó®  — |r+| j                   |j                     j                  ||¬«      }n| j                  «       }|€y t	        |d   «      dk(  r¶|d   | j
                  v r¥| j
                  j                  |d   «       | j                  j                  |d   d «       | j                  j                  |d   «      }| j                   |j                     j                  du r%| j                   j                  |j                  «       | j                  s2| j                  s&| j                  s| j                  j                  «        | j                   s|ry |S )N)Úignore_subscribe_messagesr·   r×  Úsunsubscriber~   F)rð  rÝ  r  r  rP   Ú"pending_unsubscribe_shard_channelsrµ  Úshard_channelsr+  rï  rË  Ú
subscribedÚchannelsÚpatternsÚsubscribed_eventrž  r
  )râ   r
  r·   r5  r  r¢   s         rZ   Úget_sharded_messagez!ClusterPubSub.get_sharded_message‚
  s.  € ñ Ø×.Ñ.¨{×/?Ñ/?Ñ@×LÑLØ*CÈWð 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ØØˆrY   c                 óh  — |rt        |d   |dd  «      }t        j                  |«      }|j                  |«       |j	                  «       D ]å  \  }}| j
                  j                  |«      }| j                  |«      }|r |j                  di ||i¤Ž n|j                  |«       | j                  j                  |j                  «       | j                  j                  | j                  |d i«      «       |j                  sŒ¸| j                  rŒÅ| j                  j                  «        d| _        Œç y )Nr   r‰   rX   )r$   rš   Úfromkeysrç   ro   rï  rË  r  Ú
ssubscriber  r  Údifference_updateÚ_normalize_keysr  r  ÚsetÚhealth_check_response_counter)râ   rl   rÓ   Ú
s_channelsÚ	s_channelÚhandlerr¢   rå  s           rZ   r  zClusterPubSub.ssubscribeœ
  s  € ÙÜ  Q¡¨¨a¨b¨Ó2ˆDÜ—]‘] 4Ó(ˆ
Ø×Ñ˜&Ô!Ø",×"2Ñ"2Ö"4ÑˆI�wØ—<‘<×1Ñ1°)Ó<ˆDØ×*Ñ*¨4Ó0ˆFÙØ!�×!Ñ!Ñ9 Y°Ð$8Ó9à×!Ñ! )Ô,Ø×Ñ×&Ñ& v×'<Ñ'<Ô=Ø×3Ñ3×EÑEØ×$Ñ$ i°Ð%6Ó7ôð × Ó ¨¯«Ø×%Ñ%×)Ñ)Ô+Ø56�Õ2ñ #5rY   c                 ó  — |rt        |d   |dd  «      }n| j                  }|D ]d  }| j                  j                  |«      }| j	                  |«      }|j                  |«       | j                  j                  |j                  «       Œf y rˆ   )r$   r  rï  rË  r  r  r  rç   )râ   rl   r  r¢   Úps        rZ   r  zClusterPubSub.sunsubscribe°
  s}   € ÙÜ  Q¡¨¨a¨b¨Ó2‰Dà×&Ñ&ˆDãˆIØ—<‘<×1Ñ1°)Ó<ˆDØ×%Ñ% dÓ+ˆAØ�N‰N˜9Ô%Ø×3Ñ3×:Ñ:Ø×4Ñ4õñ	 rY   c                 óH   — | j                   �| j                   j                  S y)zH
        Get the Redis connection of the pubsub connected node.
        N)r¢   rà   rs  s    rZ   r´  z"ClusterPubSub.get_redis_connection¾
  s#   € ð �9‰9Ð Ø—9‘9×-Ñ-Ð-ð !rY   c                 óÂ   — | j                   r| j                   j                  «        | j                  j                  «       D ]  }|j                   j                  «        Œ y)z3
        Disconnect the pubsub connection.
        N)ri   rª  rð  rz   )râ   rå  s     rZ   rª  zClusterPubSub.disconnectÅ
  sF   € ð �?Š?Ø�O‰O×&Ñ&Ô(Ø×.Ñ.×5Ñ5Ö7ˆFØ×Ñ×(Ñ(Õ*ñ 8rY   )NNNNNrw  )Fg        N)rè   ré   rê   rë   r   rä   rî  rù  rõ  r"  r  r  rñ  r  r  r  r´  rª  Ú__classcell__©r‚  s   @rZ   rä  rä  Ú	  su   ø„ ñð ØØØØ8<ñ+
ð #Ð#4Ñ5õ+
óZ òBòò(BòTòò%ð IMóò47ò(ò.ö+rY   rä  c                   ó’  ‡ — e Zd ZdZeeeeefZ	dhZ
ddhZh d£Z edgdd¬«      d	d	d	d
d	ddd	d	d
 e«       d	fdddddeeeef      deeeef      deed      dedee   dededee   deded   fˆ fd„«       Zd„ Zd„ Zd„ Zd „ Zd!„ Zd"„ Zd#„ Z d$„ Z!d%„ Z"d5d&ed'ee#   fd(„Z$d)„ Z%	 d6d*„Z&d+„ Z'd,„ Z(d-„ Z)d.„ Z*d/„ Z+d0„ Z,d1„ Z-d2„ Z.d3„ Z/d4„ Z0ˆ xZ1S )7ré  z8
    Support for Redis pipeline
    in cluster mode
    ÚUNWATCHÚWATCH¾   ÚEXECÚDISCARDr$  rO  rP  rQ  rM  NFr‹   rR  ræ   r‡  r”  r   r‰  rˆ  rS  r8  rL  rV  rU  r¹   r[  rZ  r/   c                 óD  •‡ — g ‰ _         |‰ _        |‰ _        d‰ _        |xs$ ‰ j                  j
                  j                  «       ‰ _        |r|ng ‰ _        |‰ _	        |‰ _
        ‰ j                  j                  j                  «       ‰ _        |‰ _        d‰ _        |	‰ _        |
�|
‰ _        nt#        t%        dd¬«      |¬«      ‰ _        t'        |j)                  dd	«      |j)                  d
d«      |j)                  dd«      «      ‰ _        |€t-        j.                  «       }|‰ _        t2        ‰‰ �h  ‰ _        |st9        ‰ «      n
t;        ‰ «      ‰ _        ‰ j                  j>                  t@        jB                  ‰ j                  jD                  t@        jF                  ‰ j                  jH                  t@        jH                  ‰ j                  jJ                  t@        jL                  ‰ j                  jN                  t@        jN                  tP        t@        jR                  i‰ _*        t@        jB                  ˆ fd„t@        jR                  ˆ fd„t@        jN                  ˆ fd„t@        jF                  ‰ jV                  t@        jH                  ‰ jX                  t@        jL                  ‰ jZ                  t@        j\                  ˆ fd„t@        j^                  ‰ j`                  tb        jB                  d„ tb        jR                  d„ i
‰ _2        |‰ _3        |€ti        «       ‰ _5        y|‰ _5        y)rø  Fr   Nr‰   r^  r_  rb  r¯   r¦   r°   re  r®   c                 ó(   •— ‰j                  | «      gS rS   rg  ri  s    €rZ   r%  z*ClusterPipeline.__init__.<locals>.<lambda>+  rk  rY   c                 ó*   •—  ‰j                   | g|¢­Ž S rS   rm  ro  s     €rZ   r%  z*ClusterPipeline.__init__.<locals>.<lambda>.  rp  rY   c                  ó&   •— ‰ j                  «       gS rS   rr  rs  s   €rZ   r%  z*ClusterPipeline.__init__.<locals>.<lambda>0  rt  rY   c                  ó(   •—  ‰j                   | i |¤ŽS rS   rv  rx  s     €rZ   r%  z*ClusterPipeline.__init__.<locals>.<lambda>4  ry  rY   c                 ó   — | S rS   rX   r{  s    rZ   r%  z*ClusterPipeline.__init__.<locals>.<lambda>7  r|  rY   c                 ó   — | S rS   rX   r{  s    rZ   r%  z*ClusterPipeline.__init__.<locals>.<lambda>8  r~  rY   )6Úcommand_stackræ   r”  Úrefresh_table_asapr‚  rD  r   r‰  rS  rL  rV  rA  rƒ  rˆ  r…  rU  r¹   rH   r   r   rŽ   r�  r–  r—  r˜  rò  r"  Úparent_execute_commandÚPipelineStrategyÚTransactionStrategyÚ_execution_strategyr=  r   rŠ  r:  r‹  r<  r;  rŒ  r>  r@  r�  rŽ  r2  rß   r4  r�  r�  r‘  r   r’  r“  r/   r†  )râ   ræ   r”  r‰  rˆ  rS  rL  rV  rO  rU  r¹   rç  rè  r[  rZ  rÓ   r‚  s   `               €rZ   rä   zClusterPipeline.__init__á
  s  ù€ ð4  ˆÔØ*ˆÔØ.ˆÔØ"'ˆÔàÒF §¡× ?Ñ ?× DÑ DÓ Fð 	Ôñ /<™]ÀˆÔØ"4ˆÔØ'>ˆÔ$Ø!Ÿ^™^×9Ñ9×>Ñ>Ó@ˆÔØ*DˆÔ'Ø$%ˆÔ!Ø"4ˆÔØÐØˆD�JäÜ4¸!ÀÔDØ4ôˆDŒJô
 Ø�J‰J�z 7Ó+Ø�J‰JÐ(¨(Ó3Ø�J‰JÐ)¨5Ó1ó
ˆŒð
 ˆ<Ü—?‘?Ó$ˆDØˆŒ
Ü&+¡gÑ&=ˆÔ#á*5Ô˜TÔ"Ô;NÈtÓ;Tð 	Ô ð �N‰N×!Ñ!¤=×#@Ñ#@Ø�N‰N×$Ñ$¤m×&>Ñ&>Ø�N‰N×$Ñ$¤m×&=Ñ&=Ø�N‰N×#Ñ#¤]×%?Ñ%?Ø�N‰N×'Ñ'¬×)CÑ)CÜ”]×0Ñ0ðX
ˆÔ#ô ×)Ñ)ó ,ô ×'Ñ'ó *<ä×&Ñ&Ó(IÜ×$Ñ$ d×&8Ñ&8Ü×#Ñ# T§^¡^Ü×&Ñ&¨×(9Ñ(9Ü×%Ñ%ó (Gä×!Ñ! 4×#9Ñ#9Ü×*Ñ*©OÜ×(Ñ(©/ð
ð 	Ô'ð& !0ˆÔàÐ#Ü%4Ó%6ˆDÕ"à%5ˆDÕ"rY   c                 ó.   — t        | «      j                  › S ©rø  )r×  rè   rs  s    rZ   r…  zClusterPipeline.__repr__B  s   € ä�t“*×%Ñ%Ð&Ð'rY   c                 ó   — | S r7  rX   rs  s    rZ   r›  zClusterPipeline.__enter__F  s   € àˆrY   c                 ó$   — | j                  «        y©rø  N©rŸ  rž  s       rZ   r¢  zClusterPipeline.__exit__J  s   € à�
‰
�rY   c                 óD   — 	 | j                  «        y # t        $ r Y y w xY wrS   )rŸ  r¥  rs  s    rZ   r¦  zClusterPipeline.__del__N  r§  r¨  c                 ó@   — t        | j                  j                  «      S r7  )rœ   r5  Úcommand_queuers  s    rZ   Ú__len__zClusterPipeline.__len__T  s   € ä�4×+Ñ+×9Ñ9Ó:Ð:rY   c                  ó   — y)z?Pipeline instances should  always evaluate to True on Python 3+TrX   rs  s    rZ   Ú__bool__zClusterPipeline.__bool__X  s   € àrY   c                 ó:   —  | j                   j                  |i |¤ŽS )z?
        Wrapper function for pipeline_execute_command
        ©r5  r"  r!  s      rZ   r"  zClusterPipeline.execute_command\  s"   € ð 8ˆt×'Ñ'×7Ñ7¸ÐHÀÑHÐHrY   c                 ó:   —  | j                   j                  |i |¤ŽS )ar  
        Stage a command to be executed when execute() is next called

        Returns the current Pipeline object back so commands can be
        chained together, such as:

        pipe = pipe.set('foo', 'bar').incr('baz').decr('bang')

        At some other point, you can then run: pipe.execute(),
        which will execute all commands queued in the pipe.
        rC  ©râ   rl   rm   s      rZ   Úpipeline_execute_commandz(ClusterPipeline.pipeline_execute_commandb  s"   € ð 8ˆt×'Ñ'×7Ñ7¸ÐIÀÑIÐIrY   c                 ó>   — | j                   j                  |||«       y)úS
        Provides extra context to the exception prior to it being handled
        N)r5  Úannotate_exception©râ   rÙ  Únumberrp   s       rZ   rI  z"ClusterPipeline.annotate_exceptionp  s   € ð 	× Ñ ×3Ñ3°I¸vÀwÕOrY   Úraise_on_errorr^   c                 ó„   — 	 | j                   j                  |«      | j                  «        S # | j                  «        w xY w)zB
        Execute all the commands in the current pipeline
        )r5  rr  rŸ  ©râ   rL  s     rZ   rr  zClusterPipeline.executev  s.   € ð
	Ø×+Ñ+×3Ñ3°NÓCà�J‰J�LøˆD�J‰J�Lús   ‚- ­?c                 ó8   — | j                   j                  «        y©z/
        Reset back to empty pipeline.
        N)r5  rŸ  rs  s    rZ   rŸ  zClusterPipeline.reset€  s   € ð 	× Ñ ×&Ñ&Õ(rY   c                 ó>   — | j                   j                  |||¬«      S )N©rL  Úallow_redirections)r5  Úsend_cluster_commands©râ   ÚstackrL  rS  s       rZ   rT  z%ClusterPipeline.send_cluster_commands†  s*   € ð ×'Ñ'×=Ñ=Ø .ÐEWð >ó 
ð 	
rY   c                 ó4   —  | j                   j                  |Ž S rS   )r5  Úexists©râ   rÒ  s     rZ   rX  zClusterPipeline.exists�  s   € Ø.ˆt×'Ñ'×.Ñ.°Ð5Ð5rY   c                 ó6   — | j                   j                  «       S r7  )r5  Úevalrs  s    rZ   r[  zClusterPipeline.eval�  s   € à×'Ñ'×,Ñ,Ó.Ð.rY   c                 ó8   — | j                   j                  «        y)z’
        Start a transactional block of the pipeline after WATCH commands
        are issued. End the transactional block with `execute`.
        N)r5  Úmultirs  s    rZ   r]  zClusterPipeline.multi”  s   € ð
 	× Ñ ×&Ñ&Õ(rY   c                 ó8   — | j                   j                  «        yr:  )r5  Úload_scriptsrs  s    rZ   r_  zClusterPipeline.load_scripts›  s   € à× Ñ ×-Ñ-Õ/rY   c                 ó8   — | j                   j                  «        yr:  )r5  Údiscardrs  s    rZ   ra  zClusterPipeline.discardŸ  ó   € à× Ñ ×(Ñ(Õ*rY   c                 ó6   —  | j                   j                  |Ž  y)z$Watches the values at keys ``names``N)r5  rq  ©râ   Únamess     rZ   rq  zClusterPipeline.watch£  s   € à&ˆ× Ñ ×&Ñ&¨Ò.rY   c                 ó8   — | j                   j                  «        y)z'Unwatches all previously specified keysN)r5  Úunwatchrs  s    rZ   rg  zClusterPipeline.unwatch§  rb  rY   c                 ó<   —  | j                   j                  |i |¤Ž y rS   )r5  Úscript_load_for_pipeliner!  s      rZ   ri  z(ClusterPipeline.script_load_for_pipeline«  s   € Ø9ˆ× Ñ ×9Ñ9¸4ÐJÀ6ÓJrY   c                 ó6   —  | j                   j                  |Ž  y rS   )r5  Údeleterd  s     rZ   rk  zClusterPipeline.delete®  ó   € Ø'ˆ× Ñ ×'Ñ'¨Ò/rY   c                 ó6   —  | j                   j                  |Ž  y rS   )r5  Úunlinkrd  s     rZ   rn  zClusterPipeline.unlink±  rl  rY   ©T©TT)2rè   ré   rê   rë   r4   r?   r:   r0   r@   rE  ÚNO_SLOTS_COMMANDSÚIMMEDIATE_EXECUTE_COMMANDSÚUNWATCH_COMMANDSrJ   r&   r   r   r�   r
   r   r{  rW  r  rH   r%   rä   r…  r›  r¢  r¦  r?  rA  r"  rF  rI  r	   rr  rŸ  rT  rX  r[  r]  r_  ra  rq  rg  ri  rk  rn  r!  r"  s   @rZ   ré  ré  Ï
  sÑ  ø„ ñð 	ØØØØðÐð #˜ÐØ")¨9Ð!5ÐÚ5Ðáà*ð
ð =Øôð ;?ØDHØ7;Ø#(ØCGØ,-Ø"#Ø!%ØØÙ*>Ó*@Ø8<ñX6à%ðX6ð *ðX6ð # 4¨¨X¨Ñ#6Ñ7ð	X6ð
 %-¨T°#°x°-Ñ-@Ñ$AðX6ð    ]Ñ 3Ñ4ðX6ð !ðX6ð "*Ð*?Ñ!@ðX6ð '*ðX6ð  ðX6ð ˜‰ðX6ð (ðX6ð #Ð#4Ñ5ôX6óðX6òt(òòòò;òòIòJòPñ dð °d¸3±ió ò)ð >Bó
ò6ò/ò)ò0ò+ò/ò+òKò0ö0rY   ré  rÝ  .c                 ó   ‡ — ˆ fd„}|S )zi
    Prints error because some pipelined commands should
    be blocked when running in cluster-mode
    c                  ó"   •— t        d‰› d�«      ‚)Nz"ERROR: Calling pipelined function z1 is blocked when running redis in cluster mode...©r;   )rl   rÓ   rÝ  s     €rZ   Úinnerz%block_pipeline_command.<locals>.inner»  s!   ø€ Ü#Ø0°°ð 74ð 5ó
ð 	
rY   rX   )rÝ  rw  s   ` rZ   Úblock_pipeline_commandrx  µ  s   ø€ ô
ð €LrY   )FÚBGREWRITEAOFr  ÚBITOPÚ
BRPOPLPUSHrõ   r  ró   rô   ÚCLIENTr  rø   r÷   rö   ÚCONFIGr  ÚECHOr	  r  r  r   r  r  ÚMGETzMGET NONATOMICÚMOVEÚMSETÚMSETEXz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                   ó   — e Zd ZdZdd„Zy)ÚPipelineCommandrø  Nc                 ón   — || _         |€i }|| _        || _        d | _        d | _        d| _        d | _        y ©NF)rl   rm   ÚpositionÚresultr¢   rP  r;  )râ   rl   rm   rš  s       rZ   rä   zPipelineCommand.__init__  s>   € ØˆŒ	Øˆ?ØˆGØˆŒØ ˆŒØˆŒØˆŒ	ØˆŒØ;?ˆÕrY   rx  )rè   ré   rê   rë   rä   rX   rY   rZ   r—  r—    s   „ Ùô	@rY   r—  c                   ó2   — e Zd ZdZdedefd„Zd„ Zd„ Zd„ Z	y)	ÚNodeCommandsrø  rj   ri   c                 ó<   — || _         || _        || _        g | _        yr:  )rD  rj   ri   rÓ  )râ   rD  rj   ri   s       rZ   rä   zNodeCommands.__init__%  s"   € ð -ˆÔØ.ˆÔØ$ˆŒØˆ�rY   c                 ó:   — | j                   j                  |«       yr:  )rÓ  r�   )râ   Úcs     rZ   r�   zNodeCommands.append.  s   € à�‰×Ñ˜QÕrY   c                 ó   — | j                   }| j                  }|D ]	  }d|_        Œ 	 |j                  |j	                  |D �cg c]  }|j
                  ‘Œ c}«      «       yc c}w # t        t        f$ r}|D ]	  }||_        Œ Y d}~yd}~ww xY w)z=
        Code borrowed from Redis so it can be fixed
        N)ri   rÓ  r›  Úsend_packed_commandÚpack_commandsrl   r4   r?   )râ   ri   rÓ  r   r@  s        rZ   ÚwritezNodeCommands.write2  s†   € ð —_‘_ˆ
Ø—=‘=ˆó ˆAØˆA�Hð ð
	Ø×*Ñ*Ø×(Ñ(¹(Ó)C¹(°Q¨!¯&«&¸(Ñ)CÓDõùÚ)Cøä¤Ð.ò 	Û�Ø�•õ ûð	ús)   ¨A& ÁA!ÁA& Á!A& Á&BÁ5BÂBc                 óp  — | j                   }| j                  D ]@  }|j                  �Œ	  | j                  ||j                  d   fi |j
                  ¤Ž|_        ŒB y# t        t        f$ r#}| j                  D ]	  }||_        Œ Y d}~ yd}~wt        $ r t        j                  «       d   |_        Y Œ›w xY w)rø  Nr   r‰   )ri   rÓ  r›  rD  rl   rm   r4   r?   r<   ÚsysÚexc_info)râ   ri   r   r@  s       rZ   ÚreadzNodeCommands.readH  sš   € à—_‘_ˆ
Ø—”ˆAð& �x‰xÑð1Ø2˜t×2Ñ2°:¸q¿v¹vÀa¹yÑVÈAÏIÉIÑV�A•Hñ+ øô, (¬Ð6ò Ø!Ÿ]œ]˜Ø#$˜�ð +åûÜ!ò 1Ü"Ÿ|™|›~¨aÑ0�A–Hð1ús   ª0AÁB5Á,B
Â
(B5Â4B5N)
rè   ré   rê   rë   r(   r'   rä   r�   r¤  r¨  rX   rY   rZ   r�  r�  "  s)   „ ÙðØ/=ðØKUóò òó,1rY   r�  c                   ó<  — e Zd Zeed„ «       «       Zed„ «       Zed„ «       Zed„ «       Zedde	de
e   fd„«       Ze	 dd„«       Zed	„ «       Zed
„ «       Zed„ «       Zed„ «       Zed„ «       Zed„ «       Zed„ «       Zed„ «       Zed„ «       Zed„ «       Zed„ «       Zy)ÚExecutionStrategyc                  ó   — y rS   rX   rs  s    rZ   r>  zExecutionStrategy.command_queuej  s   € ð 	rY   c                  ó   — y)zp
        Execution flow for current execution strategy.

        See: ClusterPipeline.execute_command()
        NrX   r!  s      rZ   r"  z!ExecutionStrategy.execute_commando  ó   € ð 	rY   c                  ó   — y)z€
        Annotate exception according to current execution strategy.

        See: ClusterPipeline.annotate_exception()
        NrX   rJ  s       rZ   rI  z$ExecutionStrategy.annotate_exceptionx  r­  rY   c                  ó   — y)z‚
        Pipeline execution flow for current execution strategy.

        See: ClusterPipeline.pipeline_execute_command()
        NrX   rE  s      rZ   rF  z*ExecutionStrategy.pipeline_execute_command�  r­  rY   rL  r^   c                  ó   — y)z^
        Executes current execution strategy.

        See: ClusterPipeline.execute()
        NrX   rN  s     rZ   rr  zExecutionStrategy.executeŠ  r­  rY   c                  ó   — y)z
        Sends commands according to current execution strategy.

        See: ClusterPipeline.send_cluster_commands()
        NrX   rU  s       rZ   rT  z'ExecutionStrategy.send_cluster_commands“  s   € ð 	rY   c                  ó   — y)zZ
        Resets current execution strategy.

        See: ClusterPipeline.reset()
        NrX   rs  s    rZ   rŸ  zExecutionStrategy.resetž  r­  rY   c                  ó   — y rS   rX   rY  s     rZ   rX  zExecutionStrategy.exists§  ó   € àrY   c                  ó   — y rS   rX   rs  s    rZ   r[  zExecutionStrategy.eval«  r´  rY   c                  ó   — y)zU
        Starts transactional context.

        See: ClusterPipeline.multi()
        NrX   rs  s    rZ   r]  zExecutionStrategy.multi¯  r­  rY   c                  ó   — y rS   rX   rs  s    rZ   r_  zExecutionStrategy.load_scripts¸  r´  rY   c                  ó   — y rS   rX   rd  s     rZ   rq  zExecutionStrategy.watch¼  r´  rY   c                  ó   — y)za
        Unwatches all previously specified keys

        See: ClusterPipeline.unwatch()
        NrX   rs  s    rZ   rg  zExecutionStrategy.unwatchÀ  r­  rY   c                  ó   — y rS   rX   r!  s      rZ   ri  z*ExecutionStrategy.script_load_for_pipelineÉ  r´  rY   c                  ó   — y)z^
        "Delete a key specified by ``names``"

        See: ClusterPipeline.delete()
        NrX   rd  s     rZ   rk  zExecutionStrategy.deleteÍ  r­  rY   c                  ó   — y)z^
        "Unlink a key specified by ``names``"

        See: ClusterPipeline.unlink()
        NrX   rd  s     rZ   rn  zExecutionStrategy.unlinkÖ  r­  rY   c                  ó   — y rS   rX   rs  s    rZ   ra  zExecutionStrategy.discardß  r´  rY   Nro  rp  )rè   ré   rê   Úpropertyr   r>  r"  rI  rF  r{  r   r	   rr  rT  rŸ  rX  r[  r]  r_  rq  rg  ri  rk  rn  ra  rX   rY   rZ   rª  rª  i  sq  „ ØØñó ó ðð ñó ðð ñó ðð ñó ðð ñ dð °d¸3±iò ó ðð à=Aòó ðð ñó ðð ñó ðð ñó ðð ñó ðð ñó ðð ñó ðð ñó ðð ñó ðð ñó ðð ñó ðð ñó ñrY   rª  c                   óÒ   — e Zd Zdefd„Zed„ «       Zej                  dee	   fd„«       Ze
d„ «       Zd„ Ze
dded	ee   fd
„«       Ze
	 dd„«       Ze
d„ «       Zd„ Zd„ Zd„ Zd„ Zd„ Zy)ÚAbstractStrategyrt  c                 óV   — g | _         || _        | j                  j                  | _        y rS   )Ú_command_queueÚ_piperæ   Ú_nodes_manager)râ   rt  s     rZ   rä   zAbstractStrategy.__init__å  s%   € ð 68ˆÔØˆŒ
Ø"Ÿj™j×6Ñ6ˆÕrY   c                 ó   — | j                   S rS   ©rÂ  rs  s    rZ   r>  zAbstractStrategy.command_queueí  s   € à×"Ñ"Ð"rY   Úqueuec                 ó   — || _         y rS   rÆ  )râ   rÇ  s     rZ   r>  zAbstractStrategy.command_queueñ  s
   € à#ˆÕrY   c                  ó   — y rS   rX   r!  s      rZ   r"  z AbstractStrategy.execute_commandõ  r´  rY   c           	      óŒ   — | j                   j                  t        ||t        | j                   «      «      «       | j                  S rS   )rÂ  r�   r—  rœ   rÃ  rE  s      rZ   rF  z)AbstractStrategy.pipeline_execute_commandù  s9   € Ø×Ñ×"Ñ"Ü˜D '¬3¨t×/BÑ/BÓ+CÓDô	
ð �z‰zÐrY   rL  r^   c                  ó   — y rS   rX   rN  s     rZ   rr  zAbstractStrategy.executeÿ  r´  rY   c                  ó   — y rS   rX   rU  s       rZ   rT  z&AbstractStrategy.send_cluster_commands  s   € ð 	rY   c                  ó   — y rS   rX   rs  s    rZ   rŸ  zAbstractStrategy.reset	  r´  rY   c                 ó(   —  | j                   dg|¢­Ž S )NÚEXISTS©r"  rY  s     rZ   rX  zAbstractStrategy.exists  s   € Ø#ˆt×#Ñ# HÐ4¨tÒ4Ð4rY   c                 ó   — t        d«      ‚)rø  z method eval() is not implementedrv  rs  s    rZ   r[  zAbstractStrategy.eval  s   € ä#Ð$FÓGÐGrY   c                 ó   — t        d«      ‚)rø  z(method load_scripts() is not implementedrv  rs  s    rZ   r_  zAbstractStrategy.load_scripts  s   € ä#Ð$NÓOÐOrY   c                 ó   — t        d«      ‚)rø  z4method script_load_for_pipeline() is not implementedrv  r!  s      rZ   ri  z)AbstractStrategy.script_load_for_pipeline  s   € ä#ØBó
ð 	
rY   c                 ó´   — dj                  t        t        |«      «      }d|› dt        |«      › d|j                  d   › �}|f|j                  dd z   |_        y)rH  rø  z
Command # z (z) of pipeline caused error: r   r‰   N)rG  rH  rO   rQ   rl   )râ   rÙ  rK  rp   ÚcmdÚmsgs         rZ   rI  z#AbstractStrategy.annotate_exception  se   € ð �h‰h”sœ8 WÓ-Ó.ˆà˜˜ ¤=°Ó#5Ð"6ð 7Ø&Ÿ^™^¨AÑ.Ð/ð1ð 	ð ˜ )§.¡.°°Ð"4Ñ4ˆ	�rY   Nro  rp  )rè   ré   rê   ré  rä   r¾  r>  Úsetterr   r—  r   r"  rF  r{  r	   rr  rT  rŸ  rX  r[  r_  ri  rI  rX   rY   rZ   rÀ  rÀ  ä  sÎ   „ ð7àó7ð ñ#ó ð#ð ×Ñð$ 4¨Ñ#8ò $ó ð$ð ñó ðòð ñ dð °d¸3±iò ó ðð à=Aòó ðð
 ñó ðò5òHòPò
ó	5rY   rÀ  c                   ó¨   ‡ — e Zd Zdefˆ fd„Zd„ Zd„ Zddedee	   fd„Z
d„ Z	 dd	„Z	 dd
„Zd„ Zd„ Zdeded   fd„Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zˆ xZS )r3  rt  c                 óF   •— t         ‰| �  |«       |j                  | _        y rS   )rò  rä   rƒ  ©râ   rt  r‚  s     €rZ   rä   zPipelineStrategy.__init__+  s   ø€ Ü‰Ñ˜ÔØ!×/Ñ/ˆÕrY   c                 ó&   —  | j                   |i |¤ŽS rS   )rF  r!  s      rZ   r"  z PipelineStrategy.execute_command/  s   € Ø,ˆt×,Ñ,¨dÐ=°fÑ=Ð=rY   c                 óè   — |D ]m  }|j                   }t        |t        «      sŒ | j                  ||j                  dz   |j
                  «       t        dt        j                  «       |z
  |¬«       |‚ y)ú8
        Raise the first exception on the stack
        r‰   ÚPIPELINE)rj  r*  r+  N)	r›  r™   r¥  rI  rš  rl   rG   r0  r1  )râ   rV  r>  r   rw   s        rZ   Ú_raise_first_errorz#PipelineStrategy._raise_first_error2  sc   € ó ˆAØ—‘ˆAÜ˜!œYÕ'Ø×'Ñ'¨¨1¯:©:¸©>¸1¿6¹6ÔBä)Ø!+Ü%)§^¡^Ó%5¸
Ñ%BØõð �ñ rY   rL  r^   c                 ó’   — | j                   }|sg S 	 | j                  ||«      | j                  «        S # | j                  «        w xY wrS   )rÂ  rT  rŸ  ©râ   rL  rV  s      rZ   rr  zPipelineStrategy.executeC  s=   € Ø×#Ñ#ˆÙØˆIð	Ø×-Ñ-¨e°^ÓDà�J‰J�LøˆD�J‰J�Lús	   ’4 ´Ac                 ó   — g | _         yrP  rÆ  rs  s    rZ   rŸ  zPipelineStrategy.resetM  s   € ð !ˆÕrY   c                 óÚ   — |sg S | j                   j                  j                  «       }	 	 | j                  |||¬«      S # t        j
                  $ r}|dkD  r|dz  }n|‚Y d}~nd}~ww xY wŒC)a  
        Wrapper for RedisCluster.ERRORS_ALLOW_RETRY errors handling.

        If one of the retryable exceptions has been thrown we assume that:
         - connection_pool was disconnected
         - connection_pool was reset
         - refresh_table_asap set to True

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

        If it reaches the number of times, the command will
        raises ClusterDownException.
        rR  r   r‰   N)rÃ  r¹   r/  Ú_send_cluster_commandsrG  rE  )râ   rV  rL  rS  r,  r@  s         rZ   rT  z&PipelineStrategy.send_cluster_commandsS  s‹   € ñ$ ØˆIØŸ™×)Ñ)×5Ñ5Ó7ˆØðØ×2Ñ2ØØ#1Ø'9ð 3ó ð øô
  ×2Ñ2ò Ø! AÒ%ð # aÑ'�NØà�Gô ûðúð s   «? ¿A)ÁA$Á$A)c           
      ó  — t        |d„ ¬«      }d}i }d}d}	 |D �](  }	| j                  j                  j                  |	j                  d   j                  «       «      }
|	j                  j                  dd«      }|r1| j                  |«      s | j                  |«      }|
�sât        «       }
�nÖ|
�s‘|	j                  d   j                  «       }t        |	j                  «      dk\  rt|	j                  d   › d|	j                  d	   › �j                  «       | j                  j                  v r/|	j                  d   › d|	j                  d	   › �j                  «       }| j                  j                  |«      }|s…| j                  j                  «       sd}n# | j                  j                   |	j                  Ž }|rt        |«      dk(  rt        «       }
npt        t"        j$                  t&        j$                  ¬
«      }
nF|| j                  j(                  v r$t        | j                  j(                  |   ¬«      }
n
t        «       }
 | j*                  |	j                  |
j,                  |dœŽ}|st/        d|	j                  › d�«      ‚|
|	_        t        |«      d	kD  rt/        d|	j                  › �«      ‚|d   }|| j                  j                  «       k(  rd}|j2                  }||vrK| j                  j5                  |«      }	 t7        |«      }tK        |jL                  |j>                  |«      ||<   ||   jO                  |	«       �Œ+ tQ        jR                  «       }|j=                  «       }|D ]  }|d	z  }|jU                  «        Œ |D ]½  }|jW                  «        d}|jX                  D ]*  }t[        |j\                  t^        «      sŒ|j\                  } n ta        dtQ        jR                  «       |z
  |jB                  jb                  |jB                  jd                  tg        |jB                  jh                  «      |¬«       |d	z  }Œ¿ 	 tk        |j=                  «       «      D ]N  \  }}||k  r||k\  r|jB                  jm                  «        |j>                  jA                  |jB                  «       ŒP 	 t        d„ |D «       d„ ¬«      }|r®|r¬| j                  xjn                  d	z  c_7        | j                  jq                  «       r6| jD                  jG                  «        |r| j                  jI                  «        |D ]8  }		  | j                  jr                  |	j                  i |	j                  ¤Ž|	_.        Œ: g }t        |d„ ¬«      D ]Õ  }	|	j                  d   | j                  jv                  v r“|	j                  j                  dd«        | j                  jx                  |	j0                  jz                      | j                  jv                  |	j                  d      |	j\                  fi |	j                  ¤Ž«      |	_.        |jO                  |	j\                  «       Œ× |r| j}                  ||«       |S # t8        t:        f$ rt |j=                  «       D ]'  }|j>                  jA                  |jB                  «       Œ) | jD                  jG                  «        |r| j                  jI                  «        i }‚ w xY w# tk        |j=                  «       «      D ]N  \  }}||k  r||k\  r|jB                  jm                  «        |j>                  jA                  |jB                  «       ŒP w xY w# tt        $ r}||	_.        Y d}~�ŒDd}~ww xY w)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                 ó   — | j                   S rS   ©rš  ©rŸ   s    rZ   r%  z9PipelineStrategy._send_cluster_commands.<locals>.<lambda>†  s   € ¨a¯jªjrY   )rÈ  Fr   r  Nr˜   rø  r‰   r$  r&  )rö  Ú	node_flagr'  r(  zToo many targets for command TrÞ  rY  c              3   óh   K  — | ]*  }t        |j                  t        j                  «      r|–— Œ, y ­wrS   )r™   r›  ré  rE  )Ú.0r   s     rZ   Ú	<genexpr>z:PipelineStrategy._send_cluster_commands.<locals>.<genexpr>.  s,   è ø€ ð á �AÜ˜aŸh™h¬×(JÑ(JÔKô Ù ùs   ‚02c                 ó   — | j                   S rS   rç  rè  s    rZ   r%  z9PipelineStrategy._send_cluster_commands.<locals>.<lambda>3  s   € ˜!Ÿ*š*rY   c                 ó   — | j                   S rS   rç  rè  s    rZ   r%  z9PipelineStrategy._send_cluster_commands.<locals>.<lambda>X  s   € ¨Q¯ZªZrY   rÒ  )?ÚsortedrÃ  r“  r.  rl   rû  rm   r+  r  r  r   rú  rœ   rƒ  rŽ   r1  rÑ  r   r�  r   rŽ  rÿ  rö  r;   r;  rÝ  r´  rk   r4   r?   rz   rj   rE  ri   rÄ  rM  r7  r�  rD  r�   r0  r1  r¤  r¨  rÓ  r™   r›  r¥  rG   r\   r]   r�   r­   Ú	enumeraterª  r…  r  r2  r<   rˆ  r’  r%  rß  )râ   rV  rL  rS  Úattemptr9  r—   Únodes_writtenÚ
nodes_readr   r;  r:  r  rp   rý  rÒ  r¢   rt   rc   ri   r±  r>  Únode_commandsÚ
node_errorrÕ  r¡   r@  ru   s                               rZ   rä  z'PipelineStrategy._send_cluster_commandsx  sz  € ô ˜Ñ$8Ô9ˆØˆà)+ˆØˆØˆ
ðX	8ô �Ø#'§:¡:×#>Ñ#>×#FÑ#FØ—F‘F˜1‘I—O‘OÓ%ó$Ð ð "#§¡§¡¨~¸tÓ!D�Ù!¨$×*=Ñ*=¸nÔ*MØ#'×#;Ñ#;¸NÓ#K�Lâ+Ü+:Ó+<Ò(â+Ø"#§&¡&¨¡)§/¡/Ó"3˜ä §¡›K¨1Ò,Ø#$§6¡6¨!¡9 +¨Q¨q¯v©v°a©y¨kÐ :× @Ñ @Ó BØ#Ÿz™z×7Ñ7ñ!8ð *+¯©°©¨°1°Q·V±V¸A±Y°KÐ&@×&FÑ&FÓ&H˜Gð (,×'9Ñ'9×'=Ñ'=¸gÓ'F˜Ù+à#'§:¡:×#>Ñ#>Ô#@Ø'+¡à'C t§z¡z×'CÑ'CÀQÇVÁVÐ'L Ù#'¬3¨t«9¸ª>Ü3BÓ3DÑ 0ä3BÜ3@×3NÑ3NÜ4B×4PÑ4Pô4"Ñ 0ð
  ,¨t¯z©z×/PÑ/PÑPÜ3BØ37·:±:×3TÑ3TØ(4ñ4&ô4"Ñ 0ô 4CÓ3DÐ 0à#8 4×#8Ñ#8ØŸ™Ø'7×'FÑ'FØ"0ò$�Lñ
 (Ü3Ø?ÀÇÁ¸xÀ{ÐSóð ð &6�Ô"Ü�|Ó$ qÒ(Ü/Ø7¸¿¹°xÐ@óð ð $ A‘�Ø˜4Ÿ:™:×6Ñ6Ó8Ò8Ø&*�Oð
 !ŸI™I�	Ø EÑ)Ø!%§¡×!@Ñ!@ÀÓ!F�JðÜ%3°JÓ%?˜
ô (4Ø"×1Ñ1Ø"×2Ñ2Ø"ó(�E˜)Ñ$ð
 �iÑ ×'Ñ'¨Ö*ð{ ôR Ÿ™Ó)ˆJà!ŸL™L›NˆMÛ"�Ø Ñ"�Ø—‘•	ð #ó #�Ø—‘”ð "�
ØŸ:œ:�CÜ! #§*¡*¬iÕ8Ø%(§Z¡Z˜
Ùð &ô
 *Ø!+Ü%)§^¡^Ó%5¸
Ñ%BØ#$§<¡<×#4Ñ#4Ø !§¡× 1Ñ 1Ü!$ Q§\¡\§_¡_Ó!5Ø$õð ˜a‘‘
ñ% #ôB " %§,¡,£.Ö1‘��1Ø�}Ò$¨¨jªØ—L‘L×+Ñ+Ô-Ø×!Ñ!×)Ñ)¨!¯,©,Õ7ñ 2ô ñá óñ
 %ô
ˆñ Ñ)ð& �J‰J×+Ò+¨qÑ0Õ+Ø�z‰z×/Ñ/Ô1Ø×#Ñ#×.Ñ.Ô0Ù"Ø—J‘J×3Ñ3Ô5Û�ð!ð  A˜tŸz™z×@Ñ@À!Ç&Á&ÐVÈAÏIÉIÑV�A•Hð	 ð ˆÜ˜Ñ#7×8ˆAØ�v‰v�a‰y˜DŸJ™J×AÑAÑAà—	‘	—‘˜f dÔ+ð˜4Ÿ:™:×@Ñ@Ø×&Ñ&×6Ñ6ñð E�D—J‘J×9Ñ9¸!¿&¹&À¹)ÑDØŸ™ñØ$%§I¡Iñó�”ð �O‰O˜AŸH™HÕ%ð 9ñ Ø×#Ñ# E¨:Ô6àˆøôU ,¬\Ð:ò 
à!&§¡¦˜AØ×-Ñ-×5Ñ5°a·l±lÕCð "0ð ×+Ñ+×6Ñ6Ô8Ù*Ø ŸJ™J×;Ñ;Ô=Ø "˜Øð
ûôH " %§,¡,£.Ö1‘��1Ø�}Ò$¨¨jªØ—L‘L×+Ñ+Ô-Ø×!Ñ!×)Ñ)¨!¯,©,Õ7ñ 2ûô` "ò !Ø �A—H’Hûð!úsF   ˜K'[= Ì Y7ÌB;[= ÏB[= Õ5],Ù7B[:Û:[= Û=A,])Ý,	^Ý5^Þ^c                 óV   — t        |t        «      xr || j                  j                  v S rS   )r™   r�   rÃ  r„  r  s     rZ   r  zPipelineStrategy._is_nodes_flagj  s#   € Ü˜,¬Ó,ÒV°ÀÇÁ×AVÑAVÐ1VÐVrY   c                 óÆ   — t        |t        «      r|}|S t        |t        «      r|g}|S t        |t        «      r|j	                  «       }|S t        dt        |«      › �«      ‚r  r  r  s      rZ   r  z$PipelineStrategy._parse_target_nodesm  r  rY   rö  r8  c                óä  — |d   j                  «       }t        |«      dk\  rL|d   › d|d   › �j                  «       | j                  j                  v r|d   › d|d   › �j                  «       }|j	                  dd «      }|�|}n%| j                  j                  j                  |«      }|| j                  j                  v r| j                  j                  |   }| j                  j                  |   }|t        j                  k(  r
 ||g|¢­Ž }nB|t        j                  k(  r	 ||i |¤Ž}n&|t        j                  k(  r ||d   «      }n |«       }|d   j                  «       dk(  r|| _        |S )Nr   r˜   rø  r‰   r´   rù  )rú  rœ   rÃ  rƒ  r+  rŽ   rŽ  r’  r   r�  r�  rŠ  rû  r•  rü  s	            rZ   rÿ  z!PipelineStrategy._determine_nodes�  s[  € ð
 �q‘'—-‘-“/ˆä�‹I˜ŠNØ˜‘7�)˜1˜T !™W˜IÐ&×,Ñ,Ó.°$·*±*×2JÑ2JÑJà˜a™˜	  4¨¡7 )Ð,×2Ñ2Ó4ˆGà—Z‘Z ¨dÓ3ˆ
ØÐ!à%‰Lð  Ÿ:™:×3Ñ3×7Ñ7¸Ó@ˆLà˜4Ÿ:™:×<Ñ<Ñ<Ø!ŸZ™Z×>Ñ>¸|ÑLˆNàŸ*™*×?Ñ?ÀÑOˆàœ]×8Ñ8Ò8Ù# GÐ3¨dÒ3‰EØœ}×8Ñ8Ò8Ù# TÐ4¨VÑ4‰EØœ}×<Ñ<Ò<Ù# D¨¡GÓ,‰Eá#Ó%ˆEà�‰7�=‰=‹?˜nÒ,Ø$)ˆDÔ!àˆrY   c                 ó   — t        d«      ‚)Nz@method multi() is not supported outside of transactional contextrv  rs  s    rZ   r]  zPipelineStrategy.multi¨  ó   € Ü#ØNó
ð 	
rY   c                 ó   — t        d«      ‚)NzBmethod discard() is not supported outside of transactional contextrv  rs  s    rZ   ra  zPipelineStrategy.discard­  ó   € Ü#ØPó
ð 	
rY   c                 ó   — t        d«      ‚)Nz@method watch() is not supported outside of transactional contextrv  rd  s     rZ   rq  zPipelineStrategy.watch²  rú  rY   c                 ó   — t        d«      ‚)NzBmethod unwatch() is not supported outside of transactional contextrv  rd  s     rZ   rg  zPipelineStrategy.unwatch·  rü  rY   c                 ó^   — t        |«      dk7  rt        d«      ‚| j                  d|d   «      S )Nr‰   z=deleting multiple keys is not implemented in pipeline commandÚDELr   ©rœ   r;   r"  rd  s     rZ   rk  zPipelineStrategy.delete¼  s6   € Üˆu‹:˜Š?Ü'ØOóð ð ×#Ñ# E¨5°©8Ó4Ð4rY   c                 ó^   — t        |«      dk7  rt        d«      ‚| j                  d|d   «      S )Nr‰   z>unlinking multiple keys is not implemented in pipeline commandÚUNLINKr   r  rd  s     rZ   rn  zPipelineStrategy.unlinkÄ  s6   € Üˆu‹:˜Š?Ü'ØPóð ð ×#Ñ# H¨e°A©hÓ7Ð7rY   ro  rp  )rè   ré   rê   ré  rä   r"  rß  r{  r   r	   rr  rŸ  rT  rä  r  r  r   rÿ  r]  ra  rq  rg  rk  rn  r!  r"  s   @rZ   r3  r3  *  s’   ø„ ð0˜_õ 0ò>òñ" dð °d¸3±ió ò!ð >Bó#ðL >BópòdWòð(%Ø%2ð%à	ˆmÑ	ó%òN
ò

ò

ò

ò
5ö8rY   r3  c                   ó  ‡ — e Zd ZdhZddhZh d£ZeefZe	e
eefZdefˆ fd„Zdeeef   fd„Zd„ Zd	„ Zd
„ Zd„ Zdefd„Zd„ Zd„ Zddedee   fd„Zded   defd„Zded   defd„Z d„ Z!	 dd„Z"d„ Z#d„ Z$d„ Z%d„ Z&d„ Z'd„ Z(ˆ xZ)S ) r4  r$  r%  r&  rt  c                 ó.  •— t         ‰| �  |«       d| _        d| _        t	        «       | _        d | _        d| _        t        | j                  j                  «      | _        | j                  j                  t        j                  | j                  z   «       y r™  )rò  rä   Ú_explicit_transactionÚ	_watchingr  Ú_pipeline_slotsÚ_transaction_connectionÚ
_executingr   rÃ  r¹   Ú_retryÚupdate_supported_errorsrG  rE  ÚSLOT_REDIRECT_ERRORSrÚ  s     €rZ   rä   zTransactionStrategy.__init__Ù  st   ø€ Ü‰Ñ˜ÔØ%*ˆÔ"ØˆŒÜ),«ˆÔØ=AˆÔ$ØˆŒÜ˜4Ÿ:™:×+Ñ+Ó,ˆŒØ�‰×+Ñ+Ü×+Ñ+¨d×.GÑ.GÑGõ	
rY   r^   c                 ó"  — | j                   st        d«      ‚| j                  j                  t	        | j                   «      d   d«      }| j
                  j                  |«      }| j                  rv|j                  j                  | j                  «      sQ| j                  j                  | j                  «      }|j                  j                  | j                  «       d| _        | j                  st        |«      | _        || j                  fS )ao  
        Find a connection for a pipeline transaction.

        For running an atomic transaction, watch keys ensure that contents have not been
        altered as long as the watch commands for those keys were sent over the same
        connection. So once we start watching a key, we fetch a connection to the
        node that owns that slot and reuse it.
        z:At least a command with a key is needed to identify a noder   FN)r  r;   rÄ  rÏ  r#  rÃ  r´  r	  rj   Úowns_connectionrê  rE  rk   )râ   r¢   rc   rÍ  s       rZ   Ú*_get_client_and_connection_for_transactionz>TransactionStrategy._get_client_and_connection_for_transactionå  sò   € ð ×#Ò#Ü'ØLóð ð !×/Ñ/×BÑBÜ�×%Ñ%Ó& qÑ)¨5ó
ˆð !ŸJ™J×;Ñ;¸DÓAˆ
Ø×'Ò'Ø×-Ñ-×=Ñ=Ø×,Ñ,ôð !%× 3Ñ 3× IÑ IØ×0Ñ0ó!�ð ×-Ñ-×5Ñ5°d×6RÑ6RÔSØ/3�Ô,à×+Ò+Ü+9¸*Ó+EˆDÔ(à˜4×7Ñ7Ð7Ð7rY   c                 ó2  — d }|d   t         j                  vr | j                  j                  |Ž }| j                  s|d   | j
                  v rœ| j                  s�|d   dk(  r| j                  «        |�A| j                  r|| j                  vrt        d«      ‚| j                  j                  |«       n#|d   | j                  vrt        d|d   › d�«      ‚ | j                  |i |¤ŽS |�| j                  j                  |«        | j                  |i |¤ŽS )Nr   r%  z0Cannot watch or send commands on different slotsz)Cannot identify slot number for command: z(,it cannot be triggered in a transaction)ré  rq  rÃ  rÎ  r  rr  r  Ú_validate_watchr  r5   Úaddr;   Ú_immediate_execute_commandrF  )râ   rl   rÓ   Úslot_numbers       rZ   r"  z#TransactionStrategy.execute_command  s-  € Ø%)ˆØ�‰7œ/×;Ñ;Ñ;Ø3˜$Ÿ*™*×3Ñ3°TÐ:ˆKð �NŠN˜d 1™g¨×)HÑ)HÑHØ×,Ò,Ø�A‰w˜'Ò!Ø×$Ñ$Ô&àÐ&Ø×'Ò'¨K¸t×?SÑ?SÑ,SÜ3ØJóð ð ×$Ñ$×(Ñ(¨Õ5Ø�a‘ × 6Ñ 6Ñ6Ü+Ø?ÀÀQÁ¸yð I>ð >óð ð
 3�4×2Ñ2°DÐC¸FÑCÐCàÐ&Ø×$Ñ$×(Ñ(¨Ô5à0�4×0Ñ0°$ÐA¸&ÑAÐArY   c                 ó@   — | j                   rt        d«      ‚d| _        y )Nú"Cannot issue a WATCH after a MULTIT)r  r<   r  rs  s    rZ   r  z#TransactionStrategy._validate_watch%  s   € Ø×%Ò%ÜÐAÓBÐBàˆ�rY   c                 ób   ‡ ‡‡— ‰ j                   j                  ˆˆˆ fd„‰ j                  d¬«      S )Nc                  ó(   •—  ‰j                   ‰ i ‰¤ŽS rS   )Ú _get_connection_and_send_command)rl   rm   râ   s   €€€rZ   r%  z@TransactionStrategy._immediate_execute_command.<locals>.<lambda>-  s   ø€ Ð9�D×9Ñ9¸4ÐKÀ7ÒKrY   T©Úwith_failure_count)r  Úcall_with_retryÚ_reinitialize_on_errorrE  s   ```rZ   r  z.TransactionStrategy._immediate_execute_command+  s.   ú€ Ø�{‰{×*Ñ*ÝKØ×'Ñ'Ø#ð +ó 
ð 	
rY   c           
      ó   — | j                  «       \  }}t        j                  «       }	  | j                  |||d   g|¢­i |¤Ž}t	        |d   t        j                  «       |z
  |j
                  |j                  t        |j                  «      ¬«       |S # t        $ r_}|r||_
        t	        |d   t        j                  «       |z
  |j
                  |j                  t        |j                  «      |¬«       ‚ d }~ww xY w)Nr   ©rj  r*  rZ  r[  r\  rY  )r  r0  r1  Ú_send_command_parse_responserG   r\   r]   r�   r­   r¥  ri   )râ   rl   rm   rc   ri   r>  ru   r@  s           rZ   r  z4TransactionStrategy._get_connection_and_send_command2  sð   € Ø!%×!PÑ!PÓ!RÑˆ
�Jô —^‘^Ó%ˆ
ð	Ø8�t×8Ñ8Ø˜J¨¨Q©ðØ26òØ:AñˆHô &Ø! !™WÜ!%§¡Ó!1°JÑ!>Ø)Ÿ™Ø&ŸO™OÜ  §¡Ó/õð ˆOøÜò 	Ùà)�”Ü%Ø! !™WÜ!%§¡Ó!1°JÑ!>Ø)Ÿ™Ø&ŸO™OÜ  §¡Ó/Øõð ûð	ús   ©A+B Â	C=ÂAC8Ã8C=rc   c                 óv   —  |j                   |Ž   |j                  ||fi |¤Ž}|| j                  v rd| _        |S )z7
        Send a command and parse the response
        F)r°  rD  rs  r  )râ   Úconnrc   rj  rl   rm   Úoutputs          rZ   r!  z0TransactionStrategy._send_command_parse_responseT  sG   € ð 	ˆ×Ñ˜4Ñ Ø*�×*Ñ*¨4°ÑIÀÑIˆà˜4×0Ñ0Ñ0Ø"ˆDŒNØˆrY   c           	      óø  — t        |d«      rbt        |j                  j                  |j                  j                  |j                  j                  |j                  j                  ||d¬«       | j
                  r.t        |«      | j                  v r| j                  rt        d«      ‚t        |«      | j                  v st        |«      | j                  v �r| j                  rƒ| j                  j                  «        | j                  j                  | j                  «      }|r;|j                  r/|j                  j                   j#                  | j                  «       d | _        | j$                  xj&                  dz  c_        | j$                  j)                  «       r)| j                  j+                  «        d| _        d| _        y t-        |t.        «      r| j                  j1                  |«       d| _        y )Nri   Tr^  z-Slot rebalancing occurred while watching keysr‰   r   F)r5  rF   ri   r\   r]   r  r×  r  r
  rA   ÚCONNECTION_ERRORSr	  rª  rÄ  rê  rà   rj   rE  rÃ  r…  r  rM  r™   r0   rN  )râ   r+  r=  r¢   s       rZ   r  z*TransactionStrategy._reinitialize_on_errorb  s�  € Ü�5˜,Ô'ÜØ$×/Ñ/×4Ñ4Ø!×,Ñ,×1Ñ1Ø%*×%5Ñ%5×%:Ñ%:Ø"'×"2Ñ"2×"7Ñ"7Ø Ø,Ø õð �>Š>Ü�E‹{˜d×7Ñ7Ñ7¸D¿OºOÜ Ð!PÓQÐQô �‹K˜4×4Ñ4Ñ4Ü�E‹{˜d×4Ñ4Ò4à×+Ò+à×,Ñ,×7Ñ7Ô9Ø×*Ñ*×@Ñ@Ø×0Ñ0ó�ñ ˜D×1Ò1Ø×)Ñ)×9Ñ9×AÑAØ×4Ñ4ôð 04�Ô,à�J‰J×+Ò+¨qÑ0Õ+Ø�z‰z×/Ñ/Ô1Ø×#Ñ#×.Ñ.Ô0Ø,-�Ô)ð
  ˆ�ô ˜e¤XÔ.Ø×'Ñ'×1Ñ1°%Ô8àˆ�rY   c           
      óx  — t        ||«      D ]«  \  }}t        |t        «      sŒ| j                  ||j                  dz   |j
                  «       t        dt        j                  «       |z
  | j                  j                  | j                  j                  t        | j                  j                  «      ¬«       |‚ y)rÝ  r‰   ÚTRANSACTIONr   N)r-  r™   r¥  rI  rš  rl   rG   r0  r1  r	  r\   r]   r�   r­   )râ   Ú	responsesrV  r>  rw   rÕ  s         rZ   rß  z&TransactionStrategy._raise_first_errorŒ  s•   € ô ˜) UÖ+‰FˆAˆsÜ˜!œYÕ'Ø×'Ñ'¨¨3¯<©<¸!Ñ+;¸S¿X¹XÔFä)Ø!.Ü%)§^¡^Ó%5¸
Ñ%BØ#'×#?Ñ#?×#DÑ#DØ $× <Ñ <× AÑ AÜ!$ T×%AÑ%A×%DÑ%DÓ!Eõð �ñ ,rY   rL  c                 óv   — | j                   }|s| j                  r| j                  sg S | j                  ||«      S rS   )rÂ  r  r  Ú!_execute_transaction_with_retriesrá  s      rZ   rr  zTransactionStrategy.executež  s6   € Ø×#Ñ#ˆÙ˜dŸnšn°D×4HÒ4HØˆIà×5Ñ5°e¸^ÓLÐLrY   rV  r—  c                 óT   ‡ ‡‡— ‰ j                   j                  ˆˆ ˆfd„ˆ fd„d¬«      S )Nc                  ó(   •— ‰j                  ‰‰ «      S rS   )Ú_execute_transaction)rL  râ   rV  s   €€€rZ   r%  zGTransactionStrategy._execute_transaction_with_retries.<locals>.<lambda>©  s   ø€ �D×-Ñ-¨e°^ÔDrY   c                 ó(   •— ‰j                  | |«      S rS   )r  )r+  r=  râ   s     €rZ   r%  zGTransactionStrategy._execute_transaction_with_retries.<locals>.<lambda>ª  s   ø€ ¨×)DÑ)DØ�}ô*rY   Tr  )r  r  )râ   rV  rL  s   ```rZ   r+  z5TransactionStrategy._execute_transaction_with_retries¥  s.   ú€ ð �{‰{×*Ñ*ÝDóð  $ð +ó 
ð 	
rY   c           	      óˆ  — t        | j                  «      dkD  rt        d«      ‚d| _        | j	                  «       \  }}t        t        d«      g|t        d«      g«      }|D �cg c]!  }t        |j                  vsŒ|j                  ‘Œ# }}|j                  |«      }t        j                  «       }|j                  |«       g }		 |j                  |d«       t'        | j(                  «      D ]O  \  }}t        |j                  v r%|	j#                  ||j                  t           f«       Œ=	 |j                  |d«      }ŒQ d }	 |j                  |d	«      }d
| _        t/        dt        j                  «       |z
  |j0                  |j2                  t5        |j6                  «      ¬«       d
| _        |€t;        d«      ‚|	D ]  \  }}
|j=                  ||
«       Œ t        |«      t        | j(                  «      k7  rIt?        djA                  | j(                  D �cg c]  }|j                  d   ‘Œ c}t        |«      «      «      ‚|st        |	«      dkD  r| jC                  || j(                  |«       g }tE        || j(                  «      D ]w  \  }}tG        |tH        «      sQ|j                  d   }|| jJ                  jL                  v r* | jJ                  jL                  |   |fi |j                  ¤Ž}|j#                  |«       Œy |S c c}w # t        $ r/}
| j!                  |
dd«       |	j#                  |
«       Y d }
~
�Œbd }
~
w| j$                  $ r}| j!                  |dd«       ‚ d }~ww xY w# | j*                  $ r<}| j!                  ||dz   |j                  «       |	j#                  |«       Y d }~�ŒÁd }~w| j$                  $ r&}| j!                  ||dz   |j                  «       ‚ d }~wt        $ r<}
| j!                  |
|dz   |j                  «       |	j#                  |
«       Y d }
~
�Œ7d }
~
ww xY w# t,        $ r	 |	r|	d   ‚‚ w xY wc c}w )Nr‰   zDAll keys involved in a cluster transaction must map to the same slotT)ÚMULTI)r'  r1  r   r?  r'  Fr(  r   zWatched variable changed.zeUnexpected response length for cluster pipeline EXEC. Command stack was {} but response had length {})'rœ   r  r5   r
  r  r   r—  r   rm   rl   r£  r0  r1  r¢  rD  r=   rI  r�   r&  rð  rÂ  r  r7   rG   r\   r]   r�   r­   r  rA   Úinsertr8   Úformatrß  r-  r™   r¥  rÃ  rˆ  )râ   rV  rL  rc   ri   r   rÓ  Úpacked_commandsr>  Úerrorsr@  Úcluster_errorr¡   rp   r?  Ú
slot_errorru   Údatarw   rÕ  rj  s                        rZ   r.  z(TransactionStrategy._execute_transaction°  sð  € ô ˆt×#Ñ#Ó$ qÒ(Ü+ØVóð ð ˆŒà!%×!PÑ!PÓ!RÑˆ
�JäÜ˜ZÓ(Ð)ØÜ˜YÓ'Ð(ó
ˆñ
 %*ÓM¡E˜q¬^À1Ç9Á9Ò-L�A—F“F EˆÐMØ$×2Ñ2°8Ó<ˆô —^‘^Ó%ˆ
à×&Ñ& Ô7Øˆð	Ø×%Ñ% j°'Ô:ô $ D×$7Ñ$7Ö8‰JˆAˆwÜ §¡Ñ0Ø—‘˜q '§/¡/´.Ñ"AÐBÕCð
%Ø"×1Ñ1°*¸cÓB‘Að 9ð  ˆð	Ø!×0Ñ0°¸VÓDˆHð  ˆŒä!Ø&Ü!Ÿ^™^Ó-°
Ñ:Ø%Ÿ?™?Ø"Ÿ™Ü˜ZŸ]™]Ó+õ	
ð ˆŒàÐÜÐ8Ó9Ð9ó ‰DˆAˆqØ�O‰O˜A˜qÕ!ð ô ˆx‹=œC × 3Ñ 3Ó4Ò4Ü&ðCßCIÁ6Ø(,×(;Ò(;Ó<Ñ(; 1�Q—V‘V˜A“YÐ(;Ñ<¼cÀ(»móDóð ñ œS ›[¨1š_Ø×#Ñ#ØØ×#Ñ#Øôð ˆÜ˜( D×$7Ñ$7Ö8‰FˆAˆsÜ˜a¤Ô+Ø"Ÿx™x¨™{�Ø 4§:¡:×#HÑ#HÑHØK˜Ÿ
™
×=Ñ=¸lÑKØñØ Ÿ[™[ñ�Að �K‰K˜�Nð 9ð ˆùò} Nøô ò 	Ø×#Ñ# A q¨'Ô2Ø�M‰M˜!×ÒûØ×%Ñ%ò 	Ø×#Ñ# M°1°gÔ>Øûð	ûð ×0Ñ0ò .Ø×+Ñ+¨J¸¸A¹¸w¿|¹|ÔLØ—M‘M *×-Ò-ûØ×-Ñ-ò Ø×+Ñ+¨M¸1¸q¹5À'Ç,Á,ÔOØûÜ$ò %Ø×+Ñ+¨A¨q°1©u°g·l±lÔCØ—M‘M !×$Ò$ûð%ûô ò 	ÙØ˜Q‘i�Øð	üò: =sr   Á#L Á;L ÃL Ä)M&Å P* ÈP?Ì	M#Ì$L8Ì8M#Í
MÍM#Í&P'Í51N,Î,P'Î>!OÏP'Ï+1P"Ð"P'Ð*P<c                 ó  — g | _         | j                  r«	 | j                  r5| j                  j                  d«       | j                  j	                  «        | j
                  j                  | j                  «      }|r;|j                  r/|j                  j                  j                  | j                  «       d | _        d| _        d| _        t        «       | _        d| _        y # | j                  $ r’ | j                  rƒ| j                  j                  «        | j
                  j                  | j                  «      }|r;|j                  r/|j                  j                  j                  | j                  «       d | _        Y ŒÅw xY w)Nr$  F)rÂ  r	  r  r°  r±  rÄ  rê  rà   rj   rE  r&  rª  r  r  r  r
  r¬  s     rZ   rŸ  zTransactionStrategy.reset!  sR  € Ø ˆÔð ×'Ò'ð8Ø—>’>ð ×0Ñ0×=Ñ=¸iÔHØ×0Ñ0×>Ñ>Ô@ð ×*Ñ*×@Ñ@Ø×0Ñ0ó�ñ ˜D×1Ò1Ø×)Ñ)×9Ñ9×AÑAØ×4Ñ4ôð 04�Ô,ð ˆŒØ%*ˆÔ"Ü"›uˆÔØˆ�øð# ×)Ñ)ò 8à×/Ò/Ø×0Ñ0×;Ñ;Ô=Ø×.Ñ.×DÑDØ×4Ñ4ó�Dñ  × 5Ò 5Ø×-Ñ-×=Ñ=×EÑEØ ×8Ñ8ôð 48�DÔ0ùð8ús   •B*C$ Ã$BFÆFc                 ó   — t        d«      ‚)NzBsend_cluster_commands cannot be executed in transactional context.)ÚNotImplementedErrorrU  s       rZ   rT  z)TransactionStrategy.send_cluster_commandsJ  s   € ô "ØPó
ð 	
rY   c                 ón   — | j                   rt        d«      ‚| j                  rt        d«      ‚d| _         y )Nz"Cannot issue nested calls to MULTIz:Commands without an initial WATCH have already been issuedT)r  r<   rÂ  rs  s    rZ   r]  zTransactionStrategy.multiQ  s:   € Ø×%Ò%ÜÐAÓBÐBØ×ÒÜØLóð ð &*ˆÕ"rY   c                 óV   — | j                   rt        d«      ‚ | j                  dg|¢­Ž S )Nr  r%  )r  r<   r"  rd  s     rZ   rq  zTransactionStrategy.watchZ  s/   € Ø×%Ò%ÜÐAÓBÐBà#ˆt×#Ñ# GÐ4¨eÒ4Ð4rY   c                 ó>   — | j                   r| j                  d«      S y)Nr$  T)r  r"  rs  s    rZ   rg  zTransactionStrategy.unwatch`  s   € Ø�>Š>Ø×'Ñ'¨	Ó2Ð2àrY   c                 ó$   — | j                  «        y rS   r;  rs  s    rZ   ra  zTransactionStrategy.discardf  r£  rY   c                 ó(   —  | j                   dg|¢­Ž S )Nr   rÐ  rd  s     rZ   rk  zTransactionStrategy.deletei  s   € Ø#ˆt×#Ñ# EÐ2¨EÒ2Ð2rY   c                 ó(   —  | j                   dg|¢­Ž S )Nr  rÐ  rd  s     rZ   rn  zTransactionStrategy.unlinkl  s   € Ø#ˆt×#Ñ# HÐ5¨uÒ5Ð5rY   ro  rp  )*rè   ré   rê   rq  rr  rs  r0   r:   r  r4   r«  r2   r>   r&  ré  rä   r   r!   r'   r  r"  r  r  r  r!  r  rß  r{  r   r	   rr  r+  r.  rŸ  rT  r]  rq  rg  ra  rk  rn  r!  r"  s   @rZ   r4  r4  Í  s  ø„ Ø"˜ÐØ")¨9Ð!5ÐÚ5ÐØ$ jÐ1ÐàØØØð	Ðð

˜_õ 

ð8¸EÀ%ÈÐBSÑ<Tó 8òBBò>ò
ò ðDØ %óò( òTñ$M dð M°d¸3±ió Mð	
ØÐ+Ñ,ð	
Ø>Bó	
ðoØÐ+Ñ,ðoØ>Bóoòb' ðT >Bó
ò*ò5òòò3ö6rY   r4  )“rV   rñ   r€  r¦  r–  r0  Úabcr   r   Úcollectionsr   r   Úenumr   Ú	itertoolsr   Útypingr	   r
   r   r   r   r   r   r   r   Úredis._parsersr   r   Úredis._parsers.commandsr   r   r   Úredis._parsers.helpersr   Úredis.backoffr   r   Úredis.cacher   r   r   r   Úredis.clientr   r   r    r!   Úredis.commandsr"   r#   Úredis.commands.helpersr$   Úredis.commands.policiesr%   r&   Úredis.connectionr'   r(   r)   Ú	redis.crcr*   r+   Úredis.eventr,   r-   r.   r/   Úredis.exceptionsr0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   Ú
redis.lockrC   Úredis.maint_notificationsrD   rE   Úredis.observability.recorderrF   rG   Úredis.retryrH   Úredis.utilsrI   rJ   rK   rL   rM   rN   rO   rP   rQ   Ú	getLoggerrè   rT   r[   r�   r  rb   rk   rx   r‚   r•   r¤   r¨   rº  r½  r@  rÑ   rÒ   r×   rÙ   rí   rG  r8  rW  r”  r‡  rä  ré  rx  ÚPIPELINE_BLOCKED_COMMANDSrp   Úreplacerû  rj  r—  r�  rª  rÀ  r3  r4  rX   rY   rZ   Ú<module>r\     sÃ  ðÛ Û Û Û 
Û Û ß #Ý #Ý Ý Ý ÷
÷ 
õ 
÷ 3ß RÑ RÝ -ß Aß XÓ Xß KÓ Kß >Ý /ß H÷ñ ÷
 9÷ó ÷÷ ÷ ÷ ÷ õ( ÷÷õ ÷
÷ 
õ 
ð 
ˆ×	Ñ	˜8Ó	$€ò.ð˜ð  5¨¨c¨¡?ð °só ñ Ø�Ø3Øôð
P˜uð P¸:ò Póð
Pòò
ðØ
ðØðà	ˆ%��S�‰/˜4  S ™>Ð
)Ñ*óò(ò, ð €Ø
€Ø
€ð+Ð ðX 1Ð ò
÷<
ñ <
÷~tNñ tNônxØÐ@ÐBVôx÷v)ñ ô6&˜Dô &÷* ñ * ÷Zdñ dôNr+�Fô r+ôjc0�lô c0ðL ð ¨°#°s°(Ñ);ó ð GÐ óP )€GØ�oŠo˜c 3Ó'×-Ò-Ó/€GáˆO˜WÑ&<¸WÓ&EÕFð )÷@ñ @÷D1ñ D1ôNx˜ô xôvC5Ð(ô C5ôL`8Ð'ô `8ôF`6Ð*õ `6rY   