B
    3¢\ôO  ã               @   s  d Z ddlZddlZddlmZ ddlmZmZ ddlm	Z	 ddl
mZ ddlmZ ddlm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 G dd„ deƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZdZdZ defde efdee f efde efgZ!dS )z®Tornado handlers for kernels.

Preliminary documentation at https://github.com/ipython/ipython/wiki/IPEP-16%3A-Notebook-multi-directory-dashboard-and-URL-mapping#kernels-api
é    N)Údedent)ÚgenÚweb)ÚFuture)ÚIOLoop)Údate_default)Úcast_unicode)Úurl_path_joinÚ
url_escapeé   )Ú
APIHandler)ÚAuthenticatedZMQStreamHandlerÚdeserialize_binary_message)Úprotocol_versionc               @   s4   e Zd Zejejdd„ ƒƒZejejdd„ ƒƒZdS )ÚMainKernelHandlerc             c   s.   | j }t | ¡ ¡V }|  tj|td¡ d S )N)Údefault)Úkernel_managerr   Úmaybe_futureZlist_kernelsÚfinishÚjsonÚdumpsr   )ÚselfÚkmÚkernels© r   úAlib/python3.7/site-packages/notebook/services/kernels/handlers.pyÚget   s    zMainKernelHandler.getc             c   s”   | j }|  ¡ }|d kr"d|ji}n| d|j¡ t |j|d d¡V }| |¡}t| j	ddt
|ƒƒ}|  d|¡ |  d¡ |  tj|td¡ d S )NÚname)Zkernel_nameZapir   ZLocationéÉ   )r   )r   Zget_json_bodyZdefault_kernel_nameÚ
setdefaultr   r   Zstart_kernelÚkernel_modelr	   Zbase_urlr
   Z
set_headerÚ
set_statusr   r   r   r   )r   r   ÚmodelÚ	kernel_idÚlocationr   r   r   Úpost#   s    

zMainKernelHandler.postN)	Ú__name__Ú
__module__Ú__qualname__r   Úauthenticatedr   Ú	coroutiner   r%   r   r   r   r   r      s   r   c               @   s.   e Zd Zejdd„ ƒZejejdd„ ƒƒZdS )ÚKernelHandlerc             C   s2   | j }| |¡ | |¡}|  tj|td¡ d S )N)r   )r   Z_check_kernel_idr    r   r   r   r   )r   r#   r   r"   r   r   r   r   9   s    

zKernelHandler.getc             c   s.   | j }t | |¡¡V  |  d¡ |  ¡  d S )NéÌ   )r   r   r   Zshutdown_kernelr!   r   )r   r#   r   r   r   r   Údelete@   s    
zKernelHandler.deleteN)	r&   r'   r(   r   r)   r   r   r*   r-   r   r   r   r   r+   7   s   r+   c               @   s    e Zd Zejejdd„ ƒƒZdS )ÚKernelActionHandlerc          
   c   s¨   | j }|dkr"| |¡ |  d¡ |dkrœyt | |¡¡V  W n< tk
r| } z| jjddd |  d¡ W d d }~X Y n X | 	|¡}|  
tj|td¡ |  ¡  d S )	NZ	interruptr,   ZrestartzException restarting kernelT)Úexc_infoiô  )r   )r   Zinterrupt_kernelr!   r   r   Zrestart_kernelÚ	ExceptionÚlogÚerrorr    Úwriter   r   r   r   )r   r#   Úactionr   Úer"   r   r   r   r%   K   s    


zKernelActionHandler.postN)r&   r'   r(   r   r)   r   r*   r%   r   r   r   r   r.   I   s   r.   c                   sú   e Zd ZdZi Zedd„ ƒZedd„ ƒZedd„ ƒZedd	„ ƒZ	d
d„ Z
dd„ Zdd„ Zdd„ Zdd„ Z‡ fdd„Zej‡ fdd„ƒZej‡ fdd„ƒZejdd„ ƒZ‡ fdd„Zdd„ Z‡ fd d!„Z‡ fd"d#„Zd$d%„ Zd&d'„ Zd(d)„ Zd*d+„ Z‡  ZS ),ÚZMQChannelsHandlerz]There is one ZMQChannelsHandler per running kernel and it oversees all
    the sessions.
    c             C   s   | j j}| j d|¡S )NÚkernel_info_timeout)r   r7   Úsettingsr   )r   Z
