o
    o]b(                     @   s8  d dl mZ d dl mZ d dl mZ d dl mZ d dlmZ d dlmZmZ d dl	m
Z
mZ d dlmZmZ d d	lmZmZ zd d
lmZ W n eyU   d d
lmZ Y nw zefZW n eyh   eefZY nw dZdZdZdd Zdd ZG dd deZ G dd de!Z"G dd deZ#ddddde fddZ$dS )    )unicode_literals)division)print_function)absolute_import)wraps)datetime	timedelta)isgeneratorfunctionisclass)AnyStrIterable)ceilfloor)	monotonicclosedopenZ	half_openc                     s    fdd}|S )zOBuild a predicate function that checks if an exception is a subtype from a listc                    s
   t |  S N)
issubclass)Zthrown_type_	exc_types 2usr/lib/python3.10/site-packages/circuitbreaker.pymatches_types       
z(in_exception_list.<locals>.matches_typesr   )r   r   r   r   r   in_exception_list   s   r   c                 C   sx   t | rt| trt| }|S zt|  t| trtdt|  }W |S  ty;   t	| r2t | r6td| }Y |S w )az   Build a failure predicate_function.
          The returned function has the signature (Type[Exception], Exception) -> bool.
          Return value True indicates a failure in the underlying function.

        :param expected_exception: either an type of Exception, iterable of Exception types, or a predicate function.

          If an Exception type or iterable of Exception types, the failure predicate will return True when a thrown
          exception type matches one of the provided types.

          If a predicate function, it will just be returned as is.

         :return: callable (Type[Exception], Exception) -> bool
    z9expected_exception cannot be a string. Did you mean name?z1expected_exception does not look like a predicate)
r
   r   	Exceptionr   iter
isinstanceSTRING_TYPES
ValueError	TypeErrorcallable)expected_exceptionZfailure_predicater   r   r   build_failure_predicate&   s   

r$   c                   @   s   e Zd ZdZdZeZdZ					d*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edd Zedd Zedd Zedd Zedd Zed d! Zed"d# Zed$d% Zed&d' Zd(d) ZdS )+CircuitBreaker      Nc                 C   s   d| _ d| _|p
| j| _|p| j| _|s*z	t| jd }W n ty)   t	j
}Y nw t|| _|p3| j| _|| _t| _t | _dS )a  
        Construct a circuit breaker.

        :param failure_threshold: break open after this many failures
        :param recovery_timeout: close after this many seconds
        :param expected_exception: either an type of Exception, iterable of Exception types, or a predicate function.
        :param name: name for this circuitbreaker
        :param fallback_function: called when the circuit is opened

           :return: Circuitbreaker instance
           :rtype: Circuitbreaker
        Nr   EXPECTED_EXCEPTION)_last_failure_failure_countFAILURE_THRESHOLD_failure_thresholdRECOVERY_TIMEOUT_recovery_timeouttype__dict__KeyErrorr%   r(   r$   
is_failureFALLBACK_FUNCTION_fallback_function_nameSTATE_CLOSED_stater   _opened)selffailure_thresholdrecovery_timeoutr#   namefallback_functionr   r   r   __init__N   s   

zCircuitBreaker.__init__c                 C   s
   |  |S r   )decorate)r9   wrappedr   r   r   __call__y   r   zCircuitBreaker.__call__c                 C   s   d S r   r   r9   r   r   r   	__enter__|   s   zCircuitBreaker.__enter__c                 C   s.   |r|  ||r|| _|   dS |   dS )NF)r2   r)   _CircuitBreaker__call_failed_CircuitBreaker__call_succeeded)r9   exc_type	exc_value
_tracebackr   r   r   __exit__   s   zCircuitBreaker.__exit__c                    sn   j du rzj_ W n ty   j_ Y nw t tr&j nj t	 fdd}|S )z;
        Applies the circuit breaker to a function
        Nc                     s:   j rjrj| i |S t g| R i |S r   )openedr=   CircuitBreakerError)argskwargscallfunctionr9   r   r   wrapper   s
   z(CircuitBreaker.decorate.<locals>.wrapper)
r5   __qualname__AttributeError__name__CircuitBreakerMonitorregisterr	   call_generatorrO   r   )r9   rP   rQ   r   rN   r   r?      s   

zCircuitBreaker.decoratec                 O   s6   |  ||i |W  d   S 1 sw   Y  dS )z
        Calls the decorated function and applies the circuit breaker
        rules on success or failure
        :param func: Decorated function
        Nr   )r9   funcrL   rM   r   r   r   rO      s   $zCircuitBreaker.callc                 o   sF    |  ||i |D ]}|V  qW d   dS 1 sw   Y  dS )z
        Calls the decorated generator function and applies the circuit breaker
        rules on success or failure
        :param func: Decorated generator function
        Nr   )r9   rX   rL   rM   elr   r   r   rW      s   "zCircuitBreaker.call_generatorc                 C   s   t | _d| _d| _dS )zR
        Close circuit after successful execution and reset failure count
        Nr   )r6   r7   r)   r*   rB   r   r   r   Z__call_succeeded   s   
