U
    	d                  
   @   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m	Z	 d dlm
Z
 d dl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 d d	lmZ d d
lmZ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+m,Z,m-Z-m.Z. d dl/m0Z0 d dl1m2Z2m3Z3m4Z4m5Z5 zd dl6Z6dZ7W n e8k
r\   dZ7Y nX e9ej:iZ;e7re<e6drde;e6j=< de;e6j>< n
de;e6j?< e@e;A ZBe3rd dlCZCdZDdZEdZFdZGdZHeI ZJdZKdZLdZMdZNeedZOG dd dZPG dd dZQG d d! d!ZRG d"d# d#eQZSG d$d% d%eQZTeQeUd&< e3rFeTZVneSZVG d'd( d(ZWG d)d* d*ZXG d+d, d,ZYG d-d. d.eYZZG d/d0 d0eZZ[G d1d2 d2eYZ\d3Z]d4d5 Z^e_e`e`e^e^eae_e_e^d6	Zbd7d8 ZcG d9d: d:ZdG d;d< d<edZedS )=    N)abstractmethod)SEEK_END)chain)EmptyFull	LifoQueue)time)OptionalUnion)parse_qsunquoteurlparse)	NoBackoff)CredentialProvider"UsernamePasswordCredentialProvider)AuthenticationError$AuthenticationWrongNumberOfArgsErrorBusyLoadingErrorChildDeadlockedErrorConnectionError	DataErrorExecAbortErrorInvalidResponseModuleErrorNoPermissionErrorNoScriptErrorOutOfMemoryErrorReadOnlyError
RedisErrorResponseErrorTimeoutError)Retry)CRYPTOGRAPHY_AVAILABLEHIREDIS_AVAILABLEHIREDIS_PACK_AVAILABLEstr_if_bytesTFSSLWantReadError      *   $s   
    zConnection closed by server.z:Error loading the extension. Please check the server logs.z5Error unloading module: no such module with that namez/Error unloading module: operation not possible.z[Error unloading module: the module exports one or more module-side data types, can't unload)zxAUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?z(Client sent AUTH, but no password is setc                   @   s*   e Zd ZdZdd Zdd Zd
ddZd	S )Encoderz=Encode strings to bytes-like and decode bytes-like to stringsc                 C   s   || _ || _|| _d S Nencodingencoding_errorsdecode_responses)selfr.   r/   r0    r2   M/var/www/html/myproject/myenv/lib/python3.8/site-packages/redis/connection.py__init__`   s    zEncoder.__init__c                 C   s   t |ttfr|S t |tr&tdn@t |ttfrBt| }n$t |t	sft
|j}td| dt |t	r|| j| j}|S )z=Return a bytestring or bytes-like representation of the valuezNInvalid input of type: 'bool'. Convert to a bytes, string, int or float first.zInvalid input of type: 'z2'. Convert to a bytes, string, int or float first.)
isinstancebytes
memoryviewboolr   intfloatreprencodestrtype__name__r.   r/   )r1   valuetypenamer2   r2   r3   r<   e   s     




zEncoder.encodeFc                 C   s:   | j s
|r6t|tr| }t|tr6|| j| j}|S )z:Return a unicode string from the bytes-like representation)r0   r5   r7   tobytesr6   decoder.   r/   )r1   r@   forcer2   r2   r3   rC   |   s    


zEncoder.decodeN)F)r?   
__module____qualname____doc__r4   r<   rC   r2   r2   r2   r3   r+   ]   s   r+   c                   @   sT   e Zd Zdedededeeeeee	ee
eieeeeeeeeed	Zedd ZdS )	
BaseParserzmax number of clients reachedzinvalid passwordz,wrong number of arguments for 'auth' commandz,wrong number of arguments for 'AUTH' command)	ZERRZOOMZ	WRONGPASSZ	EXECABORTZLOADINGZNOSCRIPTZREADONLYZNOAUTHZNOPERMc                 C   s\   | dd }|| jkrT|t|d d }| j| }t|trL||t}||S t|S )zParse an error response r      N)splitEXCEPTION_CLASSESlenr5   dictgetr   )clsresponseZ
error_codeZexception_classr2   r2   r3   parse_error   s    


zBaseParser.parse_errorN)r?   rE   rF   r   r   r   MODULE_LOAD_ERRORr   MODULE_EXPORTS_DATA_TYPES_ERRORNO_SUCH_MODULE_ERROR MODULE_UNLOAD_NOT_POSSIBLE_ERRORNO_AUTH_SET_ERRORr   r   r   r   r   r   rL   classmethodrR   r2   r2   r2   r3   rH      s<         rH   c                   @   s   e Zd ZejeedddZedddZdedfe	e e
eef e	e ed	d
dZeedddZeedddZedddZedddZeddddZddddZddddZdS )SocketBuffer)socketsocket_read_sizesocket_timeoutc                 C   s    || _ || _|| _t | _d S r,   )_sockr[   r\   ioBytesIO_buffer)r1   rZ   r[   r\   r2   r2   r3   r4      s    zSocketBuffer.__init__returnc                 C   s,   | j  }| j dt}| j | || S )z3
        Remaining unread length of buffer
        r   )r`   tellseekr   )r1   posendr2   r2   r3   unread_bytes   s    
