U
    g                     @   s  U 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Zd dlZd dl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mZmZmZmZ d dlmZmZm Z m!Z! ddl"m#Z# ej$d	krd d
l m%Z& n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/ d dl0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7 d dl8m9Z9 d dl:m;Z;m<Z<m=Z= ddl>m?Z?m@Z@mAZAmBZBmCZC dZDdZEdZFdZGdZHG dd dejIZJeJjKZLeeeBeCeAf  eMd< e;reAZNneBZNG dd deZOG dd deZPeeOePf ZQG dd  d ZRG d!d" d"eRZSG d#d$ d$eSZTG d%d& d&ZUG d'd( d(eRZVd)ZWeeX d*d+d,ZYeeZe[e[eYeYeZeZeYe[d-	Z\ee]ed.e^f f eMd/< G d0d1 d1ed2d3Z_e]e_d4d5d6Z`ed7d8d9ZaG d:d8 d8ZbG d;d< d<ebZcdS )=    N)abstractmethod)chain)MappingProxyType)AnyCallableIterableListMappingOptionalProtocolSetTupleType	TypedDictTypeVarUnion)ParseResultparse_qsunquoteurlparse   )format_error_message)      r   )timeout)Retry)	NoBackoff)DEFAULT_RESP_VERSION)CredentialProvider"UsernamePasswordCredentialProvider)AuthenticationError$AuthenticationWrongNumberOfArgsErrorConnectionError	DataError
RedisErrorResponseErrorTimeoutError)
EncodableT)HIREDIS_AVAILABLEget_lib_versionstr_if_bytes)
BaseParserEncoder_AsyncHiredisParser_AsyncRESP2Parser_AsyncRESP3Parser   *   $s   
   
    c                   @   s   e Zd Ze ZdS )	_SentinelN)__name__
__module____qualname__objectsentinel r:   r:   </tmp/pip-unpacked-wheel-f3sx1i9r/redis/asyncio/connection.pyr4   F   s   r4   DefaultParserc                   @   s   e Zd ZddddZdS )ConnectCallbackProtocolAbstractConnection
connectionc                 C   s   d S Nr:   selfr@   r:   r:   r;   __call__U   r3   z ConnectCallbackProtocol.__call__Nr5   r6   r7   rD   r:   r:   r:   r;   r=   T   s   r=   c                   @   s   e Zd ZddddZdS )AsyncConnectCallbackProtocolr>   r?   c                    s   d S rA   r:   rB   r:   r:   r;   rD   Y   r3   z%AsyncConnectCallbackProtocol.__call__NrE   r:   r:   r:   r;   rF   X   s   rF   c                   @   s@  e Zd ZdZdZdddddedddedddd	e dddedd
de	e
ef ee
 ee ee ee	eef e
e
eee eeee
 ee
 ee
 ee
 ee ee ee ee ee dddZefedddZdd Zdd Zedd Zedd Zdd Z dd Z!ee ddddZ"d d! Z#ed"d# Z$ee
d$d%d&Z%e&e
d'd(d)Z'dd$d*d+Z(dOedd,d-d.Z)d/d0 Z*d1d2 Z+d3d4 Z,e-e. dd5d6d7Z/dPe	e.e
e-e. f edd9d:d;Z0eedd<d=d>Z1d?d@ Z2dQd8ddAeee eee dBdCdDZ3e4e5e. dEdFdGZ6e-e-e4  e5e. dHdIdJZ7dKdL Z8dMdN Z9dS )Rr>   z0Manages communication to and from a Redis server)dbusernameclient_namelib_namelib_versioncredential_providerpasswordsocket_timeoutsocket_connect_timeoutredis_connect_funcretry_on_timeoutretry_on_errorhealth_check_intervalnext_health_checkZlast_active_atencoderssl_contextprotocol_reader_writer_parser_connect_callbacks_buffer_cutoff_lock_socket_read_size__dict__r   NFutf-8stricti   zredis-pyr   )rG   rM   rN   rO   rQ   rR   encodingencoding_errorsdecode_responsesparser_classsocket_read_sizerS   rI   rJ   rK   rH   retryrP   encoder_classrL   rW   c                C   s  |s|r|d k	rt d|| _|| _|| _|| _|| _|| _|| _|| _|d krT|}|| _	|| _
|tkrlg }|r|t |tj |tj || _|s|r|stt d| _nt|| _| j| ntt d| _|| _d| _||||	| _|| _d | _d | _|| _| |
 g | _ d| _!zHzt$|}W n6 t%k
