o
    i                     @   s   d Z ddlZddlmZmZmZ zddlmZ W n ey'   ddlmZ Y nw ddl	m
Z
 dd Zd	d
 Zdd ZG dd deZdddddZdS )u   
This implementation is mostly copied from asyncio.tasks (Python 3.8) while making the necessary changes.

:copyright: 2021 Nándor Mátravölgyi
:license: Apache2, see LICENSE for more details.
    N)CancelledErrorensure_futureTimeoutError)get_running_loop)get_event_loop)partialc                 G   s   |   s| d  d S d S N)done
set_result)waiterargs r   B/home/ubuntu/.local/lib/python3.10/site-packages/wait_for2/impl.py_release_waiter   s   r   c              
   C   sT   |r%z||| W n t y$ } z| d||d W Y d }~nd }~ww t||)Nzwait_for2 race_handler failed)message	exceptionfuture)	Exceptioncall_exception_handlerCancelledWithResultError)loopfut
fut_resultres_exceptionrace_handlerer   r   r   (_handle_cancelling_with_inner_completion   s   
r   c           	   
      s   |s6|  }tt|}| | |   zz|I dH  W n ty(   d}Y nw W | | n
| | w |   z| I dH }|sE|W S W n- tyZ } z|rR|t |d}~w tys } z|se||}d}W Y d}~nd}~ww d}t	|| ||| dS )a  
    The builtin implementation of _cancel_and_wait is made in a way to ensure cancellation of it will always be
    possible, at the cost of ensuring that the wrapped future shall terminate inside it.

    The documentation says that
        - "If a timeout occurs, it cancels the task and raises asyncio.TimeoutError."
        - "The function will wait until the future is actually cancelled"
    , but their combination will result in undocumented behaviour:
        If a timeout occurs and the inner future is cancelled, then cancelling the waiter will instantly cancel
        it and the inner future may still be running, which does not fulfill the second promise.

    This implementation will prioritize cancellation or the result of the inner future dynamically as it makes sense.
    NTF)
create_futurer   r   add_done_callbackcancelr   remove_done_callbackr   r   r   )	r   r   
cancellingr   r   cbr   excr   r   r   r   _cancel_and_wait2   sB   


r$   c                       s4   e Zd Z fddZedd Zedd Z  ZS )r   c                    s   t t| || d S r   )superr   __init__)selfresultr#   	__class__r   r   r&   Q   s   z!CancelledWithResultError.__init__c                 C   
   | j d S )Nr   r   r'   r   r   r   r(   T      
zCancelledWithResultError.resultc                 C   r+   )N   r,   r-   r   r   r   is_exceptionX   r.   z%CancelledWithResultError.is_exception)__name__
__module____qualname__r&   propertyr(   r0   __classcell__r   r   r)   r   r   P   s    
r   )r   r   c          	         s  |du r	t  }n	tjdkrtd|du r| I dH S |dkr7t| |d} |  r-|  S t| |d|I dH S | }|	|t
|}tt
|}t| |d} | | ziz|I dH  W n@ ty   |  rz|  }W n tys    w |du r|  }d}nd}t|| ||| | | t| |d|I dH  Y nw |  r|  W |  S | | t| |d|I dH W |  S |  w )aS	  
    Alternate implementation of asyncio.wait_for() based on the version from Python 3.8. It handles simultaneous
    cancellation of wait and completion of future differently and consistently across python versions 3.6+.

    Builtin asyncio.wait_for() behaviours:
        Python 3.6, 3.7 and PyPy3:
            Cancellation of wait_for could lose the completed future's result.
        Python 3.8+:
            Cancellation of wait_for could lose the cancellation request.

    Whenever waiting for a future's result the user expects to either have the future completed or cancelled.
    Unfortunately due to technical details there is a chance that both will happen simultaneously. The builtin version
    of asyncio.wait_for() shipped with Python either handles one or the other only. If losing the future's result or
    ignoring the cancellation is critical to the application it may not be suitable for use.

    Using this implementation, in case both conditions occur at the same time a subclassed CancelledError will be
    raised which also contains the result of the future. The caller code must catch this exception and handle the
    result if it is important. Otherwise it can be used the same way as the builtin wait_for.

    If the caller prefers to handle the race-condition with a callback, the `race_handler` argument may be provided.
    It will be called with the result of the future when the waiter task is being cancelled. Even if this is provided,
    the special error will be raised in the place of a normal CancelledError.

    Additionally, this implementation will inherit the behaviour of the inner future when it comes to ignoring
    cancellation. The builtin version prefers to always be cancellable, even if that means the wrapped future may
    not be terminated with it. (behaviour of builtin _cancel_and_wait) This behaviour is also improved in
    timeout-cancel edge cases, where the builtin would not wait for the termination of the inner future if the
    waiter was cancelled after timeout handling had already started. This is more consistent as the inner future
    must always be stopped for it to return.

    NOTE: CancelledWithResultError is limited to the coroutine wait_for is invoked from!
    If this wait_for is wrapped in tasks those will not propagate the special exception, but raise their own
    CancelledError instances.
    N)   
   z1loop parameter has been dropped since Python 3.10r   )r   FT)r   sysversion_infoRuntimeErrorr   r	   r(   r$   r   
call_laterr   r   r   r   r   r   r    r   )	r   timeoutr   r   r   timeout_handler"   r   r   r   r   r   wait_for]   sR   #






r>   )__doc__r8   asyncior   r   r   r   ImportErrorr   	functoolsr   r   r   r$   r   r>   r   r   r   r   <module>   s    	1