Ë
    PU h™8  ã                  ó$  — d dl m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mZ d dlmZ d dlmZ d dlmZ d d	lmZ  ej,                  e«      Z G d
„ dej2                  ¬«      Z G d„ de«      Zdd„Zdd„Zdd„Z G d„ de«      Zy)é    )ÚannotationsN)Ú
HTTPStatus)ÚAny)ÚResponseÚSession)ÚConnectionError)ÚCaseInsensitiveDict)Ú	TypeGuard)Ú	JIRAErrorc                  ó>   — e Zd ZdZej
                  	 	 	 	 dd„«       Zy)ÚPrepareRequestForRetryz²This class allows for the manipulation of the Request keyword arguments before a retry.

    The :py:meth:`.prepare` handles the processing of the Request keyword arguments.
    c                ó   — |S )a)  Process the Request's keyword arguments before retrying the Request.

        Args:
            original_request_kwargs (CaseInsensitiveDict): The keyword arguments of the Request.

        Returns:
            CaseInsensitiveDict: The new keyword arguments to use in the retried Request.
        © )ÚselfÚoriginal_request_kwargss     úM/var/www/timesheet/venv/lib/python3.12/site-packages/jira/resilientsession.pyÚpreparezPrepareRequestForRetry.prepare   s
   € ð 'Ð&ó    N©r   r	   Úreturnr	   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚabcÚabstractmethodr   r   r   r   r   r      s1   „ ñð
 	×Ñð'Ø':ð'à	ò'ó ñ'r   r   )Ú	metaclassc                  ó,   ‡ — e Zd ZdZ	 	 	 	 dˆ fd„Zˆ xZS )ÚPassthroughRetryPreparezbReturns the Request's keyword arguments unchanged, when no change needs to be made before a retry.c                ó"   •— t         ‰| �  |«      S )N)Úsuperr   )r   r   Ú	__class__s     €r   r   zPassthroughRetryPrepare.prepare-   s   ø€ ô ‰w‰Ð6Ó7Ð7r   r   )r   r   r   r   r   Ú__classcell__©r"   s   @r   r   r   *   s    ø„ Ùlð8Ø':ð8à	÷8ñ 8r   r   c                óÀ   — |j                  dd«      }| €t        dd| i|¤Ž‚| j                  s1t        | ¬«      }t        |f| j                  | j
                  || dœ|¤Ž‚y)a.  Handle errors from a Jira Request.

    Args:
        resp (Optional[Response]): Response from Jira request

    Raises:
        JIRAError: If Response is None
        JIRAError: for unhandled 400 status codes.

    Returns:
        TypeGuard[Response]: True if the passed in Response is all good.
    ÚrequestNÚresponse)Úresp)Ústatus_codeÚurlr&   r'   T)zEmpty Response!)Úgetr   ÚokÚparse_error_msgr)   r*   )r(   Úkwargsr&   Úerrors       r   Úraise_on_errorr0   3   sw   € ð �j‰j˜ DÓ)€Gà€|ÜÑC°DÐC¸FÑCÐCà�7Š7Ü TÔ*ˆäØð
à×(Ñ(Ø—‘ØØñ
ð ñ
ð 	
ð r   c                ó,  — i }g }| j                   dk(  rd| j                  v r| j                  d   gS | j                  r	 | j                  «       }d|v r|d   g}|S d|v r|d   g}|S d|v r;|d   }t        |«      dkD  r&t        |t        t        f«      rt        |«      }|S |g}|S d|v rI|d   }t        |«      dkD  r6t        |t        «      r&|j                  «       D �cg c]  }t        |«      ‘Œ }}|S # t        $ r | j                  gcY S w xY wc c}w )a;  Parse a Jira Error messages from the Response.

    https://developer.atlassian.com/cloud/jira/platform/rest/v2/intro/#status-codes

    Args:
        resp (Response): The Jira API request's response.

    Returns:
        List[str]: The error messages list parsed from the Response. An empty list if no error.
    i“  zx-authentication-denied-reasonÚmessageÚerrorMessageÚerrorMessagesr   Úerrors)r)   ÚheadersÚtextÚjsonÚ