zSocketBuffer.unread_bytesNT)lengthtimeoutraise_on_timeoutrb   c              
   C   sR  | j }| j}d}|tk	}| j}| }	|dt |r@|| zz`| j 	|}
t
|
trnt|
dkrntt||
 t|
}||7 }|d k	r||krqDW W dS  tjk
r   |rtdY W jdS  tk
r* } zBt|jd}|s
|j|kr
W Y W *dS td|j W 5 d }~X Y nX W 5 ||	 |rL|| j X d S Nr   TzTimeout reading from socketFz!Error while reading from socket: )r]   r[   SENTINELr`   rc   rd   r   
settimeoutr\   recvr5   r6   rM   r   SERVER_CLOSED_CONNECTION_ERRORwriterZ   ri   r    NONBLOCKING_EXCEPTIONS#NONBLOCKING_EXCEPTION_ERROR_NUMBERSrO   	__class__errnoargs)r1   rh   ri   rj   sockr[   markercustom_timeoutbufZcurrent_posdataZdata_lengthexallowedr2   r2   r3   _read_from_socket   s>    



&
zSocketBuffer._read_from_socket)ri   rb   c                 C   s   t |  p| j|ddS )NFri   rj   )r8   rg   r~   r1   ri   r2   r2   r3   can_read   s     zSocketBuffer.can_read)rh   rb   c                 C   sJ   |d }| j |}|t| }|r>| | || j |7 }|d d S )Nr'   )r`   readrM   r~   )r1   rh   r{   missingr2   r2   r3   r      s    
zSocketBuffer.readc                 C   s:   | j }| }|ts.|   || 7 }q|d d S )Nr   )r`   readlineendswithSYM_CRLFr~   )r1   rz   r{   r2   r2   r3   r     s    
zSocketBuffer.readlinec                 C   s
   | j  S )z+
        Get current read position
        )r`   rc   r1   r2   r2   r3   get_pos  s    zSocketBuffer.get_pos)re   rb   c                 C   s   | j | dS )zO
        Rewind the buffer to a specific position, to re-start reading
        N)r`   rd   )r1   re   r2   r2   r3   rewind  s    zSocketBuffer.rewindc                 C   sX   |   }|dkrdS |dkr<| j }|| d |d|< | j| | jd dS )zH
        After a successful read, purge the read part of buffer
        r   N)rg   r`   	getbuffertruncaterd   )r1   Zunreadviewr2   r2   r3   purge  s    
zSocketBuffer.purgec                 C   s4   z| j   W n tk
r"   Y nX d | _ d | _d S r,   )r`   close	Exceptionr]   r   r2   r2   r3   r   *  s    zSocketBuffer.close)r?   rE   rF   rZ   r9   r:   r4   rg   rm   r	   r
   objectr8   r~   r   r6   r   r   r   r   r   r   r2   r2   r2   r3   rY      s*     
/
rY   c                   @   sL   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdddZ	dddZ
dS )PythonParserzPlain Python parsing classc                 C   s   || _ d | _d | _d | _d S r,   )r[   encoderr]   r`   r1   r[   r2   r2   r3   r4   ;  s    zPythonParser.__init__c                 C   s&   z|    W n tk
r    Y nX d S r,   on_disconnectr   r   r2   r2   r3   __del__A  s    zPythonParser.__del__c                 C   s(   |j | _ t| j | j|j| _|j| _dS )zCalled when the socket connectsN)r]   rY   r[   r\   r`   r   r1   
connectionr2   r2   r3   
on_connectG  s      zPythonParser.on_connectc                 C   s*   d| _ | jdk	r | j  d| _d| _dS )z"Called when the socket disconnectsN)r]   r`   r   r   r   r2   r2   r3   r   O  s
    

zPythonParser.on_disconnectc                 C   s   | j o| j |S r,   )r`   r   r   r2   r2   r3   r   W  s    zPythonParser.can_readFc                 C   s`   | j r| j  nd }z| j|d}W n( tk
rL   | j rF| j |  Y nX | j   |S d S )Ndisable_decoding)r`   r   _read_responseBaseExceptionr   r   )r1   r   re   resultr2   r2   r3   read_responseZ  s    
zPythonParser.read_responsec                    s  j  }|stt|d d |dd   }}|dkrb|jddd}|}t|tr^||S |dkrln|dkr|t|S |dkr|d	krd S |dkrj t|}nH|d
kr|d	krd S |d
kr fddt	t|D }nt
d| dkrj|}|S )NrJ      -utf-8replace)errors   +   :r)   s   -1r(   c                    s   g | ]}j  d qS )r   )r   ).0ir   r1   r2   r3   
<listcomp>  s   z/PythonParser._read_response.<locals>.<listcomp>zProtocol Error: F)r`   r   r   rp   rC   rR   r5   r9   r   ranger   r   )r1   r   rawbyterQ   errorr2   r   r3   r   f  s8    