rL   t&}Y n t'k
rh   t"d	Y nX W 5 |dk s|dkrt"d|| _#X d S )
Nz'username' and 'password' cannot be passed along with 'credential_provider'. Please provide only one of the following arguments: 
1. 'password' and (optional) 'username'
2. 'credential_provider'   r   ip  r   r   zprotocol must be either 2 or 3zprotocol must be an integer)(r#   rG   rI   rJ   rK   rL   rM   rH   rN   rO   rQ   SENTINELappendr&   socketr   asynciorR   r   r   rg   copydeepcopyZupdate_supported_errorsrS   rT   rU   rP   rX   rY   r^   
set_parserr[   r\   r"   rW   int	TypeErrorr   
ValueError)rC   rG   rM   rN   rO   rQ   rR   rb   rc   rd   re   rf   rS   rI   rJ   rK   rH   rg   rP   rh   rL   rW   pr:   r:   r;   __init__   s`    

zAbstractConnection.__init__)	_warningsc                 C   sP   t | dd rL|jd| t| d zt  |   W n tk
rJ   Y nX d S )NrY   zunclosed Connection )source)getattrwarnResourceWarningrn   get_running_loop_closeRuntimeError)rC   rw   r:   r:   r;   __del__   s      zAbstractConnection.__del__c                 C   s    | j r| j   d | _ | _dS )zR
        Internal method to silently close the connection without waiting
        N)rY   closerX   rC   r:   r:   r;   r}      s    
zAbstractConnection._closec                 C   s8   d dd |  D }d| jj d| jj d| dS )N,c                 s   s    | ]\}}| d | V  qdS )=Nr:   ).0kvr:   r:   r;   	<genexpr>   s     z.AbstractConnection.__repr__.<locals>.<genexpr><.()>)joinrepr_pieces	__class__r6   r5   )rC   Z	repr_argsr:   r:   r;   __repr__   s    zAbstractConnection.__repr__c                 C   s   d S rA   r:   r   r:   r:   r;   r      s    zAbstractConnection.repr_piecesc                 C   s   | j d k	o| jd k	S rA   )rX   rY   r   r:   r:   r;   is_connected   s    zAbstractConnection.is_connectedc                 C   s$   t |}|| jkr | j| dS )a^  
        Register a callback to be called when the connection is established either
        initially or reconnected.  This allows listeners to issue commands that
        are ephemeral to the connection, for example pub/sub subscription or
        key tracking.  The callback must be a _method_ and will be kept as
        a weak reference.
        N)weakref
WeakMethodr[   rl   )rC   callbackZwmr:   r:   r;   register_connect_callback   s    

z,AbstractConnection.register_connect_callbackc                 C   s0   z| j t| W n tk
r*   Y nX dS )z
        De-register a previously registered callback.  It will no-longer receive
        notifications on connection events.  Calling this is not required when the
        listener goes away, since the callbacks are kept as weak methods.
        N)r[   remover   r   rt   )rC   r   r:   r:   r;   deregister_connect_callback  s    z.AbstractConnection.deregister_connect_callback)re   returnc                 C   s   || j d| _dS )z
        Creates a new instance of parser_class with socket size:
        _socket_read_size and assigns it to the parser for the connection
        :param parser_class: The required parser class
        )rf   N)r^   rZ   )rC   re   r:   r:   r;   rq     s    zAbstractConnection.set_parserc              
      s|   j r
dS z( j fdd fddI dH  W n tjk
rJ    Y n| tjtjfk
rl   tdY nZ tk
r } zt	 
|W 5 d}~X Y n, tk
r } zt	||W 5 d}~X Y nX z@ jsވ  I dH  n&t jr  I dH n   W n& tk
r,     I dH   Y nX dd  jD  _ jD ]0}| }| }|rFt|rF|I dH  qFdS )z5Connects to the Redis server if not already connectedNc                      s      S rA   )_connectr:   r   r:   r;   <lambda>  r3   z,AbstractConnection.connect.<locals>.<lambda>c                    s      S rA   
disconnect)errorr   r:   r;   r     r3   zTimeout connecting to serverc                 S   s   g | ]}| r|qS r:   r:   )r   refr:   r:   r;   
<listcomp>8  s      z.AbstractConnection.connect.<locals>.<listcomp>)r   rg   call_with_retryrn   ZCancelledErrorrm   r   r&   OSErrorr"   _error_message	ExceptionrP   
on_connectiscoroutinefunctionr$   r   r[   inspectisawaitable)rC   eexcr   r   Ztaskr:   r   r;   connect  s>    
 


zAbstractConnection.connectc                    s   d S rA   r:   r   r:   r:   r;   r   ?  s    zAbstractConnection._connectr   c                 C   s   d S rA   r:   r   r:   r:   r;   _host_errorC  s    zAbstractConnection._host_error)	exceptionr   c                 C   s   t |  |S rA   )r   r   )rC   r   r:   r:   r;   r   G  s    z!AbstractConnection._error_messagec              	      s  | j |  | j }d}| js(| js(| jrD| jp:t| j| j}| }|r| jdkrt| j t	r~| 
t |j| j _| j |  t|dkrd|d g}| jd| jdf| I dH  |  I dH }|dt| jkr|d	t| jkrtd
n|r|| jd|ddiI dH  z|  I dH }W n> tk
rb   | jd|d ddI dH  |  I dH }Y nX t|dkrtdn\| jdkrt| j t	r| 
t |j| j _| j |  | d| jI dH  |  I dH }| jr| dd| jI dH  t|  I dH dkrtd| jr6| ddd| jI dH  | jrV| ddd| jI dH  | jrr| d| jI dH  dd | j| jfD D ]0}z|  I dH  W n tk
r   Y nX q| jrt|  I dH dkrtddS )z=Initialize the connection, authenticate and select a databaseN)r   2ri   defaultr   ZHELLOAUTHs   protoprotozInvalid RESP versioncheck_healthFrj   r   OKzInvalid Username or PasswordZCLIENTZSETNAMEzError setting client nameZSETINFOzLIB-NAMEzLIB-VERZSELECTc                 s   s   | ]}|r|V  qd S rA   r:   )r   sentr:   r:   r;   r     s      z0AbstractConnection.on_connect.<locals>.<genexpr>zInvalid Database)r   )rZ   r   rL   rH   rM   r   Zget_credentialsrW   
isinstancer.   rq   r/   ZEXCEPTION_CLASSESlensend_commandread_responsegetrr   r"   r!   r*   r    rI   rJ   rK   rG   r%   )rC   parserZ	auth_argsZcred_providerresponseZauth_response_r:   r:   r;   r   J  sr    






zAbstractConnection.on_connect)nowaitr   c              
      s   zt | j4 I dH x | j  | js<W 5 Q I dH R  W dS z<z"| j  |s^| j I dH  W n t	k
rt   Y nX W 5 d| _d| _X W 5 Q I dH R X W n( t
jk
r   td| j dY nX dS )z!Disconnects from the Redis serverNz#Timed out closing connection after )async_timeoutrO   rZ   Zon_disconnectr   rX   rY   r   Zwait_closedr   rn   r&   )rC   r   r:   r:   r;   r     s&    



zAbstractConnection.disconnectc                    s6   | j dddI dH  t|  I dH dkr2tddS )z Send PING, expect PONG in returnZPINGFr   NZPONGz#Bad response from PING health check)r   r*   r   r"   r   r:   r:   r;   
_send_ping  s    zAbstractConnection._send_pingc                    s   |   I dH  dS )z Function to call when PING failsNr   )rC   r   r:   r:   r;   _ping_failed  s    zAbstractConnection._ping_failedc                    s4   | j r0t  | jkr0| j| j| jI dH  dS )z3Check the health of the connection with a PING/PONGN)	rS   rn   r|   timerT   rg   r   r   r   r   r:   r:   r;   r     s
    zAbstractConnection.check_health)commandr   c                    s    | j | | j  I d H  d S rA   )rY   
writelinesdrain)rC   r   r:   r:   r;   _send_packed_command  s    z'AbstractConnection._send_packed_commandT)r   r   r   c              
      sn  | j s|  I d H  n|r(|  I d H  zdt|tr<| }t|trL|g}| jrnt	| 
|| jI d H  n| j| | j I d H  W n tjk
r   | jddI d H  tdd Y n tk
r@ } zd| jddI d H  t|jdkrd|jd  }}n|jd }|jd }td| d| d	|W 5 d }~X Y n* tk
rh   | jddI d H   Y nX d S )
NTr   zTimeout writing to socketri   UNKNOWNr   zError z while writing to socket. r   )r   r   r   r   strencodebytesrN   rn   wait_forr   rY   r   r   r&   r   r   r   argsr"   BaseException)rC   r   r   r   Zerr_noerrmsgr:   r:   r;   send_packed_command  sB    

 

z&AbstractConnection.send_packed_command)r   kwargsr   c                    s&   | j | j| |dddI dH  dS )z+Pack and send a command to the Redis serverr   Tr   N)r   pack_commandr   )rC   r   r   r:   r:   r;   r     s     
zAbstractConnection.send_commandc              
      sj   z| j  I dH W S  tk
rd } z4| jddI dH  |  }td| d|j W 5 d}~X Y nX dS )z8Poll the socket to see if there's data that can be read.NTr   Error while reading from z: )rZ   can_read_destructiver   r   r   r"   r   )rC   r   
host_errorr:   r:   r;   r     s    z'AbstractConnection.can_read_destructive)disconnect_on_errorpush_request)disable_decodingr   r   r   c          
   
      s  |dk	r|n| j }|  }z|dk	rl| jdkrltslt|4 I dH  | jj||dI dH }W 5 Q I dH R X nz|dk	rt|4 I dH  | jj|dI dH }W 5 Q I dH R X n:| jdkrts| jj||dI dH }n| jj|dI dH }W n tjk
r6   |dk	rY dS |r$| j	ddI dH  td| Y n t
k
r } z2|r`| j	ddI dH  td| d	|j W 5 d}~X Y n0 tk
r   |r| j	ddI dH   Y nX | jrt  | j }	|	| _t|tr|d|S )
z0Read the response from a previously sent commandN)3r   )r   r   )r   Tr   zTimeout reading from r   z : )rN   r   rW   r(   r   rZ   r   rn   r&   r   r   r"   r   r   rS   r|   r   rT   r   r%   )
rC   r   r   r   r   read_timeoutr   r   r   Z	next_timer:   r:   r;   r     s^    	  
&z AbstractConnection.read_response)r   r   c              	   G   s*  g }t |d trtt |d trFt|d   |dd  }n(d|d krnt|d  |dd  }tt	tt
| tf}| j}t| jj|D ]|}t
|}t
||ks||kst |trt|tt| tf}|| || t}qt|tt| t|tf}q|| |S )z2Pack a series of arguments into the Redis protocolr   ri   N    )r   floatAssertionErrorr   tupler   split	SYM_EMPTYr   SYM_STARr   SYM_CRLFr\   maprU   
memoryview
SYM_DOLLARrl   )rC   r   outputZbuffbuffer_cutoffargZ
arg_lengthr:   r:   r;   r   D  sB    "





