U
    d                  
   @   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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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#m$Z$m%Z% d d	l&m'Z' d d
l(m)Z)m*Z*m+Z+ zd dl,Z,dZ-W n e.k
r   dZ-Y nX e/ej0iZ1e-r\e2e,drRde1e,j3< de1e,j4< n
de1e,j5< e6e17 Z8e*rd dl9Z9ee9j:Z;e;edkZ<e;edkZ=e;edkZ>dZ?e=sdZ?dZ@dZAdZBdZCdZDeE ZFdZGdZHdZIdZJG dd dZKG dd dZLG dd  d ZMG d!d" d"eLZNG d#d$ d$eLZOe*r2eOZPneNZPG d%d& d&ZQG d'd( d(eQZRG d)d* d*eQZSd+ZTd,d- ZUeVeWeWeUeUeXeVeVeUd.	ZYd/d0 ZZG d1d2 d2Z[G d3d4 d4e[Z\dS )5    N)chain)EmptyFull	LifoQueue)time)parse_qsunquoteurlparse)Version)	NoBackoff)AuthenticationError$AuthenticationWrongNumberOfArgsErrorBusyLoadingErrorChildDeadlockedErrorConnectionError	DataErrorExecAbortErrorInvalidResponseModuleErrorNoPermissionErrorNoScriptErrorReadOnlyError
RedisErrorResponseErrorTimeoutError)Retry)CRYPTOGRAPHY_AVAILABLEHIREDIS_AVAILABLEstr_if_bytesTFSSLWantReadError   z0.1.3z0.1.4z1.0.0   *   $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 unloadc                   @   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(   r)    r+   4/tmp/pip-unpacked-wheel-f5h5_hbx/redis/connection.py__init__X   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(   )r*   valuetypenamer+   r+   r,   r5   ]   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)r)   r.   r0   tobytesr/   decoder'   r(   )r*   r9   forcer+   r+   r,   r<   t   s    


zEncoder.decodeN)F)r8   
__module____qualname____doc__r-   r5   r<   r+   r+   r+   r,   r$   U   s   r$   c                   @   sL   e Zd Zdededededeeeeee	ee
ei	eeeeeedZdd Zd	S )

BaseParserzmax number of clients reachedz(Client sent AUTH, but no password is setzinvalid passwordz,wrong number of arguments for 'auth' commandz,wrong number of arguments for 'AUTH' command)ZERRZ	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lenr.   dictgetr   )r*   responseZ
error_codeZexception_classr+   r+   r,   parse_error   s    


zBaseParser.parse_errorN)r8   r>   r?   r   r   r   MODULE_LOAD_ERRORr   MODULE_EXPORTS_DATA_TYPES_ERRORNO_SUCH_MODULE_ERROR MODULE_UNLOAD_NOT_POSSIBLE_ERRORr   r   r   r   r   rE   rJ   r+   r+   r+   r,   rA   ~   s6          rA   c                   @   sX   e Zd Zdd Zedd ZdedfddZd	d
 Zdd Z	dd Z
dd Zdd ZdS )SocketBufferc                 C   s,   || _ || _|| _t | _d| _d| _d S Nr   )_socksocket_read_sizesocket_timeoutioBytesIO_bufferbytes_written
bytes_read)r*   socketrR   rS   r+   r+   r,   r-      s    
zSocketBuffer.__init__c                 C   s   | j | j S r%   )rW   rX   r*   r+   r+   r,   length   s    zSocketBuffer.lengthNTc              
   C   sP  | j }| j}| j}|| j d}|tk	}z
z||r>|| | j |}	t	|	t
rht|	dkrhtt||	 t|	}
|  j|
7  _||
7 }|d k	r||krq>W W dS  tjk
r   |rtdY W jdS  tk
r2 } zBt|jd}|s|j|krW Y W *dS td|j W 5 d }~X Y nX W 5 |rJ|| j X d S Nr   TzTimeout reading from socketFz!Error while reading from socket: )rQ   rR   rV   seekrW   SENTINEL
settimeoutrS   recvr.   r/   rF   r   SERVER_CLOSED_CONNECTION_ERRORwriterY   timeoutr   NONBLOCKING_EXCEPTIONS#NONBLOCKING_EXCEPTION_ERROR_NUMBERSrH   	__class__errnoargs)r*   r[   rd   raise_on_timeoutsockrR   bufmarkercustom_timeoutdataZdata_lengthexallowedr+   r+   r,   _read_from_socket   s<    



