U
    7eB                     @   sz   d Z ddlZddlmZ ddlZddlZddlZddlmZm	Z	 ddl
mZ dddZdd Zd	d
 Zdd Zdd ZdS )z*Patch asyncio to allow nested event loops.    N)contextmanagersuppress)heappopc                 C   s*   t   t  t  | pt } t|  dS )z/Patch asyncio to make its event loop reentrant.N)_patch_asyncio_patch_policy_patch_tornadoasyncioget_event_loop_patch_looploop r   +lib/python3.8/site-packages/nest_asyncio.pyapply   s
    r   c                  C   s   dddd} ddd}t tdr&d	S tjd
krdtjj t_ tj_tj_tjj	 t_
 tj_tj_
tjdk rtjjjtj_tjjjt_tjdkr| t_ t_t_| t_dt_d	S )z:Patch asyncio module to use pure Python tasks and futures.F)debugc                S   sb   t  }|| t | }z||W S | s\|  tt j || W 5 Q R X X d S N)	r   r	   Z	set_debugensure_futuredonecancelr   ZCancelledErrorrun_until_complete)mainr   r   Ztaskr   r   r   run   s    

z_patch_asyncio.<locals>.run   c                 S   s    t  }|d krt   }|S r   )events_get_running_loopget_event_loop_policyr	   )
stacklevelr   r   r   r   _get_event_loop%   s    z'_patch_asyncio.<locals>._get_event_loop_nest_patchedN)r      r   r      r   )r   	   r   T)r   )hasattrr   sysversion_infotasksZ_PyTaskTaskZ_CTaskZfuturesZ	_PyFutureFutureZ_CFuture_current_tasksZ	all_tasksr   r   r	   r   r   )r   r   r   r   r   r      s$    




r   c                  C   s   dd } t  }| |j_dS )z1Patch the policy to always return a patched loop.c                 S   s.   | j jd kr&|  }t| | | | j jS r   )_localZ_loopZnew_event_loopr
   Zset_event_loop)selfr   r   r   r   r	   @   s
    
z%_patch_policy.<locals>.get_event_loopN)r   r   	__class__r	   )r	   Zpolicyr   r   r   r   =   s    r   c                    s   fdd}fdd} fdd}t dd t d	d
 dd }t| drTdS t| tjsptdt|  | j}||_||_	||_
||_||_|  rdnd|_tjdkot|tj|_tjdk r|j|_tjdkrtjjntjj d|_dS )z Patch loop to make it reentrant.c              
      sD   | ,  |  |    | jrq&qW 5 Q R X W 5 Q R X d| _d S )NF)	_run_once	_stoppingr+   )manage_asyncgens
manage_runr   r   run_foreverN   s
    z _patch_loop.<locals>.run_foreverc              
      sn    | \ t j|| d}||k	r&d|_| s@|   | jr&q@q&| sPtd| W  5 Q R  S Q R X d S )Nr   Fz+Event loop stopped before Future completed.)r   r   Z_log_destroy_pendingr   r-   r.   RuntimeErrorresult)r+   Zfuturef)r1   r   r   r   V   s    
z'_patch_loop.<locals>.run_until_completec           	   
      s   | j }| j}|r$|d jr$t| q|s.| jr2dn$|rTtt|d j|   ddnd}| j	
|}| | |  | j }|r|d j|k rt|}|| q|tt|D ]F}|s q| }|js | d}z|  W 5 |dk	r| | < X qd}dS )zu
        Simplified re-implementation of asyncio's _run_once that
        runs handles as they become ready.
        r   iQ N)Z_readyZ
_scheduledZ
_cancelledr   r.   minmaxZ_whentimeZ	_selectorZselectZ_process_eventsZ_clock_resolutionappendrangelenpopleftpopZ_run)	r+   ZreadyZ	scheduledtimeoutZ
event_listZend_timeZhandle_Z	curr_task)
curr_tasksr   r   r-   d   s>    
 
z_patch_loop.<locals>._run_oncec              	   s   s   |    | j}t }zHt | _t|  |  jd7  _| jrV| jdkrV| | j dV  W 5 || _t| |  jd8  _| jr| jdkr| jdk	r| jj}| j	  |dk	r| j
| d| _X dS )zSet up the loop for running.   r   N)Z_check_closedZ
_thread_idr   r   Z_set_running_loop_num_runs_pending_is_proactorloopZ_self_reading_futureZ_ovr   Z	_proactorZ_unregister	threading	get_identZ	call_soonZ_loop_self_reading)r+   Zold_thread_idZold_running_loopZovr   r   r   r1      s.    






z_patch_loop.<locals>.manage_runc              	   s   sn   t tdsd S t }z2| | j | jd k	r@tj| j| jd d V  W 5 | d | jd k	rhtj|  X d S )Nget_asyncgen_hooksF)	firstiter	finalizer)	r#   r$   rF   _set_coroutine_origin_trackingZ
_asyncgensset_asyncgen_hooksZ_debugZ_asyncgen_firstiter_hookZ_asyncgen_finalizer_hook)r+   Zold_agen_hooksr   r   r   r0      s    




z%_patch_loop.<locals>.manage_asyncgensc                 S   s   dS )z2Do not throw exception if loop is already running.Nr   r/   r   r   r   _check_running   s    z#_patch_loop.<locals>._check_runningr   NzCan't patch loop of type %srA   r   ntr    T)r   r#   
isinstancer   ZBaseEventLoop
ValueErrortyper,   r2   r   r-   rK   Z_check_runnungZ
is_runningrB   osname
issubclassZProactorEventLooprC   r$   r%   Z_set_coroutine_wrapperrI   r&   r)   r'   r   )r   r2   r   r-   rK   clsr   )r@   r0   r1   r   r
   K   s8    )




r
   c                  C   s@   dt jkr<ddlm}  tj| _tj| jkr<|  jtjf7  _dS )zo
    If tornado is imported before nest_asyncio, make tornado aware of
    the pure-Python asyncio Future.
    Ztornador   N)r$   modulesZtornado.concurrentZ
concurrentr   r(   ZFUTURES)Ztcr   r   r   r      s
    
r   )N)__doc__r   Zasyncio.eventsr   rP   r$   rD   
contextlibr   r   heapqr   r   r   r   r
   r   r   r   r   r   <module>   s   

' 