zPythonParser._read_responseN)F)F)r?   rE   rF   rG   r4   r   r   r   r   r   r   r2   r2   r2   r3   r   8  s   
r   c                   @   sP   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Ze	dfddZ
dddZdS )HiredisParserz*Parser class for connections using Hiredisc                 C   s    t std|| _t|| _d S )NzHiredis is not installed)r#   r   r[   	bytearrayr`   r   r2   r2   r3   r4     s    zHiredisParser.__init__c                 C   s&   z|    W n tk
r    Y nX d S r,   r   r   r2   r2   r3   r     s    zHiredisParser.__del__c                 K   sN   |j | _ |j| _t| j|jjd}|jjr6|jj|d< t	j
f || _d| _d S )N)ZprotocolErrorZ
replyErrorr   r.   F)r]   r\   _socket_timeoutr   rR   r   r/   r0   r.   hiredisReader_reader_next_response)r1   r   kwargsr2   r2   r3   r     s    zHiredisParser.on_connectc                 C   s   d | _ d | _d| _d S )NF)r]   r   r   r   r2   r2   r3   r     s    zHiredisParser.on_disconnectc                 C   s@   | j stt| jdkr<| j  | _| jdkr<| j|ddS dS )NFr   T)r   r   rp   r   getsread_from_socketr   r2   r2   r3   r     s    

zHiredisParser.can_readTc              
   C   s   | j }|tk	}zzH|r || | j | j}|dkr>tt| j	| jd| W W dS  t