km_defaultr   r   r   r7   i   s    z&ZMQChannelsHandler.kernel_info_timeoutc             C   s   | j  dd¡S )NÚiopub_msg_rate_limitr   )r8   r   )r   r   r   r   r9   n   s    z'ZMQChannelsHandler.iopub_msg_rate_limitc             C   s   | j  dd¡S )NÚiopub_data_rate_limitr   )r8   r   )r   r   r   r   r:   r   s    z(ZMQChannelsHandler.iopub_data_rate_limitc             C   s   | j  dd¡S )NÚrate_limit_windowg      ð?)r8   r   )r   r   r   r   r;   v   s    z$ZMQChannelsHandler.rate_limit_windowc             C   s   d| j jt| ddƒf S )Nz%s(%s)r#   Zuninitialized)Ú	__class__r&   Úgetattr)r   r   r   r   Ú__repr__z   s    zZMQChannelsHandler.__repr__c             C   sL   | j }| jj}x8dD ]0}t|d| ƒ}|| j|d | j|< }||_qW d S )N)ÚshellÚiopubÚstdinZconnect_)Úidentity)r   ÚsessionZbsessionr=   r#   ÚchannelsÚchannel)r   r   rB   rE   ÚmethÚstreamr   r   r   Úcreate_stream}   s    
z ZMQChannelsHandler.create_streamc                s¬   ˆ j }| ˆ j¡}y
|j}W nb tk
r~   ˆ j dˆ j¡ ˆ jdkrT| ˆ j¡ˆ _ˆ j 	ˆ j
¡ ˆ j ˆ jd¡ ˆ j|_Y n(X | ¡ s”ˆ j d¡ | ‡ fdd„¡ ˆ jS )zsend a request for kernel_infozRequesting kernel info from %sNZkernel_info_requestz'Waiting for pending kernel_info requestc                s   ˆ   |  ¡ ¡S )N)Ú_finish_kernel_infoÚresult)Úf)r   r   r   Ú<lambda>™   ó    z8ZMQChannelsHandler.request_kernel_info.<locals>.<lambda>)r   Ú
get_kernelr#   Ú_kernel_info_futureÚAttributeErrorr1   ÚdebugÚkernel_info_channelZconnect_shellÚon_recvÚ_handle_kernel_info_replyrC   ÚsendÚdoneZadd_done_callback)r   r   ÚkernelÚfuturer   )r   r   Úrequest_kernel_info…   s    

z&ZMQChannelsHandler.request_kernel_infoc             C   s¨   | j  |¡\}}y| j  |¡}W n&   | jjddd | j i ¡ dS |d }| j d|¡ |d dksrd	|kr„| j d
|¡ i }|  |¡ | j	rž| j	 
¡  d| _	dS )zbprocess the kernel_info_reply
        
        enabling msg spec adaptation, if necessary
        zBad kernel_info replyT)r/   NÚcontentzReceived kernel info: %sÚmsg_typeZkernel_info_replyr   z/Kernel info request failed, assuming current %s)rC   Úfeed_identitiesÚdeserializer1   r2   rO   Ú
set_resultrQ   rI   rR   Úclose)r   ÚmsgÚidentsÚinfor   r   r   rT   œ   s     

z,ZMQChannelsHandler._handle_kernel_info_replyc             C   sV   |  dt¡}|tkr<t| d¡d ƒ| j_| j d|| j¡ | j	 
¡ sR| j	 |¡ dS )z“Finish handling kernel_info reply
        
        Set up protocol adaptation, if needed,
        and signal that connection can continue.
        r   Ú.r   z&Adapting to protocol v%s for kernel %sN)r   Úclient_protocol_versionÚintÚsplitrC   Zadapt_versionr1   rb   r#   rO   rV   r^   )r   rb   r   r   r   r   rI   µ   s    
z&ZMQChannelsHandler._finish_kernel_infoc                s^   t t| ƒ ¡  d | _i | _d | _d | _tƒ | _tƒ | _	d| _
d| _d| _d| _d| _g | _d S )NÚ r   F)Úsuperr6   Ú
initializeZ
zmq_streamrD   r#   rR   r   rO   Ú_close_futureÚsession_keyÚ_iopub_window_msg_countÚ_iopub_window_byte_countÚ_iopub_msgs_exceededÚ_iopub_data_exceededÚ_iopub_window_byte_queue)r   )r<   r   r   ri   Â   s    zZMQChannelsHandler.initializec             #   sp   t tˆƒ ¡  ˆ ¡ V  ˆj ˆj¡}|jjˆj_ˆ 	¡ ‰ ‡ ‡fdd„}t
 ¡ }| | ¡ ˆj |¡ ˆ V  d S )Nc                  s*   ˆ   ¡ rdS ˆj dˆj¡ ˆ  i ¡ dS )z*Don't wait forever for the kernel to replyNz-Timeout waiting for kernel_info reply from %s)rV   r1   Úwarningr#   r^   r   )rX   r   r   r   Úgive_upã   s    z+ZMQChannelsHandler.pre_get.<locals>.give_up)rh   r6   Úpre_getÚ_register_sessionr   rN   r#   rC   ÚkeyrY   r   ÚcurrentZadd_timeoutÚtimer7   )r   rW   rr   Zloop)r<   )rX   r   r   rs   Ö   s    
