o
    tf                      @  s   d dl mZ d dlmZ d dlmZmZmZmZm	Z	m
Z
 er5d dlZd dlmZ e	d Ze	d ZedZne
dZG d	d
 d
ee ZG dd deee ZG dd deee Z			dd ddZ			d!d"ddZdS )#    )annotations)Timer)TYPE_CHECKINGAnyCallableGenericLiteralTypeVarN)	ParamSpec)Z	throttlerZ	debouncer)trailingleadingPc                   @  sp   e Zd ZU ded< 		d#d$ddZd%ddZd%ddZd%ddZd%ddZd%ddZ	d&ddZ
ed'd d!Zd"S )(_ThrottlerBaser   _timerd   r   funcCallable[P, Any]intervalintpolicyEmissionPolicyreturnNonec                 C  s   || _ |d | _|| _d| _tddd | _| j  d| _i | _t	|dd| _
t	|d	d| _t	|d
d| _t	|dd | _t	|di | _d S )Ni  Fr   c                   S  s   d S N r   r   r   [/var/www/html/software/conda/envs/catlas/lib/python3.10/site-packages/psygnal/_throttler.py<lambda>"   s    z)_ThrottlerBase.__init__.<locals>.<lambda>r   
__module__ __name____qualname____doc____annotations__)__wrapped__	_interval_policy_has_pendingr   r   start_args_kwargsgetattrr   r   r    r!   r"   selfr   r   r   r   r   r   __init__   s   

z_ThrottlerBase.__init__c                 C  s&   d| _ | j| ji | j |   d S )NF)r&   r#   r(   r)   _start_timerr,   r   r   r   _actually_call0   s   z_ThrottlerBase._actually_callc                 C  s   | j r	|   d S d S r   )r&   r0   r/   r   r   r   _call_if_has_pending5   s   z#_ThrottlerBase._call_if_has_pendingc                 C  s(   | j   t| j| j| _ | j   d S r   )r   cancelr   r$   r1   r'   r/   r   r   r   r.   9   s   
z_ThrottlerBase._start_timerc                 C  s   d| _ | j  dS )zCancel any pending calls.FN)r&   r   r2   r/   r   r   r   r2   >   s   z_ThrottlerBase.cancelc                 C  s   |    dS )z%Force a call if there is one pending.N)r1   r/   r   r   r   flushC   s   z_ThrottlerBase.flushargsP.argskwargsP.kwargsc                 O  s   t d)Nz&Subclasses must implement this method.)NotImplementedErrorr,   r4   r6   r   r   r   __call__G   s   z_ThrottlerBase.__call__inspect.Signaturec                 C  s   dd l }|| jS )Nr   )inspect	signaturer#   )r,   r<   r   r   r   __signature__J   s   z_ThrottlerBase.__signature__Nr   r   r   r   r   r   r   r   r   r   )r   r   r4   r5   r6   r7   r   r   )r   r;   )r   r   r    r"   r-   r0   r1   r.   r2   r3   r:   propertyr>   r   r   r   r   r      s   
 





r   c                      <   e Zd ZU dZded< 		dd fddZdddZ  ZS )	Throttlera  Class that prevents calling `func` more than once per `interval`.

    Parameters
    ----------
    func : Callable[P, Any]
        a function to wrap
    interval : int, optional
        the minimum interval in ms that must pass before the function is called again,
        by default 100
    policy : EmissionPolicy, optional
        Whether to invoke the function on the "leading" or "trailing" edge of the
        wait timer, by default "leading"
    r   r   r   r   r   r   r   r   r   r   r   r   c                      t  ||| d S r   superr-   r+   	__class__r   r   r-   b      zThrottler.__init__r4   r5   r6   r7   c                 O  sB   d| _ || _|| _| j s| jdkr|   dS |   dS dS zCall underlying function.Tr   Nr&   r(   r)   r   is_aliver%   r0   r.   r9   r   r   r   r:   j   s   

