
    BPc)                         d Z ddlZddlZddlmZmZ ddlmZ ddlmZm	Z	 ddl
mZmZ  G d d          Z G d	 d
          Zd Zd Zd ZddZd Zd ZdS )a  Convienience library for concurrency

GUI apps frequently need concurrency, for example to avoid blocking UI while
doing some long running computation. This module provides helpers for doing
this kind of thing.

The functions/methods here which spawn callables asynchronously
don't supply a direct way to provide arguments. Instead, the user is
expected to use a lambda, e.g::

    holding(lck, lambda: do_stuff(1,2,3, x='hello'))

This is because the calling function may have additional arguments which
could obscure the user's ability to pass arguments expected by the called
function. For example, in the call::

    holding(lck, lambda: run_task(blocking=True), blocking=False)

the blocking argument to holding might otherwise conflict with the
blocking argument to run_task.
    N)datetime	timedeltawraps)AnyTuple)GdkGLibc                   6    e Zd ZdZd Zd Zd Zd Zd Zd Z	dS )	Futurea-  A deferred result

    A `Future` is a result-to-be; it can be used to deliver a result
    asynchronously. Typical usage:

        >>> def background_task(task):
        ...     ret = Future()
        ...     def _task(x):
        ...         return x - 4 + 2
        ...     thread = threading.Thread(target=lambda: ret.run(lambda: _task(7)))
        ...     thread.start()
        ...     return ret
        >>> # Do other stuff
        >>> print(ret.wait())
        5

    :func:`run` will also propogate exceptions; see it's docstring for details.
    c                     t          j                    | _        d | _        d | _        | j                                         d S N)	threadingLock_lock_value
_exceptionacquireselfs    3/usr/share/inkscape/extensions/inkex/gui/asyncme.py__init__zFuture.__init__C   s9    ^%%

    c                 p    | j                             d          }|r| j                                          |S )z"Return whether the result is readyF)r   r   release)r   results     r   is_readyzFuture.is_readyI   s8    ##E** 	!J   r   c                 n    | j         5  | j        | j        cddd           S | j        # 1 swxY w Y   dS )a  Wait for the result.

        `wait` blocks until the result is ready (either :func:`result` or
        :func:`exception` has been called), and then returns it (in the case
        of :func:`result`), or raises it (in the case of :func:`exception`).
        N)r   r   r   r   s    r   waitzFuture.waitP   s     Z 	& 	&&{	& 	& 	& 	& 	& 	& 	& 	& o%		& 	& 	& 	& 	& 	& 	& 	& 	& 	&s   **..c                 F    || _         | j                                         dS )zSupply the result as a return value.

        ``value`` is the result to supply; it will be returned when
        :func:`wait` is called.
        N)r   r   r   r   values     r   r   zFuture.result]   s%     
r   c                 F    || _         | j                                         dS )zSupply an exception as the result.

        Args:
            err (Exception): an exception, which will be raised when :func:`wait`
                is called.
        N)r   r   r   )r   errs     r   	exceptionzFuture.exceptionf   s%     
r   c                     	 |                       |                       dS # t          $ r }|                     |           Y d}~dS d}~ww xY w)zCalls task(), and supplies the result.

        If ``task`` raises an exception, pass it to :func:`exception`.
        Otherwise, pass the return value to :func:`result`.
        N)r   	Exceptionr%   )r   taskr$   s      r   runz