jk
r   |rvtdY W ddS  tk
r } z>t|jd}|s|j|krW Y W *dS td|j W 5 d }~X Y nX W 5 |r|| j X d S rk   )r]   rm   rn   r   	recv_intor`   r   rp   r   feedrZ   ri   r    rr   rs   rO   rt   ru   rv   )r1   ri   rj   rw   ry   Zbufflenr|   r}   r2   r2   r3   r     s*    


&zHiredisParser.read_from_socketFc                 C   s   | j stt| jdk	r(| j}d| _|S |r:| j d}n
| j  }|dkrr|   |rf| j d}qD| j  }qDt|tr|n$t|tr|rt|d tr|d |S )NFr   )r   r   rp   r   r   r   r5   list)r1   r   rQ   r2   r2   r3   r     s0    


zHiredisParser.read_responseN)F)r?   rE   rF   rG   r4   r   r   r   r   rm   r   r   r2   r2   r2   r3   r     s   
r   DefaultParserc                   @   s   e Zd Zdd ZdS )HiredisRespSerializerc                 G   s   g }t |d tr4t|d   |dd  }n(d|d kr\t|d  |dd  }z|t| W n0 tk
r   t	
 \}}}t||Y nX |S 2Pack a series of arguments into the Redis protocolr   rJ   N    )r5   r=   tupler<   rK   appendr   pack_command	TypeErrorsysexc_infor   with_traceback)r1   rv   output_r@   	tracebackr2   r2   r3   pack
  s    "zHiredisRespSerializer.packN)r?   rE   rF   r   r2   r2   r2   r3   r   	  s   r   c                   @   s"   e Zd ZddddZdd ZdS )PythonRespSerializerNra   c                 C   s   || _ || _d S r,   )_buffer_cutoffr<   )r1   buffer_cutoffr<   r2   r2   r3   r4     s    zPythonRespSerializer.__init__c              	   G   s  g }t |d tr4t|d   |dd  }n(d|d kr\t|d  |dd  }tttt| t	f}| j
}t| j|D ]|}t|}t||ks||kst |trt|tt| t	f}|| || t	}qt|tt| t	|t	f}q|| |S r   )r5   r=   r   r<   rK   	SYM_EMPTYjoinSYM_STARrM   r   r   mapr7   
SYM_DOLLARr   )r1   rv   r   Zbuffr   argZ
arg_lengthr2   r2   r3   r      s@    "





zPythonRespSerializer.pack)r?   rE   rF   r4   r   r2   r2   r2   r3   r     s   r   c                   @   s  e Zd ZdZdddddedddeddddddddfee dd	d
Zdd Z	e
dd Zdd Zdd Zdd Zdd Zdd Zdd Ze
dd Ze
dd Ze
dd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd9d,d-Zd.d/ Zd:d0d1Zd;d+d2ed2d3d4Zd5d6 Zd7d8 Z dS )<AbstractConnectionz0Manages communication to and from a Redis serverr   NFr   stricti   )credential_providerc                 C   s  |s|r|dk	rt dt | _|| _|| _|| _|| _|| _|| _	|dkrR|}|| _
|| _|tkrjg }|rx|t || _|s|r|dkrtt d| _nt|| _| j| ntt d| _|| _d| _|| _t|||	| _d| _|| _| |
 g | _d| _|  || _!dS )a2  
        Initialize a new Connection.
        To specify a retry policy for specific errors, first set
        `retry_on_error` to a list of the error/s to retry on, then set
        `retry` to a valid `Retry` object.
        To retry on TimeoutError, `retry_on_timeout` can also be set to `True`.
        Nz'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'rJ   r   ip  )"r   osgetpidpiddbclient_namer   passwordusernamer\   socket_connect_timeoutretry_on_timeoutrm   r   r    retry_on_errorr!   r   retrycopydeepcopyZupdate_supported_errorshealth_check_intervalnext_health_checkredis_connect_funcr+   r   r]   _socket_read_size
set_parser_connect_callbacksr   _construct_command_packer_command_packer)r1   r   r   r\   r   r   r   r.   r/   r0   parser_classr[   r   r   r   r   r   r   Zcommand_packerr2   r2   r3   r4   Q  sH    


zAbstractConnection.__init__c                 C   s,   d dd |  D }| jj d| dS )N,c                 S   s   g | ]\}}| d | qS )=r2   )r   kvr2   r2   r3   r     s     z/AbstractConnection.__repr__.<locals>.<listcomp><>)r   repr_piecesrt   r?   )r1   Z	repr_argsr2   r2   r3   __repr__  s    zAbstractConnection.__repr__c                 C   s   d S r,   r2   r   r2   r2   r3   r     s    zAbstractConnection.repr_piecesc                 C   s&   z|    W n tk
r    Y nX d S r,   )
disconnectr   r   r2   r2   r3   r     s    zAbstractConnection.__del__c                 C   s*   |d k	r|S t rt S t| j| jjS d S r,   )r$   r   r   r   r   r<   )r1   packerr2   r2   r3   r     s
    z,AbstractConnection._construct_command_packerc                 C   s   | j t| d S r,   )r   r   weakref
WeakMethod)r1   callbackr2   r2   r3   register_connect_callback  s    z,AbstractConnection.register_connect_callbackc                 C   s
   g | _ d S r,   )r   r   r2   r2   r3   clear_connect_callbacks  s    z*AbstractConnection.clear_connect_callbacksc                 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
        )r[   N)r   _parser)r1   r   r2   r2   r3   r     s    zAbstractConnection.set_parserc              
      s    j r
dS z" j fdd fdd}W nL tjk
rJ   tdY n0 tk
rx } zt |W 5 d}~X Y nX | _ z" j	dkr 
  n
 	  W n tk
r       Y nX  jD ]}| }|r|  qdS )z5Connects to the Redis server if not already connectedNc                      s      S r,   )_connectr2   r   r2   r3   <lambda>  r*   z,AbstractConnection.connect.<locals>.<lambda>c                    s
     | S r,   r   )r   r   r2   r3   r     r*   zTimeout connecting to server)r]   r   call_with_retryrZ   ri   r    OSErrorr   _error_messager   r   r   r   r   )r1   rw   erefr   r2   r   r3   connect  s.    
 
 


zAbstractConnection.connectc                 C   s   d S r,   r2   r   r2   r2   r3   r     s    zAbstractConnection._connectc                 C   s   d S r,   r2   r   r2   r2   r3   _host_error  s    zAbstractConnection._host_errorc                 C   s   d S r,   r2   )r1   	exceptionr2   r2   r3   r    s    z!AbstractConnection._error_messagec                 C   s   | j |  | js| js| jr| jp0t| j| j}| }| jd|ddi z|  }W n0 t	k
r   | jd|d dd |  }Y nX t
|dkrtd| jr| dd	| j t
|  dkrtd
| jr| d| j t
|  dkrtddS )z=Initialize the connection, authenticate and select a databaseAUTHcheck_healthFrl   r
  OKzInvalid Username or PasswordZCLIENTZSETNAMEzError setting client nameZSELECTzInvalid DatabaseN)r	  )r   r   r   r   r   r   Zget_credentialssend_commandr   r   r%   r   r   r   r   )r1   Zcred_providerZ	auth_argsZauth_responser2   r2   r3   r     s,    zAbstractConnection.on_connectc                 G   s|   | j   | j}d| _|dkr"dS t | jkrVz|tj W n t	k
rT   Y nX z|
  W n t	k
rv   Y nX dS )z!Disconnects from the Redis serverN)r   r   r]   r   r   r   shutdownrZ   	SHUT_RDWRr  r   )r1   rv   Z	conn_sockr2   r2   r3   r     s    
zAbstractConnection.disconnectc                 C   s*   | j ddd t|  dkr&tddS )z Send PING, expect PONG in returnZPINGFr  ZPONGz#Bad response from PING health checkN)r  r%   r   r   r   r2   r2   r3   
_send_ping'  s    zAbstractConnection._send_pingc                 C   s   |    dS )z Function to call when PING failsNr   )r1   r   r2   r2   r3   _ping_failed-  s    zAbstractConnection._ping_failedc                 C   s(   | j r$t | jkr$| j| j| j dS )z3Check the health of the connection with a PING/PONGN)r   r   r   r   r  r  r  r   r2   r2   r3   r
  1  s    zAbstractConnection.check_healthTc              
   C   s   | j s|   |r|   z*t|tr,|g}|D ]}| j | q0W n tjk
rj   |   t	dY n t
k
r } zV|   t|jdkrd|jd  }}n|jd }|jd }td| d| dW 5 d}~X Y n tk
r   |    Y nX dS )	z2Send an already packed command to the Redis serverzTimeout writing to socketrJ   UNKNOWNr   Error z while writing to socket. .N)r]   r  r
  r5   r=   sendallrZ   ri   r   r    r  rM   rv   r   r   )r1   commandr
  itemr  ru   errmsgr2   r2   r3   send_packed_command6  s,    


&z&AbstractConnection.send_packed_commandc                 O   s"   | j | jj| |ddd dS )z+Pack and send a command to the Redis serverr
  Tr  N)r  r   r   rO   )r1   rv   r   r2   r2   r3   r  U  s    

zAbstractConnection.send_commandc              
   C   sn   | j }|s|   |  }z| j|W S  tk
rh } z"|   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.Error while reading from z: N)	r]   r  r  r   r   r  r   r   rv   )r1   ri   rw   
host_errorr  r2   r2   r3   r   \  s    zAbstractConnection.can_read)disconnect_on_errorc             
   C   s   |   }z| jj|d}W n tjk
rJ   |r8|   td| Y nd tk
r } z&|rf|   td| d|j	 W 5 d}~X Y n" t
k
r   |r|    Y nX | jrt | j | _t|tr||S )z0Read the response from a previously sent commandr   zTimeout reading from r  z : N)r  r   r   rZ   ri   r   r    r  r   rv   r   r   r   r   r5   r   )r1   r   r  r  rQ   r  r2   r2   r3   r   j  s,    
z AbstractConnection.read_responsec                 G   s   | j j| S )r   )r   r   )r1   rv   r2   r2   r3   r     s    zAbstractConnection.pack_commandc           	      C   s   g }g }d}| j }|D ]}| jj| D ]r}t|}||ksL||ksLt|trh|r`|t| d}g }||kszt|tr|| q&|| ||7 }q&q|r|t| |S )z.Pack multiple commands into the Redis protocolr   )	r   r   r   rM   r5   r7   r   r   r   )	r1   commandsr   piecesZbuffer_lengthr   cmdchunkZchunklenr2   r2   r3   pack_commands  s0    
z AbstractConnection.pack_commands)T)r   )F)!r?   rE   rF   rG   rm   r   r	   r   r4   r   r   r   r   r   r   r   r   r  r   r  r  r   r   r  r  r
  r  r  r   r8   r   r   r!  r2   r2   r2   r3   r   N  sj   I
