a
    zha(                     @   s   d Z ddlZddlZddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlmZ ddlZddlmZmZ ddlmZmZ dd	 ZdddZG dd deZG dd dZdS )z}
In addition to the remote_call mechanism implemented in CommBase:
 - Implements _wait_reply, so blocking calls can be made.
    N)get_ipython)	localhost)ioloop)CommBase	CommError)TimeoutErrorPY2c                  C   sB   t   } | t jt jd | t df |  d }|   |S )z&Find a free port on the local machine.s           r      )socketZ
setsockoptZ
SOL_SOCKETZ	SO_LINGERZbindr   Zgetsocknameclose)ZsockZport r   @lib/python3.9/site-packages/spyder_kernels/comms/frontendcomm.pyget_free_port   s    r   Tc                 C   s*   t  jj stdt  jj| d|dS )zf
    Send a request to the frontend.

    If blocking is True, The return value will be returned.
    z%Can't make a request to a closed commF)blockingZ	broadcasttimeout)r   kernelZfrontend_commZis_openr   Zfrontend_call)r   r   r   r   r   frontend_request&   s    r   c                       s   e Zd ZdZ fddZd% fdd	Z fddZd	d
 Zdd Zdd Z	d& fdd	Z
d'ddZd(ddZdd Z fddZdd Zdd Zdd  Z fd!d"Z fd#d$Z  ZS ))FrontendCommz(Mixin to implement the spyder_shell_api.c                    s   t t  |_jjjj d _	dj
 t _jjrt _jtj_dj_t _jjjj_ttdrdj_t _tjjd_j  t sjjj!  fdd}|jj_!d S )N_send_comm_configi  ZROUTER_HANDOVERr	   )targetc                      s         dS )zClose comm_socket_thread.N)close_threadr   Zparent_closeselfr   r   r   _   s    z$FrontendComm.__init__.<locals>.close)"superr   __init__r   Zcomm_managerZregister_targetZ
_comm_name
_comm_open	comm_portZregister_call_handlerr   	threadingZLock	comm_lockparentzmqZContextcontextr
   ZROUTERcomm_socketZlingerr   Z_bind_sockethasattrZrouter_handoverZEventcomm_thread_closeZThreadpoll_threadcomm_socket_threadstartr   r   )r   r   r   	__class__r   r   r   8   s6    





zFrontendComm.__init__Nc                    s:   | j   tt| |W  d   S 1 s,0    Y  dS )z)Close the comm and notify the other side.N)r   r   r   r   )r   comm_idr(   r   r   r   f   s    zFrontendComm.closec                    s@   | j & tt| j|i |W  d   S 1 s20    Y  dS )z*Publish custom messages to the other side.N)r   r   r   _send_message)r   argskwargsr(   r   r   r+   k   s    zFrontendComm._send_messagec                 C   s,   | j   | j  | j  | j  dS )Close comm.N)r$   setr"   r   r!   Ztermr&   joinr   r   r   r   r   p   s    


zFrontendComm.close_threadc                 C   s(   t st   | j s$|   qdS )z"Receive messages from comm socket.N)r   r   ZIOLoopZ
initializer$   Zis_setpoll_oner1   r   r   r   r%   w   s    
zFrontendComm.poll_threadc              
   C   s  d}| j jr| j jd }z| j j| jd\}}W n< tjjyJ   Y dS  tyn   | j j	j
ddd Y dS 0 |d d }|dkr| j  | | dS | j j|d}|du r| j j	
d	| nz\tsddl}t|d
drtjd dk r |||| n||||| n|||| W nN tyJ } zW Y d}~dS d}~0  typ   | j j	jddd Y dS 0 tj  tj  |r|tj dS )z%Receive one message from comm socket.Nr   zInvalid Message:T)exc_infoheadermsg_typeZshutdown_requestzUnknown message type: %rrunF6zException in message handler:)r   Zshell_streamsZsessionZrecvr"   r    errorZContextTerminated	ExceptionlogZwarningr$   r/   _comm_closeZshell_handlersgetr   asynciogetattr	ipykernel__version__r6   
ValueErrorsysstdoutflushstderrZPOLLOUT)r   Z
out_streamZidentmsgr5   Zhandlerr=   er   r   r   r2      sL    