Future.runp   sh    	 KK 	  	  	 NN3	 s   ! 
AAAN)
__name__
__module____qualname____doc__r   r   r   r   r%   r)    r   r   r   r   /   sx         &    & & &    	  	  	  	  	 r   r   c                   P    e Zd ZdZddZd Zddeeef         fdZ	d Z
d	 Zd
 ZdS )DebouncedSyncVara(  A synchronized variable, which debounces its value

    :class:`DebouncedSyncVar` supports three operations: put, replace, and get.
    get will only retrieve a value once it has "settled," i.e. at least
    a certain amount of time has passed since the last time the value
    was modified.
    r   c                     t          j                    | _        t          |          | _        d| _        d| _        d| _        dS )z?Create a new dsv with the supplied delay, and no initial value.secondsNF)r   	Condition_cvr   _delay	_deadliner   _have_valuer   delay_secondss     r   r   zDebouncedSyncVar.__init__   s@    &((666 r   c                 p    | j         5  t          |          | _        ddd           dS # 1 swxY w Y   dS )z)Set the delay in seconds of the debounce.r2   N)r5   r   r6   r9   s     r   	set_delayzDebouncedSyncVar.set_delay   s    X 	; 	;#M:::DK	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	; 	;   +//Treturnc                    	 | j         5  | j        s1|r| j                                          n	 ddd           dS | j        1t          j                    }| j        }| j        }||k    r9|rd| _        d| _        | j                                          |dfcddd           S 	 ddd           n# 1 swxY w Y   |r*t          j	        ||z
  
                                           ndS )a  Retrieve a value.

        Args:
            blocking (bool, optional): if True, block until (1) the dsv has a value
                and (2) the value has been unchanged for an amount of time greater
                than or equal to the dsv's delay. Otherwise, if these conditions
                are not met, return ``(None, False)`` immediately. Defaults to True.
            remove (bool, optional): if True, remove the value when returning it.
                Otherwise, leave it where it is.. Defaults to True.

        Returns:
            Tuple[Any, bool]: Tuple (value, ok). ``value`` is the value of the variable
            (if successful, see above), and ok indicates whether or not a value was
            successfully retrieved.
        TN)NFF)r5   r8   r   r   nowr7   r   notifytimesleeptotal_seconds)r   blockingremover@   deadliner"   s         r   getzDebouncedSyncVar.get   s|    	# ' ' * + +*' ' ' ' ' ' ' ' * + lnn>s??  ++0(&*HOO%%% $;)' ' ' ' ' ' ' ' #' ' ' ' ' ' ' ' ' ' ' ' ' ' '.  #
HsN99;;<<<<"{7	#s   %B/AB//B36B3c                 p    | j         5  |                     |           ddd           dS # 1 swxY w Y   dS )a<  Replace the current value of the dsv (if any) with ``value``.

        replace never blocks (except briefly to aquire the lock). It does not
        wait for any unit of time to pass (though it does reset the timer on
        completion), nor does it wait for the dsv's value to appear or
        disappear.
        N)r5   _replacer!   s     r   replacezDebouncedSyncVar.replace   s     X 	! 	!MM%   	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	!r=   c                     | j         5  | j        r | j                                          | j         |                     |           ddd           dS # 1 swxY w Y   dS )zSet the dsv's value to ``value``.

        If the dsv already has a value, this blocks until the value is removed.
        Upon completion, this resets the timer.
        N)r5   r8   r   rJ   r!   s     r   putzDebouncedSyncVar.put   s     X 	! 	!"   "  MM%   	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	!s   =AAAc                     d| _         || _        t          j                    | j        z   | _        | j                                         d S )NT)r8   r   r   r@   r6   r7   r5   rA   r!   s     r   rJ   zDebouncedSyncVar._replace   s=    !$+5r   N)r   )TT)r*   r+   r,   r-   r   r<   r   r   boolrH   rK   rM   rJ   r.   r   r   r0   r0   |   s         ! ! ! !; ; ;
+# +#sDy1A +# +# +# +#Z	! 	! 	!	! 	! 	!    r   r0   c                 X    t          j        |           }|                                 |S )zjCall ``func()`` in a separate thread

    Returns the corresponding :class:`threading.Thread` object.
    target)r   Threadstart)functhreads     r   spawn_threadrW      s)    
 T***F