!


(

 "r   c                       sB   e Zd ZdZd fdd	Zd	d
 Zdd Zdd Zdd Z  Z	S )
Connectionz4Manages TCP communication to and from a Redis server	localhost  FNr   c                    s8   || _ t|| _|| _|pi | _|| _t jf | d S r,   )hostr9   portsocket_keepalivesocket_keepalive_optionssocket_typesuperr4   )r1   r%  r&  r'  r(  r)  r   rt   r2   r3   r4     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&  r   r   )r%  r&  r   r   r   r1   r  r2   r2   r3   r     s    zConnection.repr_piecesc                 C   s  d}t | j| j| jt jD ]}|\}}}}}d}zt  |||}|t jt jd | j	r|t j
t jd | j D ]\}	}
|t j|	|
 qv|| j || || j |W   S  tk
r } z|}|dk	r|  W 5 d}~X Y qX q|dk	r|tddS )zCreate a TCP socket connectionNrJ   z)socket.getaddrinfo returned an empty list)rZ   getaddrinfor%  r&  r)  SOCK_STREAM
setsockoptIPPROTO_TCPTCP_NODELAYr'  
SOL_SOCKETSO_KEEPALIVEr(  itemsrn   r   r  r\   r  r   )r1   errresfamilysocktypeproto	canonnameZsocket_addressrw   r   r   r   r2   r2   r3   r     s6       