zAbstractConnection.pack_command)commandsr   c           	      C   s   g }g }d}| j }|D ]}| j| D ]r}t|}||ksJ||ksJt|trf|r^|t| d}g }||ksxt|tr|| q$|| ||7 }q$q|r|t| |S )z.Pack multiple commands into the Redis protocolr   )r\   r   r   r   r   rl   r   r   )	rC   r   r   piecesbuffer_lengthr   cmdchunkZchunklenr:   r:   r;   pack_commandsr  s0    
z AbstractConnection.pack_commandsc                 C   s   t | jjdkS )zCheck if the socket is emptyr   )r   rX   _bufferr   r:   r:   r;   _socket_is_empty  s    z#AbstractConnection._socket_is_emptyc                    s    |   s| jddI d H  q d S )NT)r   )r   r   r   r:   r:   r;   process_invalidation_messages  s    z0AbstractConnection.process_invalidation_messages)F)T)FN):r5   r6   r7   __doc__	__slots__rk   r<   r)   r,   r   r   rr   r
   r   boollistr4   r   r+   r   ConnectCallbackTr   rv   warningsr   r   r}   r   r   r   propertyr   r   r   rq   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r'   r   r   r   r   r   r:   r:   r:   r;   r>   _   s    

R

+
W  )  >.r>   c                
       s   e Zd ZdZddddddeeeef eee	eeee