ValueErrorÚlenÚ
isinstanceÚlistÚtupleÚdictÚvaluesÚstr)r(   Ú	resp_dataÚparsed_errorsÚerror_messagesÚresp_errorsÚerrs         r   Úparse_errorsrF   T   s[  € ð !#€IØ!€MØ×Ñ˜3ÒÐ#CÀtÇ|Á|Ñ#SØ—‘Ð=Ñ>Ð?Ð?Ø	�Šð	ØŸ	™	›ˆIð �IÑà" 9Ñ-Ð.ˆð* Ðð) 
˜9Ñ	$ð # >Ñ2Ð3ˆð" Ðð! 
˜IÑ	%ð # ?Ñ3ˆÜˆ~Ó Ò"Ü˜.¬4´¨-Ô8Ü $ ^Ó 4�ð Ðð "0Ð 0�ð Ðð 
�YÑ	Ø Ñ)ˆÜˆ{Ó˜aÒ¤J¨{¼DÔ$Að 2=×1CÑ1CÓ1EÖF¨#œS �XÐFˆMÐFàÐøô5 ò 	Ø—I‘I�;Òð	üò0 Gs   ¿C5 ÃDÃ5DÄDc                ó:   — t        | «      }dj                  |«      S )aE  Parse a Jira Error messages from the Response and join them by comma.

    https://developer.atlassian.com/cloud/jira/platform/rest/v2/intro/#status-codes

    Args:
        resp (Response): The Jira API request's response.

    Returns:
        str: The error message parsed from the Response. An empty str if no error.
    z, )rF   Újoin)r(   r5   s     r   r-   r-   ƒ   s   € ô ˜$Ó€FØ�9‰9�VÓÐr   c                  ó€   ‡ — e Zd ZdZdd	ˆ fd„Zd
d„Z e«       f	 	 	 	 	 	 	 dˆ fd„Zdd„Z	 d	 	 	 	 	 	 	 dd„Z	dd„Z
ˆ xZS )ÚResilientSessionz‹This class is supposed to retry requests that do return temporary errors.

    :py:meth:`__recoverable` handles all retry-able errors.
    c                óÆ   •— || _         || _        || _        t        ‰| �  «        | j
                  j                  ddi«       t        j                  ddt        › d�z   «       y)a�  A Session subclass catered for the Jira API with exponential delaying retry.

        Args:
            timeout (Optional[Union[Union[float, int], Tuple[float, float]]]): Connection/read timeout delay. Defaults to None.
            max_retries (int): Max number of times to retry a request. Defaults to 3.
            max_retry_delay (int): Max delay allowed between retries. Defaults to 60.
        ÚAcceptzapplication/json,*/*;q=0.9z@WARNING: On error, will dump Response headers and body to logs. zLog level debug in 'z"' is not safe for production code!N)
ÚtimeoutÚmax_retriesÚmax_retry_delayr!   Ú__init__r6   ÚupdateÚLOGÚdebugr   )r   rM   rN   rO   r"   s       €r   rP   zResilientSession.__init__˜   se   ø€ ð ˆŒØ&ˆÔØ.ˆÔÜ‰ÑÔð 	�‰×Ñ˜XÐ'CÐDÔEô 	�	‰	ØNØ$¤X JÐ.PÐQñRõ	
r   c                óD  — |j                  «       }|  | j                  j                  «       }|j                  |j                  di «      «       ||d<   |j                  dd«      }t	        |t
        «      rt        j                  |«      |d<   d|vr| j                  |d<   |S )z?Do any pre-processing of our own and return the updated kwargs.r6   ÚdataNÚverify)	Úcopyr6   rQ   r+   r;   r>   r8   ÚdumpsrV   )r   Úoriginal_kwargsÚprepared_kwargsÚrequest_headersrU   s        r   Ú_jira_preparezResilientSession._jira_prepare®   s—   € à)×.Ñ.Ó0ˆÙØŸ,™,×+Ñ+Ó-ˆØ×Ñ˜×2Ñ2°9¸bÓAÔBØ%4ˆ˜	Ñ"à×"Ñ" 6¨4Ó0ˆÜ�dœDÔ!ô '+§j¡j°Ó&6ˆO˜FÑ#à˜?Ñ*Ø(,¯©ˆO˜HÑ%àÐr   c                óü  •‡ ‡— dŠd}d} ‰ j                   di |¤Ž}dˆˆ fd„} |«       rŸd}d}	 t        ‰‰ �  ||fd‰ j                  i|¤Ž}|j                  r‰ j                  |«       |S 	 |�|n|}
‰dz  Š |«       r4‰ j                  |
||j                  «       ‰«      r|j                  |«       n‰ j                  dz   Š |«       rŒŸ|�|‚t        |fi |¤Žr|S t        d«      ‚# t        $ r}	|	}Y d}	~	ŒŠd}	~	ww xY w)	a	  This is an intentional override of `Session.request()` to inject some error handling and retry logic.

        Raises:
            Exception: Various exceptions as defined in py:method:`raise_on_error`.

        Returns:
            Response: The response.
        r   Nc                 ó"   •— ‰ ‰j                   k  S )z4Helper method to say if we should still be retrying.)rN   )Úretry_numberr   s   €€r   Úis_allowed_to_retryz5ResilientSession.request.<locals>.is_allowed_to_retry×   s   ø€ à 4×#3Ñ#3Ñ3Ð3r   rM   é   z*Expected a Response or Exception to raise!r   )r   Úbool)r\   r!   r&   rM   r,   Ú2_ResilientSession__handle_known_ok_response_errorsr   Ú_ResilientSession__recoverableÚupperr   rN   r0   ÚRuntimeError)r   Úmethodr*   Ú_prepare_retry_classr.   Ú	exceptionr'   Úprocessed_kwargsr`   ÚeÚresponse_or_exceptionr_   r"   s   `          @€r   r&   zResilientSession.requestÁ   s9  ú€ ð ˆØ&*ˆ	Ø$(ˆð .˜4×-Ñ-Ñ7°Ñ7Ðö	4ñ "Ô#ØˆHØˆIð	Ü ™7™?Ø˜CñØ)-¯©ðØ9Iñ�ð —;’;Ø×:Ñ:¸8ÔDØ#�Oð ð 19Ð0D¡HÈ)Ð!Ø˜AÑˆLÙ"Ô$¨×);Ñ);Ø% s¨F¯L©L«N¸Lô*ð %×,Ñ,Ð-=Õ>à#×/Ñ/°!Ñ3�ñ/ "Õ#ð2 Ð àˆOÜ˜HÑ9Ð(8Ò9àˆOô ÐKÓLÐLøô+ #ò Ø•	ûðús   ¯;C& Ã&	C;Ã/C6Ã6C;c                ó¼   — |j                   syt        |j                  «      dk(  r7d|j                  v r(d|j                  d   v rt        j                  d«       yyyy)zÂResponses that report ok may also have errors.

        We can either log the error or raise the error as appropriate here.

        Args:
            response (Response): The response.
        Nr   zX-Seraph-LoginReasonÚAUTHENTICATED_FAILEDz;Atlassian's bug https://jira.atlassian.com/browse/JRA-41559)r,   r:   Úcontentr6   rR   Úwarning)r   r'   s     r   Ú!__handle_known_ok_response_errorsz2ResilientSession.__handle_known_ok_response_errorsþ   s`   € ð �{Š{Øä�× Ñ Ó! QÒ&Ø&¨(×*:Ñ*:Ñ:Ø&¨(×*:Ñ*:Ð;QÑ*RÑRä�K‰KÐUÕVð Sð ;ð 'r   c                ó°  — d}t        |«      }t        |t        «      rndd|z  z  }t        j	                  d|› d|j
                  › d|› d�|› d�z   «       t        j                  t        j                  kD  røt        j	                  d	«       nât        |t        «      rÒt        j                  t        j                  g}|j                  |v r¤|j                  j                  d
«      }|rdt!        t#        |«      d«      z  }n%|j                  t        j                  k(  rdd|z  z  }|j                  t        j                  k(  r,|j                  › d|j$                  › �}| j'                  |«       |dkD  }	|	rát)        | j*                  |«      t-        j.                  dd«      z  }
t        j	                  d|› d|› d|› d| j0                  › d|
› d|› �«       t        |t        «      r^t        j3                  dt5        j6                  t9        |j                  «      d¬«      «       t        j3                  d|j:                  «       t=        j>                  |
«       |	S )a‰  Return whether the request is recoverable and hence should be retried.

        Exponentially delays if recoverable.

        At this moment it supports: 429, 503

        Args:
            response (Optional[Union[ConnectionError, Response]]): The response or exception.
              Note: the response here is expected to be ``not response.ok``.
            url (Union[str, bytes]): The URL.
            request_method (str): The request method.
            counter (int, optional): The retry counter to use when calculating the exponential delay. Defaults to 1.

        Returns:
            bool: True if the request should be retried.
        éÿÿÿÿé
   é   zGot ConnectionError [z] errno:z on ú ú
zJResponse headers for ConnectionError are only printed for log level DEBUG.úRetry-Afterra   r   g      à?g      ð?zGot recoverable error from z, will retry [ú/z] in zs. Err: zresponse.headers:
%sé   )Úindentzresponse.body:
%s) r@   r;   r   rR   rp   ÚerrnoÚlevelÚloggingÚDEBUGr   r   ÚTOO_MANY_REQUESTSÚSERVICE_UNAVAILABLEr)   r6   r+   ÚmaxÚintÚreasonÚ(_ResilientSession__log_http_429_responseÚminrO   ÚrandomÚuniformrN   rS   r8   rX   r>   ro   ÚtimeÚsleep)r   r'   r*   Úrequest_methodÚcounterÚsuggested_delayÚmsgÚrecoverable_error_codesÚretry_afterÚis_recoverableÚdelays              r   Ú__recoverablezResilientSession.__recoverable  s8  € ð. ˆÜ�(‹mˆä�h¤Ô0Ø  1 g¡:™oˆOä�K‰KØ'¨ z°¸(¿.¹.Ð9IÈÈnÐM]Ð]^Ð_Ø�E˜�*ñôô �y‰yœ7Ÿ=™=Ò(Ü—‘Ø`õô ˜¤(Ô+ä×,Ñ,Ü×.Ñ.ð'Ð#ð
 ×#Ñ#Ð'>Ñ>Ø&×.Ñ.×2Ñ2°=ÓA�ÙØ&'¬#Ü˜KÓ(¨!ó+ñ '‘Oð ×)Ñ)¬Z×-IÑ-IÒIØ&(¨1¨g©:¡o�Oà×'Ñ'¬:×+GÑ+GÒGØ%×1Ñ1Ð2°!°H·O±OÐ3DÐE�CØ×0Ñ0°Ô:à(¨1Ñ,ˆÙä˜×,Ñ,¨oÓ>ÄÇÁØ�SóBñ ˆEô �K‰KØ-¨nÐ-=¸Q¸s¸eÀ>ÐRYÐQZÐZ[Ð\`×\lÑ\lÐ[mÐmrÐsxÐryð  zBð  CFð  BGð  Hôô ˜(¤HÔ-Ü—	‘	Ø+Ü—J‘Jœt H×$4Ñ$4Ó5¸aÔ@ôô —	‘	Ð.°×0@Ñ0@ÔAÜ�J‰J�uÔàÐr   c                óh  — |j                   j                  d«      }|j                   j                  d«      }|j                   j                  d«      }|j                   j                  d«      }d}||�d|› d�ndz  }|�|�||› d	|› d�z  }|�	|d
|› d�z  }|dz   dz   }t        j                  |«       y )Nrx   zX-RateLimit-FillRatezX-RateLimit-Interval-SecondszX-RateLimit-LimitzRequest rate limited by Jira.z! Request should be retried after z
 seconds.
rw   z tokens are issued every zYou can accumulate up to z	 tokens.
z;Consider adding an exemption for the user as explained in: zohttps://confluence.atlassian.com/adminjiraserver/improving-instance-stability-with-rate-limiting-983794911.html)r6   r+   rR   rp   )r   r'   r�   Ú$number_of_tokens_issued_per_intervalÚ#token_issuing_rate_interval_secondsÚmaximum_number_of_tokensÚwarning_msgs          r   Ú__log_http_429_responsez(ResilientSession.__log_http_429_response[  s  € Ø×&Ñ&×*Ñ*¨=Ó9ˆØ/7×/?Ñ/?×/CÑ/CØ"ó0
Ð,ð /7×.>Ñ.>×.BÑ.BØ*ó/
Ð+ð $,×#3Ñ#3×#7Ñ#7Ð8KÓ#LÐ à5ˆØàÐ&ð 0°¨}¸KÑHàñ	
ˆð 1Ð<Ø3Ð?àÐBÐCÐC\ð  ^Að  ]Bð  BMð  Nñ  NˆKà#Ð/ØØ+Ð,DÐ+EÀZÐPñˆKð
 ØKñLàñ@ð 	ô 	�‰�KÕ r   )Né   é<   )rN   rƒ   rO   rƒ   )r   r>   )rg   r@   r*   ústr | bytesrh   r   r   r   )r'   r   )ra   )r'   z!ConnectionError | Response | Noner*   rœ   r‹   r@   rŒ   rƒ   )r   r   r   r   rP   r\   r   r&   rc   rd   r…   r#   r$   s   @r   rJ   rJ   ’   s�   ø„ ñö

ó,ñ. 8OÓ7Pð	;Màð;Mð ð;Mð 5ð	;Mð 
õ;MózWð, ðJà3ðJð ðJð ð	Jð
 óJ÷X"!r   rJ   )r(   zResponse | Noner   zTypeGuard[Response])r(   r   r   z	list[str])r(   r   r   r@   ) Ú
__future__r   r   r8   r~   r‡   r‰   Úhttpr   Útypingr   Úrequestsr   r   Úrequests.exceptionsr   Úrequests.structuresr	   Útyping_extensionsr
   Újira.exceptionsr   Ú	getLoggerr   rR   ÚABCMetar   r   r0   rF   r-   rJ   r   r   r   ú<module>r§      sz   ðÝ "ã 
Û Û Û Û Ý Ý ç &Ý /Ý 3Ý 'å %à€g×Ñ˜Ó!€ô' s§{¡{õ 'ô*8Ð4ô 8óóB,ó^ôk!�wõ k!r   