LLNNNMr   c                 ^     t                       fd}t          j        d|d           S )au  Run f() in the gtk main loop

    Returns a :class:`Future` object which can be used to retrieve the return
    value of the function call.

    :func:`in_mainloop` exists because Gtk isn't threadsafe, and therefore cannot be
    manipulated except in the thread running the Gtk main loop. :func:`in_mainloop`
    can be used by other threads to manipulate Gtk safely.
    c                  2                                    dS )z#Function to be called in the futureN)r)   )_args_kwargsrU   futures     r   handlerzin_mainloop.<locals>.handler   s    

4r   r   N)r   r	   threads_add_idle)rU   r]   r\   s   ` @r   in_mainloopr_      sI     XXF      GT***Mr   c                 <     t                      fd            }|S )a  A decorator which forces a function to only be run in Gtk's main loop.

    Invoking a decorated function as ``f(*args, **kwargs)`` is equivalent to
    using the undecorated function (from a thread other than the one running
    the Gtk main loop) as::

        in_mainloop(lambda: f(*args, **kwargs)).wait()

    :func:`mainloop_only` should be used to decorate functions which are unsafe
    to run outside of the Gtk main loop.
    c                       t          j                    r  i S t           fd                                          S )Nc                        i S r   r.   )argsfkwargss   r   <lambda>z0mainloop_only.<locals>.wrapper.<locals>.<lambda>  s    11d#5f#5#5 r   )r
   
main_depthr_   r   )rc   re   rd   s   ``r   wrapperzmainloop_only.<locals>.wrapper	  sT    ? 	&1d%f%%%55555566;;===r   r   )rd   rh   s   ` r   mainloop_onlyri      s5     1XX> > > > X> Nr   Tc                                            d          sdS t                       fd}t          j        |                                           S )a  Run task() while holding ``lock``.

    Args:
        blocking (bool, optional): if True, wait for the lock before running.
            Otherwise, if the lock is busy, return None immediately, and don't
            spawn `task`. Defaults to True.

    Returns:
        Union[Future, None]: The return value is a future which can be used to retrieve
        the result of running task (or None if the task was not run).
    FNc                                                      j        r                                                                   d S r   )r)   r   r   r   )lockretr(   s   r   _targetzholding.<locals>._target#  s:    > 	HHJJJr   rQ   )r   r   r   rS   rT   )rl   r(   rE   rn   rm   s   ``  @r   holdingro     ss     << t
((C       G$$$**,,,Jr   c                 <     t          j                     fd}|S )zA decorator which runs the function using :func:`holding`

    This function creates a single lock for this function and
    waits for the lock to release before returning.

    See :func:`holding` above, with ``blocking=True``
    c                  6     t           fdd          S )Nc                        i S r   r.   rc   rU   re   s   r   rf   z-run_or_wait.<locals>._inner.<locals>.<lambda>8      TT4%:6%:%: r   TrE   ro   rc   re   rU   rl   s   ``r   _innerzrun_or_wait.<locals>._inner7  s*    t::::::TJJJJr   r   r   rU   rx   rl   s   ` @r   run_or_waitr{   -  s>     >DK K K K K K Mr   c                 <     t          j                     fd}|S )zA decorator which runs the function using :func:`holding`

    This function creates a single lock for this function and
    returns None if the process is already running (locked)

    See :func:`holding` above with ``blocking=True``
    c                  6     t           fdd          S )Nc                        i S r   r.   rs   s   r   rf   z-run_or_none.<locals>._inner.<locals>.<lambda>H  rt   r   Fru   rv   rw   s   ``r   rx   zrun_or_none.<locals>._innerG  s*    t::::::UKKKKr   ry   rz   s   ` @r   run_or_noner   =  s>     >DL L L L L L Mr   )T)r-   rB   r   r   r   	functoolsr   typingr   r   gi.repositoryr	   r
   r   r0   rW   r_   ri   ro   r{   r   r.   r   r   <module>r      sK  " *      ( ( ( ( ( ( ( (               # # # # # # # #J  J  J  J  J  J  J  J Z_ _ _ _ _ _ _ _D    (  .   4       r   