f f  ed fdd	Zd
d Ze	dddZdd ZedddZ  ZS )
Connectionz4Manages TCP communication to and from a Redis server	localhosti  FNr   )hostportsocket_keepalivesocket_keepalive_optionssocket_typec                   s8   || _ t|| _|| _|pi | _|| _t jf | d S rA   )r   rr   r   r   r   r   superrv   )rC   r   r   r   r   r   r   r   r:   r;   rv     s    


zConnection.__init__c                 C   s6   d| j fd| jfd| jfg}| jr2|d| jf |S )Nr   r   rG   rI   )r   r   rG   rI   rl   rC   r   r:   r:   r;   r     s    zConnection.repr_piecesr   c                 C   s   | j | jdS )Nr   r   r  r   r:   r:   r;   _connection_arguments  s    z Connection._connection_argumentsc              
      s   t | j4 I dH   tjf |  I dH \}}W 5 Q I dH R X || _|| _|jd}|r|	t
jt
jd z@| jr|	t
jt
jd | j D ]\}}|	t
j|| qW n" ttfk
r   |   Y nX dS )zCreate a TCP socket connectionNrm   ri   )r   rO   rn   Zopen_connectionr  rX   rY   	transportZget_extra_info
setsockoptrm   IPPROTO_TCPTCP_NODELAYr   
SOL_SOCKETSO_KEEPALIVEr   itemsSOL_TCPr   rs   r   )rC   readerwritersockr   r   r:   r:   r;   r     s"    zConnection._connectc                 C   s   | j  d| j S )N:r  r   r:   r:   r;   r     s    zConnection._host_error)r5   r6   r7   r   r   r   rr   r   r
   r	   r   rv   r   r  r   r   __classcell__r:   r:   r   r;   r     s"   