zZMQChannelsHandler.pre_getc             #   s$   t |dƒ| _tt| ƒj|dV  d S )NÚascii)r#   )r   r#   rh   r6   r   )r   r#   )r<   r   r   r   î   s    zZMQChannelsHandler.getc             c   sP   d| j | jjf | _| j | j¡}|r@| j d| j¡ | ¡ V  | | j| j< dS )a+  Ensure we aren't creating a duplicate session.
        
        If a previous identical session is still open, close it to avoid collisions.
        This is likely due to a client reconnecting from a lost network connection,
        where the socket on our side has not been cleaned up yet.
        z%s:%szReplacing stale connection: %sN)r#   rC   rk   Ú_open_sessionsr   r1   rq   r_   )r   Zstale_handlerr   r   r   rt   ó   s    
z$ZMQChannelsHandler._register_sessionc       	   
      s^  t t| ƒ ¡  | j}| |¡ | || j¡}|r |d | jkr | j d| j¡ |d | _	|d }|rž| j dt
|ƒ¡ xš|D ]\}}| j	| }|  ||¡ q|W nry|  ¡  W nd tjk
r } zB| j d|¡ x&| j	 ¡ D ]\}}| ¡ sÜ| ¡  qÜW |  ¡  d S d }~X Y nX | | j| j¡ | | j| jd¡ x$| j	 ¡ D ]\}}| | j¡ q@W d S )Nrk   zRestoring connection for %srD   ÚbufferzReplaying %s buffered messageszError opening stream: %sÚdead)rh   r6   Úopenr   Znotify_connectZ
get_bufferrk   r1   rb   rD   ÚlenÚ_on_zmq_replyrH   r   Z	HTTPErrorr2   ÚitemsÚclosedr_   Zadd_restart_callbackr#   Úon_kernel_restartedÚon_restart_failedZon_recv_stream)	r   r#   r   Zbuffer_infoZreplay_bufferrE   Úmsg_listrG   r5   )r<   r   r   r|     s4    


zZMQChannelsHandler.openc             C   s”   | j s| j d|¡ d S t|tƒr,t|ƒ}n
t |¡}| dd ¡}|d kr\| j 	d|¡ d}|| j krx| j 	d|¡ d S | j | }| j
 ||¡ d S )Nz'Received message on closed websocket %rrE   z(No channel specified, assuming shell: %sr?   zNo such channel: %r)rD   r1   rQ   Ú
