B
    @\(                 @   s   d Z ddlmZmZmZmZ ddlZeeZ	ddl
Z
ddlmZ ddlmZ ddlZddlmZ ddlmZ d	Zejd
d ZG dd deZG dd deZdS )z$ Internal utils related to Tornado

    )absolute_importdivisionprint_functionunicode_literalsN)defaultdict)format_exception)gen   )make_id)yield_for_all_futuresc             c   sL   x<| dkrP yt | }W n t jk
r2   P Y qX |V } qW t | dS )z Converts result into a Future by collapsing any futures inside result.

    If result is a Future we yield until it's done, then if the value inside
    the Future is another Future we yield until it's done as well, and so on.
    N)r   convert_yieldedBadYieldErrorZReturn)resultfuture r   1lib/python3.7/site-packages/bokeh/util/tornado.pyr   0   s    
r   c               @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )_AsyncPeriodica  Like ioloop.PeriodicCallback except the 'func' can be async and
        return a Future, and we wait for func to finish each time
        before we call it again.  Plain ioloop.PeriodicCallback
        can "pile up" invocations if they are taking too long.

    c             C   s"   || _ || _|| _d| _d| _d S )NF)_func_loop_period_started_stopped)selffuncZperiodio_loopr   r   r   __init__X   s
    z_AsyncPeriodic.__init__c                s(   t   | j| jd  fdd  S )Ng     @@c                  s
     d S )N)Z
set_resultr   )fr   r   <lambda>c   s    z&_AsyncPeriodic.sleep.<locals>.<lambda>)r   ZFuturer   
call_laterr   )r   r   )r   r   sleepa   s    z_AsyncPeriodic.sleepc                sF   j rtdd_ fdd  fddj  d S )Nz&called start() twice on _AsyncPeriodicTc                 sT      }   }|d kr| S yt|}W n tjk
r@   | S X t| |gS d S )N)r   r   r   r   r   Zmulti)Zsleep_futurer   Zcallback_future)r   r   r   invokek   s    z$_AsyncPeriodic.start.<locals>.invokec                sh   j sj   |  }|d k	rdtd tjrDt| 	  }nt|j
||j}td| d S )Nz$Error thrown from periodic callback: )r   r   
add_futureZ	exceptionlogerrorsixZPY2r   exc_info	__class____traceback__join)r   exlines)r    on_doner   r   r   r,      s    
z%_AsyncPeriodic.start.<locals>.on_done)r   RuntimeErrorr   r"   r   )r   r   )r    r,   r   r   startf   s    z_AsyncPeriodic.startc             C   s
   d| _ d S )NT)r   )r   r   r   r   stop   s    z_AsyncPeriodic.stopN)__name__
__module____qualname____doc__r   r   r.   r/   r   r   r   r   r   P   s
   	'r   c               @   sp   e Zd ZdZdddZdd Zdd Zd	d
 Zdd ZdddZ	dd Z