zFrontendComm.poll_oneFc                    s   t t| j||||dS )zGet a handler for remote calls.)r   r*   callbackr   )r   r   remote_call)r   r*   r   rH   r   r(   r   r   rI      s    
zFrontendComm.remote_callc                 C   s\   | r
dS t   }| sX|dur4t   || kr4dS t | ju rL|   qt d qdS )z6Wait until condition is met. Returns False if timeout.TNFg{Gz?)timer   Zcurrent_threadr&   r2   sleep)r   Z	conditionr   Zt_startr   r   r   
wait_until   s    
zFrontendComm.wait_untilTc                    sB    fdd} |s>|r0 ||d dS td|dS )z-Wait until the frontend replies to a request.c                      s
    j v S )zThe reply is there!)Z_reply_inboxr   call_idr   r   r   reply_received   s    z0FrontendComm._wait_reply.<locals>.reply_receivedFNz%Timeout while waiting for '{}' reply.)rL   _wait_replyr   format)r   rN   	call_namer   ZretryrO   r   rM   r   rP      s    
zFrontendComm._wait_replyc                 C   s4   |j | _| | | |d d d  |   dS )z%
        A new comm is open!
        contentdataZpickle_protocolN)r*   Zcalling_comm_id_register_comm_set_pickle_protocolr   )r   commrF   r   r   r   r      s    
zFrontendComm._comm_openc                    s   | j |d< tt| |S )zA message is about to be sentr   )r   r   r   on_outgoing_call)r   Z	call_dictr(   r   r   rX      s    
zFrontendComm.on_outgoing_callc                 C   s$   |   | j |   tj dS )z%Send the comm config to the frontend.N)rI   Z_set_comm_portr   rV   pickleZHIGHEST_PROTOCOLr1   r   r   r   r      s    zFrontendComm._send_comm_configc                 C   s   |d d }|  | dS )r.   rS   r*   N)r   )r   rF   r*   r   r   r   r;      s    zFrontendComm._comm_closec                 C   s   |   | dS )zK
        Send an async error back to the frontend to be displayed.
        N)rI   _async_error)r   Zerror_wrapperr   r   r   rZ      s    zFrontendComm._async_errorc                    s&    fdd}| _ tt|   dS )z3
        Remove side effect ipykernel has.
        c                    s    j r  |  dS )zHandle a comm_msg messageN)Z_msg_callback)rF   rW   r   r   
handle_msg  s    z/FrontendComm._register_comm.<locals>.handle_msgN)r\   r   r   rU   )r   rW   r\   r(   r[   r   rU      s    zFrontendComm._register_commc                    sj   t jj}t jj}t||t j_t||t j_z&tt| |||W |t j_|t j_S |t j_|t j_0 dS )z/Call the callback function for the remote call.N)rB   rC   writerE   WriteWrapperr   r   _remote_callback)r   rR   Z	call_argsZcall_kwargsZsaved_stdout_writeZsaved_stderr_writer(   r   r   r_     s    
  zFrontendComm._remote_callback)N)NFNN)N)T)__name__
__module____qualname____doc__r   r   r+   r   r%   r2   rI   rL   rP   r   rX   r   r;   rZ   rU   r_   __classcell__r   r   r(   r   r   5   s&   .7  	

	r   c                   @   s    e Zd ZdZdd Zdd ZdS )r^   z*Wrapper to warn user when text is printed.c                 C   s   || _ || _d| _d S )NF)_write_name_warning_shown)r   r]   namer   r   r   r     s    zWriteWrapper.__init__c                 C   s.   | j s$d| _ | dt| j d  | |S )zPrint warning once.Tz
Output from spyder call z:
)rg   re   reprrf   )r   stringr   r   r   __call__  s    zWriteWrapper.__call__N)r`   ra   rb   rc   r   rk   r   r   r   r   r^     s   r^   )TN)rc   rY   r
   rB   r   rJ   r?   ZIPython.core.getipythonr   Zjupyter_client.localinterfacesr   Ztornador   r    Zspyder_kernels.comms.commbaser   r   Zspyder_kernels.py3compatr   r   r   r   r   r^   r   r   r   r   <module>   s"   

 b