zConnection._connectc                 C   s   | j  d| j S )N:)r%  r&  r   r2   r2   r3   r    s    zConnection._host_errorc                 C   s   |   }t|jdkrXzd| d|jd  dW S  tk
rT   d|jd   Y S X nLz&d|jd  d| d	|jd  dW S  tk
r   d|jd   Y S X d S )
NrJ   zError connecting to z.                         r   r  zConnection Error: r  z connecting to . )r  rM   rv   AttributeErrorr1   r  r  r2   r2   r3   r    s    
"zConnection._error_message)r#  r$  FNr   
r?   rE   rF   rG   r4   r   r   r  r  __classcell__r2   r2   r+  r3   r"    s        )r"  c                       s.   e Zd ZdZd	 fdd	Z f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requiredFc                    s   t std|| _|| _|dkr(tj}n:t|trbtjtjtj	d}||krZtd| || }|| _
|| _|| _|| _|| _|| _|	| _|
| _|| _|| _t jf | dS )ae  Constructor

        Args:
            ssl_keyfile: Path to an ssl private key. Defaults to None.
            ssl_certfile: Path to an ssl certificate. Defaults to None.
            ssl_cert_reqs: The string value for the SSLContext.verify_mode (none, optional, required). Defaults to "required".
            ssl_ca_certs: The path to a file of concatenated CA certificates in PEM format. Defaults to None.
            ssl_ca_data: Either an ASCII string of one or more PEM-encoded certificates or a bytes-like object of DER-encoded certificates.
            ssl_check_hostname: If set, match the hostname during the SSL handshake. Defaults to False.
            ssl_ca_path: The path to a directory containing several CA certificates in PEM format. Defaults to None.
            ssl_password: Password for unlocking an encrypted private key. Defaults to None.

            ssl_validate_ocsp: If set, perform a full ocsp validation (i.e not a stapled verification)
            ssl_validate_ocsp_stapled: If set, perform a validation on a stapled ocsp response
            ssl_ocsp_context: A fully initialized OpenSSL.SSL.Context object to be used in verifying the ssl_ocsp_expected_cert
            ssl_ocsp_expected_cert: A PEM armoured string containing the expected certificate to be returned from the ocsp verification service.

        Raises:
            RedisError
        z$Python wasn't built with SSL supportN)noneoptionalrB  z+Invalid SSL Certificate Requirements Flag: )ssl_availabler   keyfilecertfilessl	CERT_NONEr5   r=   CERT_OPTIONALCERT_REQUIRED	cert_reqsca_certsca_dataca_pathcheck_hostnamecertificate_passwordssl_validate_ocspssl_validate_ocsp_stapledssl_ocsp_contextssl_ocsp_expected_certr*  r4   )r1   Zssl_keyfileZssl_certfileZssl_cert_reqsZssl_ca_certsZssl_ca_datassl_check_hostnameZssl_ca_pathZssl_passwordrR  rS  rT  rU  r   Z	CERT_REQSr+  r2   r3   r4     s6    $
zSSLConnection.__init__c           
         s  t   }t }| j|_| j|_| js.| jrD|j	| j| j| j
d | jdk	sb| jdk	sb| jdk	rx|j| j| j| jd |j|| jd}| jdkrtdkrtd| jr| jrtd| jr\d	dl}d
dlm} | jdkr|j|jj}|| j || j n| j}||| j |j |t!! }|"  |#| j| j$f |%  |&  |S | jdkrtrd
dlm'} ||| j| j$| j}	|	( r|S t)d|S )z Wrap the socket with SSL support)rG  rF  r   N)cafilecapathcadata)server_hostnameTFzcryptography is not installed.zKEither an OCSP staple or pure OCSP connection must be validated - not both.r   rJ   )ocsp_staple_verifier)OCSPVerifierzocsp validation error)*r*  r   rH  create_default_contextrP  rL  verify_moderG  rF  load_cert_chainrQ  rM  rO  rN  load_verify_locationswrap_socketr%  rR  r"   r   rS  OpenSSLZocspr[  rT  ZSSLContextZSSLv23_METHODZuse_certificate_fileZuse_privatekey_fileZset_ocsp_client_callbackrU  r"  rZ   Zrequest_ocspr  r&  do_handshaker  r\  Zis_validr   )
r1   rw   contextsslsockrb  r[  Z
staple_ctxconr\  or+  r2   r3   r   R  sj    
   
zSSLConnection._connect)NNrB  NNFNNFFNN)r?   rE   rF   rG   r4   r   r@  r2   r2   r+  r3   rA  
  s               BrA  c                       sB   e Zd ZdZd fdd	Zdd Zdd Zd	d
 Zdd Z  Z	S )UnixDomainSocketConnectionz4Manages UDS communication to and from a Redis server c                    s   || _ t jf | d S r,   )pathr*  r4   )r1   rk  r   r+  r2   r3   r4     s    z#UnixDomainSocketConnection.__init__c                 C   s.   d| j fd| jfg}| jr*|d| jf |S )Nrk  r   r   )rk  r   r   r   r,  r2   r2   r3   r     s    z&UnixDomainSocketConnection.repr_piecesc                 C   s8   t  t jt j}|| j || j || j |S )z&Create a Unix domain socket connection)rZ   AF_UNIXr.  rn   r   r  rk  r\   )r1   rw   r2   r2   r3   r     s
    z#UnixDomainSocketConnection._connectc                 C   s   | j S r,   )rk  r   r2   r2   r3   r    s    z&UnixDomainSocketConnection._host_errorc                 C   sV   |   }t|jdkr.d| d|jd  dS d|jd  d| d|jd  dS d S )NrJ   z!Error connecting to unix socket: r<  r   r  r  z connecting to unix socket: )r  rM   rv   r>  r2   r2   r3   r    s    "z)UnixDomainSocketConnection._error_message)rj  r?  r2   r2   r+  r3   ri    s   ri  )0FFALSENNOc                 C   s6   | d ks| dkrd S t | tr.|  tkr.dS t| S )Nrj  F)r5   r=   upperFALSE_STRINGSr8   )r@   r2   r2   r3   to_bool  s
    rt  )	r   r\   r   r'  r   r   max_connectionsr   rV  c              
   C   s  |  ds&|  ds&|  ds&td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rt| j|d< t|d< n| jr"t| j|d< | jr8t| j|d< | jrd|krztt| jdd|d< W n ttfk