dddZdd ZdddZdd ZdS )_CallbackGroupz` A collection of callbacks added to a Tornado IOLoop that we may
    want to remove as a group. Nc             C   sT   |d krt d|| _i | _i | _i | _t | _tt	| _
tt	| _tt	| _d S )Nzmust provide an io loop)
ValueErrorr   _next_tick_callback_removers_timeout_callback_removers_periodic_callback_removers	threadingZLock_removers_lockr   set_next_tick_removers_by_callable_timeout_removers_by_callable_periodic_removers_by_callable)r   r   r   r   r   r      s    


z_CallbackGroup.__init__c             C   sj   x t | j D ]}| | qW x t | j D ]}| | q2W x t | j D ]}| | qTW dS )z" Removes all registered callbacks.N)listr6   keysremove_next_tick_callbackr7   remove_timeout_callbackr8   remove_periodic_callback)r   Zcb_idr   r   r   remove_all_callbacks   s    z#_CallbackGroup.remove_all_callbacksc             C   s>   || j kr| jS || jkr | jS || jkr0| jS td|d S )NzUnhandled removers)r6   r<   r7   r=   r8   r>   r-   )r   removersr   r   r   _get_removers_ids_by_callable   s    


z,_CallbackGroup._get_removers_ids_by_callablec          	   C   s>   | j . |d krt }n||kr(td|||< |S Q R X d S )Nz?A callback of the same type has already been added with this ID)r:   r
   r5   )r   callbackcallback_idrE   removerr   r   r   _assign_remover   s    z_CallbackGroup._assign_removerc          
   C   s   yt| j d ||}xRt| | D ]<\}}y|| |sL| ||= W q( tk
rb   Y q(X q(W W d Q R X W n tk
r   tdY nX |  d S )Nz:Removing a callback twice (or after it's already been run))r:   popr?   rF   itemsremoveKeyErrorr5   )r   rH   rE   rI   cbZcb_idsr   r   r   _execute_remover   s    

z_CallbackGroup._execute_removerc                sF    fddd_ fdd} j|j S )zs Adds a callback to be run on the next tick.
        Returns an ID that can be used with remove_next_tick_callback.c                 s"   j s  | |S d S d S )N)removedrA   )argskwargs)rG   rH   r   wrapperr   r   rT      s    

z6_CallbackGroup.add_next_tick_callback.<locals>.wrapperFc                  s
   d _ d S )NT)rQ   r   )rT   r   r   rI      s    z6_CallbackGroup.add_next_tick_callback.<locals>.remover)rQ   rJ   r6   r   Zadd_callback)r   rG   rH   rI   r   )rG   rH   r   rT   r   add_next_tick_callback   s    z%_CallbackGroup.add_next_tick_callbackc             C   s   |  || j dS )z6 Removes a callback added with add_next_tick_callback.N)rP   r6   )r   rH   r   r   r   rA      s    z(_CallbackGroup.remove_next_tick_callbackc                sJ    fdd}dfdd}  j|j|d |S )z Adds a callback to be run once after timeout_milliseconds.
        Returns an ID that can be used with remove_timeout_callback.c                 s      | |S )N)rB   )rR   rS   )rG   rH   r   r   r   rT      s    
z4_CallbackGroup.add_timeout_callback.<locals>.wrapperNc                  s    d k	rj   d S )N)r   Zremove_timeoutr   )handler   r   r   rI      s    z4_CallbackGroup.add_timeout_callback.<locals>.removerg     @@)rJ   r7   r   r   )r   rG   Ztimeout_millisecondsrH   rT   rI   r   )rG   rH   rV   r   r   add_timeout_callback   s    z#_CallbackGroup.add_timeout_callbackc             C   s   |  || j dS )zD Removes a callback added with add_timeout_callback, before it runs.N)rP   r7   )r   rH   r   r   r   rB      s    z&_CallbackGroup.remove_timeout_callbackc             C   s0   t ||| jd}| ||| j|j}|  |S )z Adds a callback to be run every period_milliseconds until it is removed.
        Returns an ID that can be used with remove_periodic_callback.)r   )r   r   rJ   r8   r/   r.   )r   rG   Zperiod_millisecondsrH   rO   r   r   r   add_periodic_callback   s    z$_CallbackGroup.add_periodic_callbackc             C   s   |  || j dS )z5 Removes a callback added with add_periodic_callback.N)rP   r8   )r   rH   r   r   r   rC     s    z'_CallbackGroup.remove_periodic_callback)N)N)N)N)r0   r1   r2   r3   r   rD   rF   rJ   rP   rU   rA   rW   rB   rX   rC   r   r   r   r   r4      s   
	
	


	r4   )r3   Z
__future__r   r   r   r   ZloggingZ	getLoggerr0   r#   r9   collectionsr   	tracebackr   r%   Ztornador   Zutil.serializationr
   __all__	coroutiner   objectr   r4   r   r   r   r   <module>	   s   
 @