U
    ³.¬bl9  ã                   @   s   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m	Z	m
Z
 e e¡Zdeee
e	giZdd„ Zdd„ Zd%d	d
„Zd&dd„Zd'dd„Zdd„ Zdd„ Zdd„ ZG dd„ dƒZG dd„ dƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZG dd „ d eƒZG d!d"„ d"eƒZG d#d$„ d$eƒZdS )(é    N)Úcrc32)ÚChecksumErrorÚConnectionClosedErrorÚConnectionErrorÚEndpointConnectionErrorÚReadTimeoutErrorZGENERAL_CONNECTION_ERRORc                 C   s<   | dkrt   ¡ } n| dkr(td| › �ƒ‚| ||d   }|S )a1  Calculate time to sleep based on exponential function.

    The format is::

        base * growth_factor ^ (attempts - 1)

    If ``base`` is set to 'rand' then a random number between
    0 and 1 will be used as the base.
    Base must be greater than 0, otherwise a ValueError will be
    raised.

    Zrandr   z.The 'base' param must be greater than 0, got: é   )ÚrandomÚ
ValueError)ÚbaseÚgrowth_factorÚattemptsZtime_to_sleep© r   ú9/tmp/pip-unpacked-wheel-7df6wvge/botocore/retryhandler.pyÚdelay_exponential+   s    
ÿr   c                 C   s   t jt| |d�S )z§Create an exponential delay function based on the attempts.

    This is used so that you only have to pass it the attempts
    parameter to calculate the delay.

    ©r   r   )Ú	functoolsÚpartialr   r   r   r   r   Ú!create_exponential_delay_functionB   s
      ÿr   c                 C   s$   t | |d�}t| |d�}t||d�S )N)Úoperation_name)ÚcheckerÚaction)Ú create_checker_from_retry_configÚcreate_retry_action_from_configÚRetryHandler)Úconfigr   r   r   r   r   r   Úcreate_retry_handlerN   s     ÿ ÿr   c                 C   s0   | d d }|d dkr,t |d |d d�S d S )NÚ__default__ÚdelayÚtypeZexponentialr   r   r   )r   )r   r   Zdelay_configr   r   r   r   X   s    þr   c                 C   s   g }d }g }d| krj| d   dg ¡}| d d }|D ]4}|| }| t|ƒ¡ t|ƒ}|d k	r4| |¡ q4|d k	rÆ|   |¡d k	rÆ| | d }	|	D ]4}| t|	| ƒ¡ t|	| ƒ}|d k	r�| |¡ q�t|ƒdkrât|d |d�S t|ƒ}
t|
|t|ƒd�S d S )Nr   ÚpoliciesÚmax_attemptsr   r   )r!   )r!   Úretryable_exceptions)	ÚgetÚappendÚ_create_single_checkerÚ_extract_retryable_exceptionÚextendÚlenÚMaxAttemptsDecoratorÚMultiCheckerÚtuple)r   r   Úcheckersr!   r"   r    ÚkeyZcurrent_configZretry_exceptionZoperation_policiesZmulti_checkerr   r   r   r   e   s:    ÿýr   c                 C   s2   d| d krt | d d ƒS d| d kr.tƒ S d S )NÚresponseÚapplies_whenÚsocket_errors)Ú_create_single_response_checkerÚExceptionRaiser)r   r   r   r   r%   ‡   s    
ÿr%   c                 C   sZ   d| krt | d | d d�}n8d| kr6t| d d�}n d| krNt| d d�}ntdƒ‚|S )NZservice_error_codeZhttp_status_code)Ústatus_codeÚ
error_code)r3   Ú	crc32body)ÚheaderzUnknown retry policy)ÚServiceErrorCodeCheckerÚHTTPStatusCodeCheckerÚCRC32Checkerr
   )r.   r   r   r   r   r1   �   s    þÿr1   c                 C   sN   | d }d|  di ¡krtgS d|krJg }|d D ]}| t| ¡ q2|S d S )Nr/   r5   r.   r0   )r#   r   r'   ÚEXCEPTION_MAP)r   r/   Ú