zCircuitBreaker.__call_succeededc                 C   s0   |  j d7  _ | j | jkrt| _t | _dS dS )zO
        Count failure and open circuit, if threshold has been reached
           N)r*   r,   
STATE_OPENr7   r   r8   rB   r   r   r   Z__call_failed   s
   zCircuitBreaker.__call_failedc                 C   s   | j tkr| jdkrtS | j S Nr   )r7   r[   open_remainingSTATE_HALF_OPENrB   r   r   r   state   s   zCircuitBreaker.statec                 C   s   t  t| jd S )zq
        The approximate datetime when the circuit breaker will try to recover
        :return: datetime
        )seconds)r   utcnowr   r]   rB   r   r   r   
open_until   s   zCircuitBreaker.open_untilc                 C   s*   | j | j t  }|dkrt|S t|S )zk
        Number of seconds remaining, the circuit breaker stays in OPEN state
        :return: int
        r   )r8   r.   r   r   r   )r9   Zremainr   r   r   r]      s   zCircuitBreaker.open_remainingc                 C      | j S r   )r*   rB   r   r   r   failure_count      zCircuitBreaker.failure_countc                 C   
   | j tkS r   )r_   r6   rB   r   r   r   r         
zCircuitBreaker.closedc                 C   rf   r   )r_   r[   rB   r   r   r   rJ      rg   zCircuitBreaker.openedc                 C   rc   r   r5   rB   r   r   r   r<      re   zCircuitBreaker.namec                 C   rc   r   )r)   rB   r   r   r   last_failure   re   zCircuitBreaker.last_failurec                 C   rc   r   )r4   rB   r   r   r   r=      re   z CircuitBreaker.fallback_functionc                 O   rc   r   rh   r9   rL   rM   r   r   r   __str__   s   zCircuitBreaker.__str__)NNNNN)rT   
__module__rR   r+   r-   r   r(   r3   r>   rA   rC   rI   r?   rO   rW   rE   rD   propertyr_   rb   r]   rd   r   rJ   r<   ri   r=   rk   r   r   r   r   r%   H   sL    
+		
	








r%   c                       s$   e Zd Z fddZdd Z  ZS )rK   c                    s    t t| j|i | || _dS )zf
        :param circuit_breaker:
        :param args:
        :param kwargs:
        :return:
        N)superrK   r>   _circuit_breaker)r9   circuit_breakerrL   rM   	__class__r   r   r>      s   
zCircuitBreakerError.__init__c                 O   s*   d| j j| j j| j jt| j j| j jf S )NzMCircuit "%s" OPEN until %s (%d failures, %d sec remaining) (last_failure: %r))ro   r<   rb   rd   roundr]   ri   rj   r   r   r   rk     s   
zCircuitBreakerError.__str__)rT   rl   rR   r>   rk   __classcell__r   r   rq   r   rK      s    
rK   c                   @   sX   e Zd Zi Zedd Zedd Zedd Zedd Zed	d
 Z	edd Z
dS )rU   c                 C   s   || j |j< d S r   )circuit_breakersr<   )clsrp   r   r   r   rV     s   zCircuitBreakerMonitor.registerc                 C   s   t t|  dkS r\   )lenlistget_openrv   r   r   r   
all_closed  s   z CircuitBreakerMonitor.all_closedc                 C   s
   | j  S r   )ru   valuesrz   r   r   r   get_circuits  s   
z"CircuitBreakerMonitor.get_circuitsc                 C   s   | j |S r   )ru   get)rv   r<   r   r   r   r~      s   zCircuitBreakerMonitor.getc                 c        |   D ]}|jr|V  qd S r   )r}   rJ   rv   circuitr   r   r   ry   %     zCircuitBreakerMonitor.get_openc                 c   r   r   )r}   r   r   r   r   r   
get_closed,  r   z CircuitBreakerMonitor.get_closedN)rT   rl   rR   ru   classmethodrV   r{   r}   r~   ry   r   r   r   r   r   rU     s    




rU   Nc                 C   s&   t | r
| | S || ||||dS )N)r:   r;   r#   r<   r=   )r"   r?   )r:   r;   r#   r<   r=   rv   r   r   r   r   4  s   r   )%
__future__r   r   r   r   	functoolsr   r   r   inspectr	   r
   typingr   r   mathr   r   timer   ImportErrorZ
basestringr   	NameErrorbytesstrr6   r[   r^   r   r$   objectr%   r   rK   rU   r   r   r   r   r   <module>   sF   
	" 3%