zThrottler.__call__r?   r@   rA   r   r   r    r!   r"   r-   r:   __classcell__r   r   rH   r   rD   Q      
 rD   c                      rC   )	Debouncera  Class that waits at least `interval` before calling `func`.

    Parameters
    ----------
    func : Callable[P, Any]
        a function to wrap
    interval : int, optional
        the minimum interval in ms that must pass before the function is called again,
        by default 100
    policy : EmissionPolicy, optional
        Whether to invoke the function on the "leading" or "trailing" edge of the
        wait timer, by default "trailing"
    r   r   r   r   r   r   r   r   r   r   r   r   c                   rE   r   rF   r+   rH   r   r   r-      rJ   zDebouncer.__init__r4   r5   r6   r7   c                 O  s:   d| _ || _|| _| j s| jdkr|   |   dS rK   rL   r9   r   r   r   r:      s   zDebouncer.__call__)r   r   r@   rA   rN   r   r   rH   r   rQ   w   rP   rQ   r   Tr   Callable[P, Any] | Nonetimeoutr   r   boolr   9Throttler[P] | Callable[[Callable[P, Any]], Throttler[P]]c                   $   d fdd}| dur|| S |S )	a$  Create a throttled function that invokes func at most once per timeout.

    The throttled function comes with a `cancel` method to cancel delayed func
    invocations and a `flush` method to immediately invoke them. Options
    to indicate whether func should be invoked on the leading and/or trailing
    edge of the wait timeout. The func is invoked with the last arguments provided
    to the throttled function. Subsequent calls to the throttled function return
    the result of the last func invocation.

    This decorator may be used with or without parameters.

    Parameters
    ----------
    func : Callable
        A function to throttle
    timeout : int
        Timeout in milliseconds to wait before allowing another call, by default 100
    leading : bool
        Whether to invoke the function on the leading edge of the wait timer,
        by default True

    Examples
    --------
    ```python
    from psygnal import Signal, throttled

    class MyEmitter:
        changed = Signal(int)

    def on_change(val: int)
        # do something possibly expensive
        ...

    emitter = MyEmitter()

    # connect the `on_change` whenever `emitter.changed` is emitted
    # BUT, no more than once every 50 milliseconds
    emitter.changed.connect(throttled(on_change, timeout=50))
    ```
    r   r   r   Throttler[P]c                       rdnd}t | |S Nr   r   )rD   r   r   r   rS   r   r   deco      zthrottled.<locals>.decoN)r   r   r   rW   r   r   rS   r   r\   r   r[   r   	throttled   s   .r_   F9Debouncer[P] | Callable[[Callable[P, Any]], Debouncer[P]]c                   rV   )	a  Create a debounced function that delays invoking `func`.

    `func` will not be invoked until `timeout` ms have elapsed since the last time
    the debounced function was invoked.

    The debounced function comes with a `cancel` method to cancel delayed func
    invocations and a `flush` method to immediately invoke them. Options
    indicate whether func should be invoked on the leading and/or trailing edge
    of the wait timeout. The func is invoked with the *last* arguments provided to
    the debounced function. Subsequent calls to the debounced function return the
    result of the last `func` invocation.

    This decorator may be used with or without parameters.

    Parameters
    ----------
    func : Callable
        A function to throttle
    timeout : int
        Timeout in milliseconds to wait before allowing another call, by default 100
    leading : bool
        Whether to invoke the function on the leading edge of the wait timer,
        by default False

    Examples
    --------
    ```python
    from psygnal import Signal, debounced

    class MyEmitter:
        changed = Signal(int)

    def on_change(val: int)
        # do something possibly expensive
        ...

    emitter = MyEmitter()

    # connect the `on_change` whenever `emitter.changed` is emitted
    # ONLY once at least 50 milliseconds have passed since the last signal emission.
    emitter.changed.connect(debounced(on_change, timeout=50))
    ```
    r   r   r   Debouncer[P]c                   rX   rY   )rQ   rZ   r[   r   r   r\     r]   zdebounced.<locals>.decoN)r   r   r   ra   r   r^   r   r[   r   	debounced   s   1rb   )Nr   T)r   rR   rS   r   r   rT   r   rU   )Nr   F)r   rR   rS   r   r   rT   r   r`   )
__future__r   	threadingr   typingr   r   r   r   r   r	   r<   Ztyping_extensionsr
   Kindr   r   r   rD   rQ   r_   rb   r   r   r   r   <module>   s*     
<&%6