isinstanceÚbytesr   r   ÚloadsÚpoprq   rC   rU   )r   r`   rE   rG   r   r   r   Ú
on_message%  s    




zZMQChannelsHandler.on_messagec                sª  ˆj  |¡\}}ˆj  |¡}|d ‰ ‡ ‡fdd„}t|dd ƒ}|d d }|dkrŠ|dkrŠ|d	  d
¡dkrŠg ˆ_dˆ_dˆ_dˆ_dˆ_	|dkr”|dkr”t
 ¡  ¡ }	xTtˆjƒdkrþˆjd }
|	|
d krúˆ j|
d 8  _ˆ jd8  _ˆjd= q¬P q¬W ˆ jd7  _|dkr,tdd„ |D ƒƒ}nd}ˆ j|7  _ˆj |	ˆj |f¡ tˆjƒˆj }tˆjƒˆj }ˆjdkr´|ˆjkr´ˆjsædˆ_|td ˆjˆj¡ƒƒ n2ˆjræ|dˆj k rædˆ_ˆj	sæˆj d¡ ˆjdkr&|ˆjkr&ˆj	sXdˆ_	|td ˆjˆj¡ƒƒ n2ˆj	rX|dˆj k rXdˆ_	ˆjsXˆj d¡ ˆjshˆj	r”ˆ jd8  _ˆ j|8  _ˆj d¡ d S ttˆƒ ||¡ d S )NZparent_headerc                sH   ˆj  | ¡ ˆjjd| d ddœˆ d}d|d< ˆ tj|td¡ d S )	NrG   Ú
Ústderr)Útextr   )rZ   Úparentr@   rE   )r   )r1   rq   rC   r`   Úwrite_messager   r   r   )Zerror_messager`   )rŒ   r   r   r   Úwrite_stderr<  s    z6ZMQChannelsHandler._on_zmq_reply.<locals>.write_stderrrE   Úheaderr[   r@   ÚstatusrZ   Úexecution_stateZidler   F>   Ú	comm_openr   Úexecute_inputé   rG   c             S   s   g | ]}t |ƒ‘qS r   )r}   )Ú.0Úxr   r   r   ú
<listcomp>b  s    z4ZMQChannelsHandler._on_zmq_reply.<locals>.<listcomp>Ta                      IOPub message rate exceeded.
                    The notebook server will temporarily stop sending output
                    to the client in order to avoid crashing it.
                    To change this limit, set the config variable
                    `--NotebookApp.iopub_msg_rate_limit`.
                    
                    Current values:
                    NotebookApp.iopub_msg_rate_limit={} (msgs/sec)
                    NotebookApp.rate_limit_window={} (secs)
                    gš™™™™™é?ziopub messages resumeda                      IOPub data rate exceeded.
                    The notebook server will temporarily stop sending output
                    to the client in order to avoid crashing it.
                    To change this limit, set the config variable
                    `--NotebookApp.iopub_data_rate_limit`.
                    
                    Current values:
                    NotebookApp.iopub_data_rate_limit={} (bytes/sec)
                    NotebookApp.rate_limit_window={} (secs)
                    éÿÿÿÿ)rC   r\   r]   r=   r   rp   rl   rm   rn   ro   r   rv   rw   r}   ÚsumÚappendr;   Úfloatr9   r   Úformatr1   rq   r:   r‡   rh   r6   r~   )r   rG   rƒ   ra   Zfed_msg_listr`   rŽ   rE   r[   ZnowZqueuedZ
byte_countZmsg_rateZ	data_rate)r<   )rŒ   r   r   r~   8  sj    "




z ZMQChannelsHandler._on_zmq_replyc                s   t t| ƒ ¡  | jS )N)rh   r6   r_   rj   )r   )r<   r   r   r_   ¥  s    zZMQChannelsHandler.closec             C   sò   | j  d| j¡ | j | j¡| kr0| j | j¡ | j}| j|kr¢| | j¡ | 	| j| j
¡ | 	| j| jd¡ |j| j dkr¢| | j| j| j¡ | j d ¡ d S x8| j ¡ D ]*\}}|d k	r®| ¡ s®| d ¡ | ¡  q®W i | _| j d ¡ d S )NzWebsocket closed %sr{   r   )r1   rQ   rk   ry   r   r‡   r   r#   Znotify_disconnectZremove_restart_callbackr   r‚   Z_kernel_connectionsZstart_bufferingrD   rj   r^   r   r€   rS   r_   )r   r   rE   rG   r   r   r   Úon_close©  s(    

zZMQChannelsHandler.on_closec             C   sT   | j  dd ¡}|r"| ¡ s"| ¡  | j dd|i¡}d|d< |  tj|t	d¡ d S )Nr@   r   r‘   rE   )r   )
rD   r   r€   ÚflushrC   r`   r   r   r   r   )r   r   r@   r`   r   r   r   Ú_send_status_messageÊ  s    
z'ZMQChannelsHandler._send_status_messagec             C   s   t  d| j¡ |  d¡ d S )Nzkernel %s restartedZ
restarting)ÚloggingÚwarnr#   rŸ   )r   r   r   r   r   ×  s    z&ZMQChannelsHandler.on_kernel_restartedc             C   s   t  d| j¡ |  d¡ d S )Nzkernel %s restarted failed!r{   )r    r2   r#   rŸ   )r   r   r   r   r‚   Û  s    z$ZMQChannelsHandler.on_restart_failed)r&   r'   r(   Ú__doc__ry   Úpropertyr7   r9   r:   r;   r>   rH   rY   rT   rI   ri   r   r*   rs   r   rt   r|   rˆ   r~   r_   r   rŸ   r   r‚   Ú__classcell__r   r   )r<   r   r6   _   s.   #m!r6   z"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)z(?P<action>restart|interrupt)z/api/kernelsz/api/kernels/%sz/api/kernels/%s/%sz/api/kernels/%s/channels)"r¢   r   r    Útextwrapr   Ztornador   r   Ztornado.concurrentr   Ztornado.ioloopr   Zjupyter_client.jsonutilr   Zipython_genutils.py3compatr   Znotebook.utilsr	   r
   Zbase.handlersr   Zbase.zmqhandlersr   r   Zjupyter_clientr   rd   r   r+   r.   r6   Z_kernel_id_regexZ_kernel_action_regexZdefault_handlersr   r   r   r   Ú<module>   s2      	