r   Y nX | jdkrt|d< |S )Nzredis://z	rediss://zunix://zRRedis URL must specify one of the following schemes (redis://, rediss://, unix://)r   zInvalid value for `z` in connection URL.r   r   unixrk  connection_classr%  r&  r   /rj  Zrediss)
startswith
ValueErrorr   r   queryr4  rM   r   URL_QUERY_ARGUMENT_PARSERSrO   r   r   r   schemerk  ri  hostnamer&  r9   r   r=  rA  )urlr   namer@   parserr2   r2   r3   	parse_url  sR    


r  c                   @   s   e Zd ZdZedd ZedfddZdd Zd	d
 Z	dd Z
dd Zdd Zdd Zdd Zdd ZdddZdddddZdS )ConnectionPoola  
    Create a connection pool. ``If max_connections`` is set, then this
    object raises :py:class:`~redis.exceptions.ConnectionError` when the pool's
    limit is reached.

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

    Any additional keyword arguments are passed to the constructor of
    ``connection_class``.
    c                 K   s0   t |}d|kr|d |d< || | 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.
        rw  )r  update)rP   r  r   Zurl_optionsr2   r2   r3   from_url  s
    )
zConnectionPool.from_urlNc                 K   sJ   |pd}t |tr|dk r"td|| _|| _|| _t | _| 	  d S )Nl        r   z,"max_connections" must be a positive integer)
r5   r9   rz  rw  connection_kwargsru  	threadingLock
_fork_lockreset)r1   rw  ru  r  r2   r2   r3   r4   M  s    

zConnectionPool.__init__c                 C   s$   t | j dt| jf | j dS )Nr   r   )r>   r?   r;   rw  r  r   r2   r2   r3   r   c  s    "zConnectionPool.__repr__c                 C   s,   t  | _d| _g | _t | _t | _	d S )Nr   )
r  r  _lock_created_connections_available_connectionsset_in_use_connectionsr   r   r   r   r2   r2   r3   r  i  s
    
zConnectionPool.resetc                 C   sP   | j t krL| jjdd}|s$tz| j t kr<|   W 5 | j  X d S )N   )ri   )r   r   r   r  acquirer   releaser  )r1   Zacquiredr2   r2   r3   	_checkpidz  s    #zConnectionPool._checkpidc              	   O   s   |    | j> z| j }W n tk
r:   |  }Y nX | j| W 5 Q R X zZ|  z|	 rnt
dW n8 t
tfk
r   |  |  |	 rt
dY nX W n  tk
r   | |  Y nX |S )zGet a connection from the poolConnection has dataConnection not ready)r  r  r  pop
IndexErrormake_connectionr  addr  r   r   r  r   r   r  r1   command_namekeysoptionsr   r2   r2   r3   get_connection  s*    
zConnectionPool.get_connectionc                 C   s,   | j }t|dd|dd|dddS )z,Return an encoder based on encoding settingsr.   r   r/   r   r0   Fr-   )r  r+   rO   )r1   r   r2   r2   r3   get_encoder  s    