exceptionsÚnamer   r   r   r&   ¢   s    r&   c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )r   a¯  Retry handler.

    The retry handler takes two params, ``checker`` object
    and an ``action`` object.

    The ``checker`` object must be a callable object and based on a response
    and an attempt number, determines whether or not sufficient criteria for
    a retry has been met.  If this is the case then the ``action`` object
    (which also is a callable) determines what needs to happen in the event
    of a retry.

    c                 C   s   || _ || _d S ©N)Ú_checkerÚ_action)Úselfr   r   r   r   r   Ú__init__»   s    zRetryHandler.__init__c                 K   sn   |||dœ}t | jtƒr8|d d  d¡}| d|i¡ | jf |Žr`| j|d�}t d|¡ |S t d¡ d	S )
z›Handler for a retry.

        Intended to be hooked up to an event handler (hence the **kwargs),
        this will process retries appropriately.

        )Úattempt_numberr.   Úcaught_exceptionZrequest_dictÚcontextÚretriesÚretries_context)r   zRetry needed, action of: %szNo retry needed.N)Ú
isinstancer>   r)   r#   Úupdater?   ÚloggerÚdebug)r@   r   r.   rC   ÚkwargsZchecker_kwargsrF   Úresultr   r   r   Ú__call__¿   s    ýzRetryHandler.__call__N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__rA   rM   r   r   r   r   r   ­   s   r   c                   @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	ÚBaseCheckerz Base class for retry checkers.

    Each class is responsible for checking a single criteria that determines
    whether or not a retry should not happen.

    c                 C   s4   |dk	r|   ||¡S |dk	r(|  ||¡S tdƒ‚dS )aÄ  Determine if retry criteria matches.

        Note that either ``response`` is not None and ``caught_exception`` is
        None or ``response`` is None and ``caught_exception`` is not None.

        :type attempt_number: int
        :param attempt_number: The total number of times we've attempted
            to send the request.

        :param response: The HTTP response (if one was received).

        :type caught_exception: Exception
        :param caught_exception: Any exception that was caught while trying to
            send the HTTP response.

        :return: True, if the retry criteria matches (and therefore a retry
            should occur.  False if the criteria does not match.

        Nz,Both response and caught_exception are None.)Ú_check_responseÚ_check_caught_exceptionr
   )r@   rB   r.   rC   r   r   r   rM   Þ   s     ÿzBaseChecker.__call__c                 C   s   d S r=   r   ©r@   rB   r.   r   r   r   rS   ý   s    zBaseChecker._check_responsec                 C   s   d S r=   r   ©r@   rB   rC   r   r   r   rT      s    z#BaseChecker._check_caught_exceptionN)rN   rO   rP   rQ   rM   rS   rT   r   r   r   r   rR   Ö   s   rR   c                   @   s*   e Zd ZdZd	dd„Zdd„ Zdd„ ZdS )
r)   a“  Allow retries up to a maximum number of attempts.

    This will pass through calls to the decorated retry checker, provided
    that the number of attempts does not exceed max_attempts.  It will
    also catch any retryable_exceptions passed in.  Once max_attempts has
    been exceeded, then False will be returned or the retryable_exceptions
    that was previously being caught will be raised.

    Nc                 C   s   || _ || _|| _d S r=   )r>   Ú_max_attemptsÚ_retryable_exceptions)r@   r   r!   r"   r   r   r   rA     s    zMaxAttemptsDecorator.__init__c                 C   sz   |rt | dd¡| jƒ|d< |  |||¡}|rr|| jkrl|d k	r\d|d kr\d|d d d< t d|¡ dS |S ndS d S )	NÚmaxr   ZResponseMetadatar   TZMaxAttemptsReachedz0Reached the maximum number of retry attempts: %sF)rY   r#   rW   Ú_should_retryrI   rJ   )r@   rB   r.   rC   rF   Zshould_retryr   r   r   rM     s0    
 ÿ  ÿ
þ
ÿþzMaxAttemptsDecorator.__call__c              
   C   sp   | j r^|| jk r^z|  |||¡W S  | j k
rZ } ztjd|dd� W Y ¢dS d }~X Y qlX n|  |||¡S d S )Nz,retry needed, retryable exception caught: %sT)Úexc_info)rX   rW   r>   rI   rJ   )r@   rB   r.   rC   Úer   r   r   rZ   0  s      ÿýz"MaxAttemptsDecorator._should_retry)N)rN   rO   rP   rQ   rA   rM   rZ   r   r   r   r   r)     s   

r)   c                   @   s   e Zd Zdd„ Zdd„ ZdS )r8   c                 C   s
   || _ d S r=   )Ú_status_code)r@   r3   r   r   r   rA   D  s    zHTTPStatusCodeChecker.__init__c                 C   s*   |d j | jkr"t d| j¡ dS dS d S )Nr   z5retry needed: retryable HTTP status code received: %sTF)r3   r]   rI   rJ   rU   r   r   r   rS   G  s    þz%HTTPStatusCodeChecker._check_responseN©rN   rO   rP   rA   rS   r   r   r   r   r8   C  s   r8   c                   @   s   e Zd Zdd„ Zdd„ ZdS )r7   c                 C   s   || _ || _d S r=   )r]   Ú_error_code)r@   r3   r4   r   r   r   rA   S  s    z ServiceErrorCodeChecker.__init__c                 C   sJ   |d j | jkrF|d  di ¡ d¡}|| jkrFt d| j| j¡ dS dS )Nr   r   ÚErrorZCodez>retry needed: matching HTTP status and error code seen: %s, %sTF)r3   r]   r#   r_   rI   rJ   )r@   rB   r.   Zactual_error_coder   r   r   rS   W  s    
üz'ServiceErrorCodeChecker._check_responseNr^   r   r   r   r   r7   R  s   r7   c                   @   s   e Zd Zdd„ Zdd„ ZdS )r*   c                 C   s
   || _ d S r=   ©Z	_checkers)r@   r,   r   r   r   rA   f  s    zMultiChecker.__init__c                 C   s(   | j D ]}||||ƒ}|r|  S qdS )NFra   )r@   rB   r.   rC   r   Zchecker_responser   r   r   rM   i  s    
  ÿ
zMultiChecker.__call__N)rN   rO   rP   rA   rM   r   r   r   r   r*   e  s   r*   c                   @   s   e Zd Zdd„ Zdd„ ZdS )r9   c                 C   s
   || _ d S r=   )Ú_header_name)r@   r6   r   r   r   rA   t  s    zCRC32Checker.__init__c                 C   st   |d }|j  | j¡}|d kr.t d| j¡ nBt|d jƒd@ }|t|ƒkspt dt|ƒ|¡ tdt|ƒ|d�‚d S )Nr   z?crc32 check skipped, the %s header is not in the http response.l   ÿÿ z>retry needed: crc32 check failed, expected != actual: %s != %sr   )Zchecksum_typeZexpected_checksumZactual_checksum)	Úheadersr#   rb   rI   rJ   r   ÚcontentÚintr   )r@   rB   r.   Úhttp_responseZexpected_crcZactual_crc32r   r   r   rS   x  s&    ýüýzCRC32Checker._check_responseNr^   r   r   r   r   r9   s  s   r9   c                   @   s   e Zd ZdZdd„ ZdS )r2   z`Raise any caught exceptions.

    This class will raise any non None ``caught_exception``.

    c                 C   s   |‚d S r=   r   rV   r   r   r   rT   ˜  s    z'ExceptionRaiser._check_caught_exceptionN)rN   rO   rP   rQ   rT   r   r   r   r   r2   ‘  s   r2   )N)N)N)r   Úloggingr	   Úbinasciir   Zbotocore.exceptionsr   r   r   r   r   Ú	getLoggerrN   rI   r:   r   r   r   r   r   r%   r1   r&   r   rR   r)   r8   r7   r*   r9   r2   r   r   r   r   Ú<module>   s8   
üÿ




"	).?