&zSocketBuffer._read_from_socketc                 C   s   t | jp| j|ddS )NFrd   rj   )r1   r[   rr   r*   rd   r+   r+   r,   can_read   s     zSocketBuffer.can_readc                 C   sn   |d }|| j kr"| || j   | j| j | j|}|  jt|7  _| j| jkrb|   |d d S )Nr    )	r[   rr   rV   r^   rX   readrF   rW   purge)r*   r[   ro   r+   r+   r,   rw      s    
zSocketBuffer.readc                 C   st   | j }|| j | }|tsB|   || j | }q|  jt|7  _| j| jkrh| 	  |d d S )Nrv   )
rV   r^   rX   readlineendswithSYM_CRLFrr   rF   rW   rx   )r*   rl   ro   r+   r+   r,   ry      s    

zSocketBuffer.readlinec                 C   s&   | j d | j   d| _d| _d S rP   )rV   r^   truncaterW   rX   rZ   r+   r+   r,   rx     s    
zSocketBuffer.purgec                 C   s<   z|    | j  W n tk
r*   Y nX d | _d | _d S r%   )rx   rV   close	ExceptionrQ   rZ   r+   r+   r,   r}     s    zSocketBuffer.close)r8   r>   r?   r-   propertyr[   r_   rr   ru   rw   ry   rx   r}   r+   r+   r+   r,   rO      s   

)rO   c                   @   sB   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S )PythonParserzPlain Python parsing classc                 C   s   || _ d | _d | _d | _d S r%   )rR   encoderrQ   rV   r*   rR   r+   r+   r,   r-     s    zPythonParser.__init__c                 C   s&   z|    W n tk
r    Y nX d S r%   on_disconnectr~   rZ   r+   r+   r,   __del__$  s    zPythonParser.__del__c                 C   s(   |j | _ t| j | j|j| _|j| _dS )zCalled when the socket connectsN)rQ   rO   rR   rS   rV   r   r*   
connectionr+   r+   r,   
on_connect*  s      zPythonParser.on_connectc                 C   s*   d| _ | jdk	r | j  d| _d| _dS )z"Called when the socket disconnectsN)rQ   rV   r}   r   rZ   r+   r+   r,   r   2  s
    

zPythonParser.on_disconnectc                 C   s   | j o| j |S r%   )rV   ru   rt   r+   r+   r,   ru   :  s    zPythonParser.can_readFc                    s  j  }|stt|d d |dd   }}|dkrFtd||dkrx|jddd}|}t|trt||S |dkrnp|d	krt|}n^|d
krt|}|dkrd S j 	|}n4|dkrt|}|dkrd S  fddt
|D }t|tr dkrj|}|S )NrC   )   -   +   :r"   r!   zProtocol Error: r   utf-8replace)errorsr   r   r"   r]   r!   c                    s   g | ]}j  d qS )disable_decoding)read_response).0ir   r*   r+   r,   
<listcomp>e  s   z.PythonParser.read_response.<locals>.<listcomp>F)rV   ry   r   rb   r   r<   rJ   r.   r2   rw   ranger/   r   )r*   r   rawbyterI   errorr[   r+   r   r,   r   =  s>    



zPythonParser.read_responseN)F)
r8   r>   r?   r@   r-   r   r   r   ru   r   r+   r+   r+   r,   r     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r t|| _d S )NzHiredis is not installed)r   r   rR   HIREDIS_USE_BYTE_BUFFER	bytearrayrV   r   r+   r+   r,   r-   q  s
    zHiredisParser.__init__c                 C   s&   z|    W n tk
