U
    M8cl9                     @   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-ozje0y8b/botocore/retryhandler.pydelay_exponential+   s    
r   c                 C   s   t jt| |dS )zCreate 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|| qt|dkrt|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 )
zHandler 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 )	BaseCheckerzBase 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   




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