r   c                
       s   e Zd ZdZdee ee eee ee eeej ee d fddZ	e
d fd	d
Zedd Zedd Zedd Zedd Zedd Zedd Zedd Z  ZS )SSLConnectionzManages SSL connections to and from the Redis server(s).
    This class extends the Connection class, adding SSL functionality, and making
    use of ssl.SSLContext (https://docs.python.org/3/library/ssl.html#ssl.SSLContext)
    NrequiredF)ssl_keyfilessl_certfilessl_cert_reqsssl_ca_certsssl_ca_datassl_check_hostnamessl_min_versionssl_ciphersc	           
   
      s,   t ||||||||d| _t jf |	 d S )Nkeyfilecertfile	cert_reqsca_certsca_datacheck_hostnamemin_versionciphers)RedisSSLContextrV   r   rv   )
rC   r  r  r  r  r  r  r  r  r   r   r:   r;   rv     s    
zSSLConnection.__init__r   c                    s   t   }| j |d< |S )Nssl)r   r  rV   r   rC   r   r   r:   r;   r    s    
z#SSLConnection._connection_argumentsc                 C   s   | j jS rA   )rV   r  r   r:   r:   r;   r    s    zSSLConnection.keyfilec                 C   s   | j jS rA   )rV   r  r   r:   r:   r;   r    s    zSSLConnection.certfilec                 C   s   | j jS rA   )rV   r  r   r:   r:   r;   r    s    zSSLConnection.cert_reqsc                 C   s   | j jS rA   )rV   r  r   r:   r:   r;   r    s    zSSLConnection.ca_certsc                 C   s   | j jS rA   )rV   r   r   r:   r:   r;   r     s    zSSLConnection.ca_datac                 C   s   | j jS rA   )rV   r!  r   r:   r:   r;   r!  	  s    zSSLConnection.check_hostnamec                 C   s   | j jS rA   )rV   r"  r   r:   r:   r;   r"    s    zSSLConnection.min_version)NNr  NNFNN)r5   r6   r7   r   r
   r   r   r%  
TLSVersionrv   r	   r  r   r  r  r  r  r   r!  r"  r  r:   r:   r   r;   r    sD           





r  c                
   @   s\   e Zd ZdZd