r    Y nX d S r%   r   rZ   r+   r+   r,   r   y  s    zHiredisParser.__del__c                 K   sd   |j | _ |j| _t| jd}ts(t|d< |jjr<|jj	|d< t
rL|jj|d< tjf || _d| _d S )N)ZprotocolError
replyErrorr   r'   r   F)rQ   rS   _socket_timeoutr   rJ    HIREDIS_SUPPORTS_CALLABLE_ERRORSr   r   r)   r'    HIREDIS_SUPPORTS_ENCODING_ERRORSr(   hiredisReader_reader_next_response)r*   r   kwargsr+   r+   r,   r     s    zHiredisParser.on_connectc                 C   s   d | _ d | _d| _d S )NF)rQ   r   r   rZ   r+   r+   r,   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 )NFrs   T)r   r   rb   r   getsread_from_socketrt   r+   r+   r,   ru     s    

zHiredisParser.can_readTc           	   
   C   s>  | j }|tk	}zz|r"|| trX| j | j}|dkrDtt| j	
| jd| n8| j | j}t|tr|t|dkrtt| j	
| W 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 |r8|| j X d S r\   )rQ   r_   r`   r   r   	recv_intorV   r   rb   r   feedra   rR   r.   r/   rF   rY   rd   r   re   rf   rH   rg   rh   ri   )	r*   rd   rj   rk   rn   Zbufflenbufferrp   rq   r+   r+   r,   r     s4    


&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st|tr| 	|j
d }n4t|tr|rt|d tr| 	|d j
d |d< t|tr|n$t|tr|rt|d tr|d |S )NFr   )r   r   rb   r   r   r   r   r.   r   rJ   ri   list)r*   r   rI   r+   r+   r,   r     sD    



zHiredisParser.read_responseN)F)r8   r>   r?   r@   r-   r   r   r   ru   r_   r   r   r+   r+   r+   r,   r   n  s   
%r   c                   @   s   e Zd ZdZddddddddddeddded	dddd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 Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd5d)d*Zd+d, Zd6d-d.Zd7d/d0Zd1d2 Zd3d4 ZdS )8
Connectionz4Manages TCP communication to and from a Redis server	localhosti  r   NFr   strict   c                 C   s  t  | _|| _t|| _|| _|| _|| _|| _	|| _
|p>|| _|| _|pNi | _|	| _|
| _|tkrjg }|
rx|t || _|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`.
        NrC   r   p  )$osgetpidpidhostr2   portdbusernameclient_namepasswordrS   socket_connect_timeoutsocket_keepalivesocket_keepalive_optionssocket_typeretry_on_timeoutr_   appendr   retry_on_errorr   r   retrycopydeepcopyupdate_supported_errorshealth_check_intervalnext_health_checkredis_connect_funcr$   r   rQ   _socket_read_size
set_parser_connect_callbacks_buffer_cutoff)r*   r   r   r   r   rS   r   r   r   r   r   r   r'   r(   r)   parser_classrR   r   r   r   r   r   r+   r+   r,   r-     sB    





zConnection.__init__c                 C   s,   d dd |  D }| jj d| dS )N,c                 S   s   g | ]\}}| d | qS )=r+   )r   kvr+   r+   r,   r   A  s     z'Connection.__repr__.<locals>.<listcomp><>)joinrepr_piecesrg   r8   )r*   Z	repr_argsr+   r+   r,   __repr__@  s    zConnection.__repr__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   r*   piecesr+   r+   r,   r   D  s    zConnection.repr_piecesc                 C   s&   z|    W n tk
r    Y nX d S r%   )
disconnectr~   rZ   r+   r+   r,   r   J  s    zConnection.__del__c                 C   s   | j t| d S r%   )r   r   weakref
WeakMethod)r*   callbackr+   r+   r,   register_connect_callbackP  s    z$Connection.register_connect_callbackc                 C   s
   g | _ d S r%   )r   rZ   r+   r+   r,   clear_connect_callbacksS  s    z"Connection.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
        )rR   N)r   _parser)r*   r   r+   r+   r,   r   V  s    zConnection.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%   )_connectr+   rZ   r+   r,   <lambda>d  r#   z$Connection.connect.<locals>.<lambda>c                    s
     | S r%   r   )r   rZ   r+   r,   r   d  r#   zTimeout connecting to server)rQ   r   call_with_retryrY   rd   r   OSErrorr   _error_messager   r   r   r   r   )r*   rk   erefr   r+   rZ   r,   connect^  s.    
 
 