zConnectionPool.get_encoderc                 C   s0   | j | jkrtd|  j d7  _ | jf | jS )zCreate a new connectionzToo many connectionsrJ   )r  ru  r   rw  r  r   r2   r2   r3   r    s    zConnectionPool.make_connectionc              	   C   s   |    | jh z| j| W n tk
r4   Y nX | |rN| j| n$|  jd8  _|	  W 5 Q R  dS W 5 Q R X dS )z(Releases the connection back to the poolrJ   N)
r  r  r  removeKeyErrorowns_connectionr  r   r  r   r   r2   r2   r3   r    s    
zConnectionPool.releasec                 C   s   |j | j kS r,   )r   r   r2   r2   r3   r    s    zConnectionPool.owns_connectionTc              	   C   sJ   |    | j2 |r$t| j| j}n| j}|D ]}|  q.W 5 Q R X dS )z
        Disconnects connections in the pool

        If ``inuse_connections`` is True, disconnect connections that are
        current in use, potentially by other threads. Otherwise only disconnect
        connections that are idle in the pool.
        N)r  r  r   r  r  r   )r1   Zinuse_connectionsconnectionsr   r2   r2   r3   r     s     zConnectionPool.disconnectr!   )r   rb   c                 C   s8   | j d|i | jD ]
}||_q| jD ]
}||_q(d S )Nr   )r  r  r  r   r  )r1   r   connr2   r2   r3   	set_retry  s
    

zConnectionPool.set_retry)T)r?   rE   rF   rG   rX   r  r"  r4   r   r  r  r  r  r  r  r  r   r  r2   r2   r2   r3   r    s    
1 
/!	
r  c                       sR   e Zd ZdZddeef fdd	Zdd Zdd	 Zd
d Z	dd Z
dd Z  ZS )BlockingConnectionPoola  
    Thread-safe blocking connection pool::

        >>> from redis.client import Redis
        >>> client = Redis(connection_pool=BlockingConnectionPool())

    It performs the same function as the default
    :py:class:`~redis.ConnectionPool` implementation, in that,
    it maintains a pool of reusable connections that can be shared by
    multiple redis clients (safely across threads if required).

    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.ConnectionPool` implementation does), it
    makes the client wait ("blocks") 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      c                    s(   || _ || _t jf ||d| d S )N)rw  ru  )queue_classri   r*  r4   )r1   ru  ri   rw  r  r  r+  r2   r3   r4   0  s    	zBlockingConnectionPool.__init__c                 C   sN   |  | j| _z| jd  W q tk
r6   Y q:Y qX qg | _t | _d S r,   )	r  ru  pool
put_nowaitr   _connectionsr   r   r   r   r2   r2   r3   r  A  s    zBlockingConnectionPool.resetc                 C   s   | j f | j}| j| |S )zMake a fresh connection.)rw  r  r  r   r   r2   r2   r3   r  Y  s    z&BlockingConnectionPool.make_connectionc              	   O   s   |    d}z| jjd| jd}W n tk
r>   tdY nX |dkrP|  }zZ|  z| rltdW n8 tt	fk
r   |
  |  | rtdY nX W n  tk
r   | |  Y nX |S )a7  
        Get a connection, blocking for ``self.timeout`` until a connection
        is available from the pool.

        If the connection returned is ``None`` then creates a new connection.
        Because we use a last-in first-out queue, the existing connections
        (having been returned to the pool after the initial ``None`` values
        were added) will be returned before ``None`` values. This means we only
        create new connections when we need to, i.e.: the actual number of
        connections will only increase in response to demand.
        NT)blockri   zNo connection available.r  r  )r  r  rO   ri   r   r   r  r  r   r  r   r   r  r  r2   r2   r3   r  _  s,    
z%BlockingConnectionPool.get_connectionc                 C   sT   |    | |s*|  | jd dS z| j| W n tk
rN   Y nX dS )z)Releases the connection back to the pool.N)r  r  r   r  r  r   r   r2   r2   r3   r    s    
zBlockingConnectionPool.releasec                 C   s    |    | jD ]}|  qdS )z(Disconnects all connections in the pool.N)r  r  r   r   r2   r2   r3   r     s    
z!BlockingConnectionPool.disconnect)r?   rE   rF   rG   r"  r   r4   r  r  r  r  r   r@  r2   r2   r+  r3   r    s   #4r  )fr   ru   r^   r   rZ   r   r  r   abcr   r   	itertoolsr   queuer   r   r   r   typingr	   r
   urllib.parser   r   r   Zredis.backoffr   Zredis.credentialsr   r   Zredis.exceptionsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    Zredis.retryr!   Zredis.utilsr"   r#   r$   r%   rH  rE  ImportErrorBlockingIOErrorEWOULDBLOCKrs   hasattrr&   SSLWantWriteErrorSSLErrorr   r  rr   r   r   r   r   r   rp   r   rm   rS   rU   rV   rT   rW   r+   rH   rY   r   r   __annotations__r   r   r   r   r"  rA  ri  rs  rt  r9   r:   r   r|  r  r  r  r2   r2   r2   r3   <module>   s    H





)* 	]m3  c[ '	9  