ee ee ee ee ee eeej ee dddZ	ej
ddd	ZdS )r$  )	r  r  r  r  r   contextr!  r"  r#  NFr  c	           
      C   s   || _ || _|d krtj| _n<t|trZtjtjtjd}	||	krPt	d| |	| | _|| _
|| _|| _|| _|| _d | _d S )N)noneoptionalr  z+Invalid SSL Certificate Requirements Flag: )r  r  r%  	CERT_NONEr  r   r   CERT_OPTIONALCERT_REQUIREDr$   r  r   r!  r"  r#  r(  )
rC   r  r  r  r  r   r!  r"  r#  Z	CERT_REQSr:   r:   r;   rv     s(    


zRedisSSLContext.__init__r   c                 C   s   | j st }| j|_| j|_| jr<| jr<|j| j| jd | j	sH| j
rZ|j| j	| j
d | jd k	rl| j|_| jd k	r|| j || _ | j S )N)r  r  )cafilecadata)r(  r%  create_default_contextr!  r  verify_moder  r  load_cert_chainr  r   load_verify_locationsr"  minimum_versionr#  set_ciphers)rC   r(  r:   r:   r;   r   @  s    

zRedisSSLContext.get)NNNNNFNN)r5   r6   r7   r   r
   r   r   r%  r'  rv   
SSLContextr   r:   r:   r:   r;   r$    s(           !r$  c                       sd   e Zd ZdZdded fddZeeeeee	f f  dddZ
d	d
 ZedddZ  ZS )UnixDomainSocketConnectionz4Manages UDS communication to and from a Redis server pathc                   s   || _ t jf | d S rA   )r:  r   rv   )rC   r:  r   r   r:   r;   rv   T  s    z#UnixDomainSocketConnection.__init__r   c                 C   s.   d| j fd| jfg}| jr*|d| jf |S )Nr:  rG   rI   )r:  rG   rI   rl   r  r:   r:   r;   r   X  s    z&UnixDomainSocketConnection.repr_piecesc              
      sZ   t | j4 I d H  tj| jdI d H \}}W 5 Q I d H R X || _|| _|  I d H  d S )Nr9  )r   rO   rn   Zopen_unix_connectionr:  rX   rY   r   )rC   r  r  r:   r:   r;   r   ^  s
    (z#UnixDomainSocketConnection._connectc                 C   s   | j S rA   r9  r   r:   r:   r;   r   e  s    z&UnixDomainSocketConnection._host_error)r5   r6   r7   r   r   rv   r   r   r   rr   r   r   r   r  r:   r:   r   r;   r7  Q  s
   "r7  )0FFALSENNOr   c                 C   s6   | d ks| dkrd S t | tr.|  tkr.dS t| S )Nr8  F)r   r   upperFALSE_STRINGSr   )valuer:   r:   r;   to_booll  s
    rC  )	rG   rN   rO   r   rQ   max_connectionsrS   r  r   .URL_QUERY_ARGUMENT_PARSERSc                   @   sJ   e Zd ZU eed< eed< ee ed< eed< eed< eed< eed< dS )	ConnectKwargsrH   rM   connection_classr   r   rG   r:  N)r5   r6   r7   r   __annotations__r   r>   rr   r:   r:   r:   r;   rF    s   
rF  F)total)urlr   c              
   C   s  t | }i }t|j D ]v\}}|rt|dkrt|d }t|}|rz||||< W q tt	fk
r   t	d| dY qX q|||< q|j
rt|j
|d< |jrt|j|d< |jdkr|jrt|j|d< t|d< n|jd	kr||jrt|j|d
< |jrt|j|d< |jrfd|krfztt|jdd|d< W n tt	fk
rd   Y nX |jdkrt|d< nd}t	d| d|S )Nr   zInvalid value for 'z' in connection URL.rH   rM   unixr:  rG  )Zredisredissr   r   rG   /r8  rL  zredis://, rediss://, unix://z5Redis URL must specify one of the following schemes ())r   r   queryr
  r   r   rE  r   rs   rt   rH   rM   schemer:  r7  hostnamer   rr   replaceAttributeErrorr  )rJ  parsedr   nameZ
value_listrB  r   Zvalid_schemesr:   r:   r;   	parse_url  sJ    