zConnection.connectc                 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 connectionNrC   z)socket.getaddrinfo returned an empty list)rY   getaddrinfor   r   r   SOCK_STREAM
setsockoptIPPROTO_TCPTCP_NODELAYr   
SOL_SOCKETSO_KEEPALIVEr   itemsr`   r   r   rS   r   r}   )r*   errresfamilysocktypeproto	canonnameZsocket_addressrk   r   r   _r+   r+   r,   r     s6       


zConnection._connectc              	   C   s   t |jdkrZz$d| j d| j d|jd  dW S  tk
rV   d|jd   Y S X nVz0d|jd  d	| j d| j d
|jd  d	W S  tk
r   d|jd   Y S X d S )NrC   zError connecting to :z.                         r   .zConnection Error: Error z connecting to . )rF   ri   r   r   AttributeErrorr*   	exceptionr+   r+   r,   r     s    
,zConnection._error_messagec                 C   s   | j |  | js| jr| jr0| j| jp*df}n| jf}| jd|ddi z|  }W n. tk
r   | jd| j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_healthFr   OKzInvalid Username or PasswordZCLIENTZSETNAMEzError setting client nameZSELECTzInvalid DatabaseN)r   )r   r   r   r   send_commandr   r   r   r   r   r   r   )r*   Z	auth_argsZauth_responser+   r+   r,   r     s*    zConnection.on_connectc                 G   s|   | j   | jdkrdS t | jkrNz| jtj W n t	k
rL   Y nX z| j
  W n t	k
rp   Y nX d| _dS )z!Disconnects from the Redis serverN)r   r   rQ   r   r   r   shutdownrY   	SHUT_RDWRr   r}   )r*   ri   r+   r+   r,   r     s    

zConnection.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   rZ   r+   r+   r,   
_send_ping  s    zConnection._send_pingc                 C   s   |    dS )z Function to call when PING failsNr   )r*   r   r+   r+   r,   _ping_failed  s    zConnection._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  rZ   r+   r+   r,   r     s    zConnection.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 socketrC   UNKNOWNr   r   z while writing to socket. r   N)rQ   r   r   r.   r6   sendallrY   rd   r   r   r   rF   ri   r   BaseException)r*   commandr   itemr   rh   errmsgr+   r+   r,   send_packed_command  s,    


&zConnection.send_packed_commandc                 O   s    | j | j| |ddd dS )z+Pack and send a command to the Redis serverr   Tr  N)r  pack_commandrH   )r*   ri   r   r+   r+   r,   r    s     
zConnection.send_commandc              
   C   sp   | j }|s|   z| j|W S  tk
rj } z,|   td| j d| j 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 r   z: N)
rQ   r   r   ru   r   r   r   r   r   ri   )r*   rd   rk   r   r+   r+   r,   ru   #  s    zConnection.can_readc              
   C   s   z| j  d| j }W n tk
r.   d}Y nX z| jj|d}W n tjk
rn   |   td| Y n\ t	k
r } z"|   t
d| d|j W 5 d}~X Y n tk
r   |    Y nX | jrt | j | _t|tr||S )z0Read the response from a previously sent commandr   r   r   zTimeout reading from r  z : N)r   r   r   r   r   rY   rd   r   r   r   r   ri   r
  r   r   r   r.   r   )r*   r   ZhosterrrI   r   r+   r+   r,   r   0  s(    
&
zConnection.read_responsec              	   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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   rC   N    )r.   r6   tupler5   rD   	SYM_EMPTYr   SYM_STARrF   r{   r   mapr   r0   
SYM_DOLLARr   )r*   ri   outputZbuffbuffer_cutoffargZ
arg_lengthr+   r+   r,   r  J  s@    "





zConnection.pack_commandc           	      C   s   g }g }d}| j }|D ]~}| j| D ]n}t|}||ksJ||ksJt|trb|t| d}g }||kstt|tr|| q$|| ||7 }q$q|r|t| |S )z.Pack multiple commands into the Redis protocolr   )r   r  rF   r.   r0   r   r  r   )	r*   commandsr  r   Zbuffer_lengthr  cmdchunkZchunklenr+   r+   r,   pack_commandsw  s.    
zConnection.pack_commands)T)r   )F)r8   r>   r?   r@   r_   DefaultParserr-   r   r   r   r   r   r   r   r   r   r   r   r  r  r   r  r  ru   r   r  r  r+   r+   r+   r,   r     sV   
F!)'


-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t jf | || _|| _|dkr6tj}n:t|t	rptjtj
tjd}||krhtd| || }|| _|| _|| _|| _|| _|| _|	| _|
| _|| _|| _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optionalr   z+Invalid SSL Certificate Requirements Flag: )ssl_availabler   superr-   keyfilecertfilessl	CERT_NONEr.   r6   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_cert)r*   Zssl_keyfileZssl_certfileZssl_cert_reqsZssl_ca_certsZssl_ca_datassl_check_hostnameZssl_ca_pathZssl_passwordr1  r2  r3  r4  r   Z	CERT_REQSrg   r+   r,   r-     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)r&  r%  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   rC   )ocsp_staple_verifier)OCSPVerifierzocsp validation error)*r$  r   r'  create_default_contextr/  r+  verify_moder&  r%  load_cert_chainr0  r,  r.  r-  load_verify_locationswrap_socketr   r1  r   r   r2  OpenSSLZocspr;  r3  ZSSLContextZSSLv23_METHODZuse_certificate_fileZuse_privatekey_fileZset_ocsp_client_callbackr4  r   rY   Zrequest_ocspr   r   do_handshaker  r<  Zis_validr   )
r*   rk   contextsslsockrB  r;  Z
staple_ctxconr<  or6  r+   r,   r     sj    
   
zSSLConnection._connect)NNr   NNFNNFFNN)r8   r>   r?   r@   r-   r   __classcell__r+   r+   r6  r,   r    s               Cr  c                   @   sN   e Zd Zdddddddddeedddddfdd	Zd
d Zdd Zdd ZdS )UnixDomainSocketConnectionr   r   Nr   r   Fr   c                 C   s   t  | _|| _|| _|| _|| _|| _|| _|	| _	|
t
kr@g }
|	rN|
t |
| _| jr|dkrrtt d| _nt|| _| j|
 ntt d| _|| _d| _|| _t|||| _d| _|| _| | g | _d| _dS )aB  
        Initialize a new UnixDomainSocketConnection.
        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`.
        NrC   r   r   )r   r   r   pathr   r   r   r   rS   r   r_   r   r   r   r   r   r   r   r   r   r   r   r   r$   r   rQ   r   r   r   r   )r*   rK  r   r   r   rS   r'   r(   r)   r   r   r   rR   r   r   r   r   r+   r+   r,   r-   #  s8    


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   r+   r+   r,   r   _  s    z&UnixDomainSocketConnection.repr_piecesc                 C   s,   t  t jt j}|| j || j |S )z&Create a Unix domain socket connection)rY   AF_UNIXr   r`   rS   r   rK  )r*   rk   r+   r+   r,   r   e  s    z#UnixDomainSocketConnection._connectc                 C   sR   t |jdkr(d| j d|jd  dS d|jd  d| j d|jd  dS d S )NrC   z!Error connecting to unix socket: r   r   r   r   z connecting to unix socket: )rF   ri   rK  r   r+   r+   r,   r   l  s    $z)UnixDomainSocketConnection._error_message)	r8   r>   r?   r_   r  r-   r   r   r   r+   r+   r+   r,   rJ  "  s(   
<rJ  )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 )Nr   F)r.   r6   upperFALSE_STRINGSr1   )r9   r+   r+   r,   to_bool{  s
    rT  )	r   rS   r   r   r   r   max_connectionsr   r5  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t	d|S )Nr   zInvalid value for `z` in connection URL.r   r   unixrK  connection_class)Zredisredissr   r   r   /r   rX  zRRedis URL must specify one of the following schemes (redis://, rediss://, unix://))r	   r   queryr   rF   r   URL_QUERY_ARGUMENT_PARSERSrH   	TypeError
ValueErrorr   r   schemerK  rJ  hostnamer   r2   r   r   r  )urlr   namer9   parserr+   r+   r,   	parse_url  sH    




rc  c                   @   st   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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]:[password]]@/path/to/socket.sock?db=0

        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  )rc  update)clsr`  r   Zurl_optionsr+   r+   r,   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)
