U
    /eF                     @   s   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d ZdS )z*Patch asyncio to allow nested event loops.    N)contextmanagersuppress)heappopc                 C   s0   t   t  t  t  | p"t } t|  dS )z/Patch asyncio to make its event loop reentrant.N)_patch_asyncio_patch_policy_patch_task_patch_tornadoasyncioget_event_loop_patch_looploop r   0/tmp/pip-unpacked-wheel-j2ot8x9f/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   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   )_local_loopZnew_event_loopr   Zset_event_loop)selfr   r   r   r   r
   A   s
    
z%_patch_policy.<locals>.get_event_loopN)r   r   	__class__r
   )r
   policyr   r   r   r   >   s    r   c                    s    fdd}fdd}dd }t dd t d	d
  dd }t| drPdS t| tjsltdt|  | j}||_||_	||_
||_||_d|_tjdkot|tj|_tjdk r|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_foreverO   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   r1   r2   RuntimeErrorresult)r.   futuref)r6   r   r   r   W   s    
z'_patch_loop.<locals>.run_until_completec                 S   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 ]"}|s q| }|js|  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   r2   minmaxZ_whentime	_selectorselectZ_process_eventsZ_clock_resolutionappendrangelenpopleftZ_run)r.   readyZ	scheduledtimeoutZ
event_listZend_timehandle_r   r   r   r1   e   s6    
 

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_loopovr   r   r   r6      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&   rO   _set_coroutine_origin_trackingZ
_asyncgensset_asyncgen_hooks_debugZ_asyncgen_firstiter_hookZ_asyncgen_finalizer_hook)r.   Zold_agen_hooksr   r   r   r5      s    




z%_patch_loop.<locals>.manage_asyncgensc                 S   s   dS )z2Do not throw exception if loop is already running.Nr   r3   r   r   r   _check_running   s    z#_patch_loop.<locals>._check_runningr    NzCan't patch loop of type %sr   ntr"   T)r   r%   
isinstancer	   ZBaseEventLoop
ValueErrortyper/   r7   r   r1   rU   Z_check_runnungrJ   osname
issubclassZProactorEventLooprK   r&   r'   Z_set_coroutine_wrapperrR   r    )r   r7   r   r1   rU   clsr   r4   r   r   L   s0    



r   c                     s   d fdd	} t j}t|dr$dS tjdkrl fdd} fdd	}|t j_|t j_t jj |j	| |_	n|j |j
| |_
d
|_dS )zCPatch the Task's step and enter/leave methods to make it reentrant.Nc              
      sD     | j}z| | W 5 |d kr4 | jd  n
| | j< X d S r   )getr-   pop)r   excZ	curr_task
curr_tasksZ	step_origr   r   step   s    z_patch_task.<locals>.stepr    r"   c                    s   | | < d S r   r   r   r   rb   r   r   
enter_task   s    z_patch_task.<locals>.enter_taskc                    s     | d  d S r   )r_   rd   re   r   r   
leave_task   s    z_patch_task.<locals>.leave_taskT)N)r	   r)   r%   r&   r'   r(   Z_enter_taskZ_leave_taskr+   Z_Task__stepZ_stepr    )rc   r)   rf   rg   r   ra   r   r      s     


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   rZ   r&   rL   
contextlibr   r   heapqr   r   r   r   r   r   r   r   r   r   r   <module>   s   
'{$