rV  _CPConnectionPool)boundc                   @   s   e Zd ZdZeee eedddZe	dfee
 ee dddZd	d
 Zdd ZedddZdd Zdd Zdd Zdd Ze
dddZe
dddZd'eddd Zddd!d"Zd#dd$d%d&ZdS )(rX  a  
    Create a connection pool. ``If max_connections`` is set, then this
    object raises :py:class:`~redis.ConnectionError` when the pool's
    limit is reached.

    By default, TCP connections are created unless ``connection_class``
    is specified. Use :py:class:`~redis.UnixDomainSocketConnection` for
    unix sockets.

    Any additional keyword arguments are passed to the constructor of
    ``connection_class``.
    )clsrJ  r   c                 K   s   t |}|| | f |S )a  
        Return a connection pool 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.
        )rV  update)rZ  rJ  r   Zurl_optionsr:   r:   r;   from_url  s    +
zConnectionPool.from_urlNrG  rD  c                 K   sV   |pd}t |tr|dk r"td|| _|| _|| _g | _t | _| j	dt
| _d S )Nl        r   z,"max_connections" must be a positive integerrh   )r   rr   rt   rG  connection_kwargsrD  _available_connectionsset_in_use_connectionsr   r,   rh   )rC   rG  rD  r^  r:   r:   r;   rv     s    zConnectionPool.__init__c                 C   s*   d| j j d| j j d| jf | jdS )Nr   r   r   r   )r   r6   r5   rG  r^  r   r:   r:   r;   r     s    (zConnectionPool.__repr__c                 C   s   g | _ t | _d S rA   )r_  r   WeakSetra  r   r:   r:   r;   reset  s    zConnectionPool.resetr   c                 C   s   | j pt| j| jk S )z;Return True if a connection can be retrieved from the pool.)r_  r   ra  rD  r   r:   r:   r;   can_get_connection  s    z!ConnectionPool.can_get_connectionc                    sH   |   }z| |I dH  W n& tk
rB   | |I dH   Y nX |S )z(Get a connected connection from the poolN)get_available_connectionensure_connectionr   release)rC   command_namekeysoptionsr@   r:   r:   r;   get_connection$  s    zConnectionPool.get_connectionc                 C   sV   z| j  }W n6 tk
rD   t| j| jkr8tdd|  }Y nX | j| |S )zCGet a connection from the pool, without making sure it is connectedzToo many connectionsN)	r_  pop
IndexErrorr   ra  rD  r"   make_connectionaddrB   r:   r:   r;   re  /  s    
z'ConnectionPool.get_available_connectionc                 C   s.   | j }| j|dd|dd|dddS )z,Return an encoder based on encoding settingsrb   r`   rc   ra   rd   F)rb   rc   rd   )r^  rh   r   r&  r:   r:   r;   get_encoder:  s    


zConnectionPool.get_encoderc                 C   s   | j f | jS )z=Create a new connection.  Can be overridden by child classes.)rG  r^  r   r:   r:   r;   rn  C  s    zConnectionPool.make_connectionr?   c              	      s|   |  I dH  z| I dH r(tddW nL ttfk
rv   | I dH  |  I dH  | I dH rrtddY nX dS )z8Ensure that the connection object is connected and validNzConnection has datazConnection not ready)r   r   r"   r   r   rB   r:   r:   r;   rf  G  s    z ConnectionPool.ensure_connectionc                    s   | j | | j| dS )z(Releases the connection back to the poolN)ra  r   r_  rl   rB   r:   r:   r;   rg  W  s    zConnectionPool.releaseT)inuse_connectionsc                    sZ   |rt | j| j}n| j}tjdd |D ddiI dH }tdd |D d}|rV|dS )z
        Disconnects connections in the pool

        If ``inuse_connections`` is True, disconnect connections that are
        current in use, potentially by other tasks. Otherwise only disconnect
        connections that are idle in the pool.
        c                 s   s   | ]}|  V  qd S rA   r   )r   r@   r:   r:   r;   r   m  s     z,ConnectionPool.disconnect.<locals>.<genexpr>Zreturn_exceptionsTNc                 s   s   | ]}t |tr|V  qd S rA   )r   r   )r   rr:   r:   r;   r   p  s     
 )r   r_  ra  rn   Zgathernext)rC   rq  connectionsrespr   r:   r:   r;   r   ^  s     zConnectionPool.disconnectc                    s   |   I dH  dS )z-Close the pool, disconnecting all connectionsNr   r   r:   r:   r;   acloset  s    zConnectionPool.acloser   )rg   r   c                 C   s(   | j D ]
}||_q| jD ]
}||_qd S rA   )r_  rg   ra  )rC   rg   connr:   r:   r;   	set_retryx  s    