r.   r2   r]  rW  connection_kwargsrU  	threadingLock
_fork_lockreset)r*   rW  rU  rh  r+   r+   r,   r-     s    

zConnectionPool.__init__c                 C   s$   t | j dt| jf | j dS )Nr   r   )r7   r8   r4   rW  rh  rZ   r+   r+   r,   r     s    "zConnectionPool.__repr__c                 C   s,   t  | _d| _g | _t | _t | _	d S rP   )
ri  rj  _lock_created_connections_available_connectionsset_in_use_connectionsr   r   r   rZ   r+   r+   r,   rl    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   )rd   )r   r   r   rk  acquirer   releaserl  )r*   Zacquiredr+   r+   r,   	_checkpid0  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)ru  rm  ro  pop
IndexErrormake_connectionrq  addr   ru   r   r   r   r
  rt  r*   command_namekeysoptionsr   r+   r+   r,   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   r)   Fr&   )rh  r$   rH   )r*   r   r+   r+   r,   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 connectionsrC   )rn  rU  r   rW  rh  rZ   r+   r+   r,   rz    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 poolrC   N)
ru  rm  rq  removeKeyErrorowns_connectionro  r   rn  r   r   r+   r+   r,   rt    s    
zConnectionPool.releasec                 C   s   |j | j kS r%   )r   r   r+   r+   r,   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)ru  rm  r   ro  rq  r   )r*   Zinuse_connectionsconnectionsr   r+   r+   r,   r     s     zConnectionPool.disconnect)T)r8   r>   r?   r@   classmethodrg  r   r-   r   rl  ru  r  r  rz  rt  r  r   r+   r+   r+   r,   rd    s   
1 
/!	rd  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_classrd   r$  r-   )r*   rU  rd   rW  r  rh  r6  r+   r,   r-     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   rZ   r+   r+   r,   rl    s    zBlockingConnectionPool.resetc                 C   s   | j f | j}| j| |S )zMake a fresh connection.)rW  rh  r  r   r   r+   r+   r,   rz    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)blockrd   zNo connection available.rv  rw  )ru  r  rH   rd   r   r   rz  r   ru   r   r   r
  rt  r|  r+   r+   r,   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)ru  r  r   r  r  r   r   r+   r+   r,   rt  B  s    
zBlockingConnectionPool.releasec                 C   s    |    | jD ]}|  qdS )z(Disconnects all connections in the pool.N)ru  r  r   r   r+   r+   r,   r   W  s    
z!BlockingConnectionPool.disconnect)r8   r>   r?   r@   r   r   r-   rl  rz  r  rt  r   rI  r+   r+   r6  r,   r    s   #4r  )]r   rh   rT   r   rY   ri  r   	itertoolsr   queuer   r   r   r   urllib.parser   r   r	   Zpackaging.versionr
   Zredis.backoffr   Zredis.exceptionsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   Zredis.retryr   Zredis.utilsr   r   r   r'  r#  ImportErrorBlockingIOErrorEWOULDBLOCKrf   hasattrr   SSLWantWriteErrorSSLErrorr  r~  re   r   __version__Zhiredis_versionr   ZHIREDIS_SUPPORTS_BYTE_BUFFERr   r   r  r  r{   r  rb   objectr_   rK   rM   rN   rL   r$   rA   rO   r   r   r  r   r  rJ  rS  rT  r2   r3   r   r[  rc  rd  r  r+   r+   r+   r,   <module>   s   D




)'vS    ! V	4 z