o
    rj@cl9                     @   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   9usr/lib/python3.10/site-packages/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| v r5| d  dg }| d d }|D ]}|| }|t| t|}|d ur4|| q|d urc|  |d urc| | d }	|	D ]}|t|	|  t|	| }|d urb|| qHt|dkrqt|d |dS t|}
t|
|t|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 v rt | d d S d| d v 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   s\   d| v rt | d | d d}|S d| v rt| d d}|S d| v r*t| d d}|S td)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 v rtgS d|v r%g }|d D ]	}|t|  q|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      || _ || _d S N)_checker_action)selfr   r   r   r   r   __init__      
zRetryHandler.__init__c                 K   sr   |||d}t | jtr|d d d}|d|i | jd
i |r2| 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.Nr   )
isinstancer?   r)   r#   updater@   loggerdebug)rA   r   r.   rE   kwargsZchecker_kwargsrH   resultr   r   r   __call__   s   zRetryHandler.__call__N)__name__
__module____qualname____doc__rB   rO   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   s0   |dur
|  ||S |dur| ||S td)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
   )rA   rD   r.   rE   r   r   r   rO      s   zBaseChecker.__call__c                 C      d S r>   r   rA   rD   r.   r   r   r   rU         zBaseChecker._check_responsec                 C   rW   r>   r   rA   rD   rE   r   r   r   rV      rY   z#BaseChecker._check_caught_exceptionN)rP   rQ   rR   rS   rO   rU   rV   r   r   r   r   rT      s
    rT   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)rA   r   r!   r"   r   r   r   rB     s   
zMaxAttemptsDecorator.__init__c                 C   st   |rt |dd| j|d< | |||}|r8|| jkr6|d ur.d|d v r.d|d d d< td| dS |S dS )	Nmaxr   ZResponseMetadatar   TZMaxAttemptsReachedz0Reached the maximum number of retry attempts: %sF)r]   r#   r[   _should_retryrK   rL   )rA   rD   r.   rE   rH   Zshould_retryr   r   r   rO     s*   

zMaxAttemptsDecorator.__call__c              
   C   sh   | j r-|| jk r-z| |||W S  | j y, } ztjd|dd W Y d }~dS d }~ww | |||S )Nz,retry needed, retryable exception caught: %sT)exc_info)r\   r[   r?   rK   rL   )rA   rD   r.   rE   er   r   r   r^   0  s   
z"MaxAttemptsDecorator._should_retryr>   )rP   rQ   rR   rS   rB   rO   r^   r   r   r   r   r)     s
    

r)   c                   @      e Zd Zdd Zdd ZdS )r8   c                 C   
   || _ d S r>   )_status_code)rA   r3   r   r   r   rB   D     
zHTTPStatusCodeChecker.__init__c                 C   s&   |d j | jkrtd| j dS dS )Nr   z5retry needed: retryable HTTP status code received: %sTF)r3   rc   rK   rL   rX   r   r   r   rU   G  s   z%HTTPStatusCodeChecker._check_responseNrP   rQ   rR   rB   rU   r   r   r   r   r8   C      r8   c                   @   ra   )r7   c                 C   r=   r>   )rc   _error_code)rA   r3   r4   r   r   r   rB   S  rC   z ServiceErrorCodeChecker.__init__c                 C   sJ   |d j | jkr#|d di d}|| jkr#td| j| j dS dS )Nr   r   ErrorZCodez>retry needed: matching HTTP status and error code seen: %s, %sTF)r3   rc   r#   rg   rK   rL   )rA   rD   r.   Zactual_error_coder   r   r   rU   W  s   
z'ServiceErrorCodeChecker._check_responseNre   r   r   r   r   r7   R      r7   c                   @   ra   )r*   c                 C   rb   r>   Z	_checkers)rA   r,   r   r   r   rB   f  rd   zMultiChecker.__init__c                 C   s(   | j D ]}||||}|r|  S qdS )NFrj   )rA   rD   r.   rE   r   Zchecker_responser   r   r   rO   i  s   
zMultiChecker.__call__N)rP   rQ   rR   rB   rO   r   r   r   r   r*   e  rf   r*   c                   @   ra   )r9   c                 C   rb   r>   )_header_name)rA   r6   r   r   r   rB   t  s   
zCRC32Checker.__init__c                 C   sv   |d }|j | j}|d u rtd| j d S t|d jd@ }|t|ks9t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#   rk   rK   rL   r   contentintr   )rA   rD   r.   Zhttp_responseZexpected_crcZactual_crc32r   r   r   rU   x  s(   zCRC32Checker._check_responseNre   r   r   r   r   r9   s  ri   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   |r>   r   rZ   r   r   r   rV     s   z'ExceptionRaiser._check_caught_exceptionN)rP   rQ   rR   rS   rV   r   r   r   r   r2     s    r2   r>   )r   loggingr	   binasciir   Zbotocore.exceptionsr   r   r   r   r   	getLoggerrP   rK   r:   r   r   r   r   r   r%   r1   r&   r   rT   r)   r8   r7   r*   r9   r2   r   r   r   r   <module>   s:   





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