zConnectionPool.set_retry)T)r5   r6   r7   r   classmethodr   rW  r   r\  r   r>   r
   rr   rv   r   rc  r   rd  rk  re  rp  rn  rf  rg  r   rv  rx  r:   r:   r:   r;   rX    s*   0	c                       sd   e Zd ZdZddeejfeee e	e
 e	ej d fddZ fddZe
d	 fd
dZ  ZS )BlockingConnectionPoola  
    A blocking connection pool::

        >>> from redis.asyncio import Redis, BlockingConnectionPool
        >>> client = Redis.from_pool(BlockingConnectionPool())

    It performs the same function as the default
    :py:class:`~redis.asyncio.ConnectionPool` implementation, in that,
    it maintains a pool of reusable connections that can be shared by
    multiple async redis clients.

    The difference is that, in the event that a client tries to get a
    connection from the pool when all of connections are in use, rather than
    raising a :py:class:`~redis.ConnectionError` (as the default
    :py:class:`~redis.asyncio.ConnectionPool` implementation does), it
    blocks the current `Task` for a specified number of seconds until
    a connection becomes available.

    Use ``max_connections`` to increase / decrease the pool size::

        >>> pool = BlockingConnectionPool(max_connections=10)

    Use ``timeout`` to tell it either how many seconds to wait for a connection
    to become available, or to block forever:

        >>> # Block forever.
        >>> pool = BlockingConnectionPool(timeout=None)

        >>> # Raise a ``ConnectionError`` after five seconds if a connection is
        >>> # not available.
        >>> pool = BlockingConnectionPool(timeout=5)
    2      )rD  r   rG  queue_classc                    s,   t  jf ||d| t | _|| _d S )Nr]  )r   rv   rn   	Condition
_conditionr   )rC   rD  r   rG  r}  r^  r   r:   r;   rv     s    
zBlockingConnectionPool.__init__c                    s   zf| j 4 I dH H t| j4 I dH $ | j | jI dH  t  }W 5 Q I dH R X W 5 Q I dH R X W n. tjk
r } zt	d|W 5 d}~X Y nX z| 
|I dH  |W S  tk
r   | |I dH   Y nX dS )z@Gets a connection from the pool, blocking until one is availableNzNo connection available.)r  r   r   r   rd  r   re  rn   r&   r"   rf  r   rg  )rC   rh  ri  rj  r@   errr   r:   r;   rk    s    .z%BlockingConnectionPool.get_connectionr?   c              
      s@   | j 4 I dH " t |I dH  | j   W 5 Q I dH R X dS )z)Releases the connection back to the pool.N)r  r   rg  notifyrB   r   r:   r;   rg    s    zBlockingConnectionPool.release)r5   r6   r7   r   r   rn   	LifoQueuerr   r
   r   r>   Queuerv   rk  rg  r  r:   r:   r   r;   rz    s   #rz  )drn   ro   enumr   rm   r%  sysr   r   abcr   	itertoolsr   typesr   typingr   r   r   r   r	   r
   r   r   r   r   r   r   r   urllib.parser   r   r   r   utilsr   version_infor   r   Zredis.asyncio.retryr   Zredis.backoffr   Zredis.connectionr   Zredis.credentialsr   r   Zredis.exceptionsr    r!   r"   r#   r$   r%   r&   Zredis.typingr'   Zredis.utilsr(   r)   r*   _parsersr+   r,   r-   r.   r/   r   r   r   ZSYM_LFr   Enumr4   r9   rk   rH  r<   r=   rF   r   r>   r   r  r$  r7  rA  r   rC  rr   r   rE  r   r8   rF  rV  rW  rX  rz  r:   r:   r:   r;   <module>   s    <
$	    >9@?
4 <