
    oi#                        d Z ddlm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mZ ddl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  G d d      Zy)z!Manager of subshells in a kernel.    )annotationsN)partial)Lockcurrent_thread)IOLoop   )
SocketPair)SubshellThread)SHELL_CHANNEL_THREAD_NAME)_async_in_contextc                      e Zd ZdZ	 	 	 	 	 	 ddZddZddZddZddZddZ	ddZ
dd	Zd
 ZddZddZddZddZ	 	 	 	 ddZddZddZy) SubshellManagera  A manager of subshells.

    Controls the lifetimes of subshell threads and their associated ZMQ sockets and
    streams. Runs mostly in the shell channel thread.

    Care needed with threadsafe access here.  All write access to the cache occurs in
    the shell channel thread so there is only ever one write access at any one time.
    Reading of cache information can be performed by other threads, so all reads are
    protected by a lock so that they are atomic.

    Sending reply messages via the shell_socket is wrapped by another lock to protect
    against multiple subshells attempting to send at the same time.

    .. versionadded:: 7
    c                   t               | _        || _        || _        || _        i | _        t               | _        t        | j                  d      | _	        | j                  j                  | j                  | j                  d       t        | j                  d      | _        t        | j                  d      | _        | j                  j                  | j                  | j                         y)z Initialize the subshell manager.controlT)copymainzmain-reverseN)r   _parent_thread_context_shell_channel_io_loop_shell_socket_cacher   _lock_cacher	   control_to_shell_channelon_recv_process_control_request_shell_channel_to_main_main_to_shell_channel_send_on_shell_channel)selfcontextshell_channel_io_loopshell_sockets       b/home/ubuntu/docker-apps/notebooks/venv/lib/python3.12/site-packages/ipykernel/subshell_manager.py__init__zSubshellManager.__init__&   s     -.,3&;#)136 )34==)(L%%%--'')F)FT 	. 	
 '1&G# '1&O###++'')D)D	
    c                   t               j                  t        k(  sJ | j                  5  	 	 | j                  j                         \  }}| j                  |       0# t        $ r Y nw xY w	 ddd       n# 1 sw Y   nxY w| j                  j                          | j                  j                          | j                  j                          y)z+Stop all subshells and close all resources.N)r   namer   r   r   popitemKeyError_stop_subshellr   closer   r   )r   _subshell_threads      r#   r+   zSubshellManager.closeG   s    $$(AAAA 	5)-)<)<)>&A ##O4    	5 	5 	5 	%%++-##))+##))+s.   A5A
A5	A(%A5'A((A55A>c                    || j                   S | j                  5  | j                  |   j                  cddd       S # 1 sw Y   yxY w)zzReturn the inproc socket pair used to send messages from the shell channel
        to a particular subshell or main shell.N)r   r   r   shell_channel_to_subshellr   subshell_ids     r#   "get_shell_channel_to_subshell_pairz2SubshellManager.get_shell_channel_to_subshell_pairV   sJ     ... 	F;;{+EE	F 	F 	Fs	   >Ac                    || j                   j                  S | j                  5  | j                  |   j                  j                  cddd       S # 1 sw Y   yxY w)zuReturn the socket used by a particular subshell or main shell to send
        messages to the shell channel.
        N)r   from_socketr   r   subshell_to_shell_channelr0   s     r#   $get_subshell_to_shell_channel_socketz4SubshellManager.get_subshell_to_shell_channel_socket^   sV     ..::: 	R;;{+EEQQ	R 	R 	Rs   #AAc                8    | j                  |      j                  S )zuReturn the socket used by the shell channel to send messages to a particular
        subshell or main shell.
        )r2   r4   r0   s     r#   $get_shell_channel_to_subshell_socketz4SubshellManager.get_shell_channel_to_subshell_socketg   s     66{COOOr%   c                x    | j                   5  | j                  |   j                  cddd       S # 1 sw Y   yxY w)z8Get the boolean aborting flag of the specified subshell.Nr   r   abortingr0   s     r#   get_subshell_abortingz%SubshellManager.get_subshell_abortingm   s2     	5;;{+44	5 	5 	5   09c                x    | j                   5  | j                  |   j                  cddd       S # 1 sw Y   yxY w)z<Return the asyncio lock belonging to the specified subshell.N)r   r   asyncio_lockr0   s     r#   get_subshell_asyncio_lockz)SubshellManager.get_subshell_asyncio_lockr   s2     	9;;{+88	9 	9 	9r=   c                p    | j                   5  t        | j                        cddd       S # 1 sw Y   yxY w)zkReturn list of current subshell ids.

        Can be called by any subshell using %subshell magic.
        N)r   listr   )r   s    r#   list_subshellzSubshellManager.list_subshellw   s.    
  	%$	% 	% 	%s   ,5c           	         t               | j                  k(  sJ || _        | j                  j	                  t        j                         t        t        |d                   y)zSet the callback used by the main shell and all subshells to receive
        messages sent from the shell channel thread.
        N)	r   r   _on_recv_callbackr   r   r   currentr   r   )r   on_recv_callbacks     r#   set_on_recv_callbackz$SubshellManager.set_on_recv_callback   sQ     4#6#6666!1##++NN/8H$0OP	
r%   c                n    | j                   5  || j                  |   _        ddd       y# 1 sw Y   yxY w)z0Set the aborting flag of the specified subshell.Nr:   )r   r1   r;   s      r#   set_subshell_abortingz%SubshellManager.set_subshell_aborting   s1     	908DKK$-	9 	9 	9s   +4c                   | j                   5  || j                  j                  k(  r
	 ddd       y| j                  j	                         D ]!  \  }}|j                  |k(  s|c cddd       S  d|d}t        |      # 1 sw Y   yxY w)zReturn subshell_id of the specified thread_id.

        Raises RuntimeError if thread_id is not the main shell or a subshell.

        Only used by %subshell magic so does not have to be fast/cached.
        Nz
Thread id z1 does not correspond to a subshell of this kernel)r   r   identr   itemsRuntimeError)r   	thread_ididsubshellmsgs        r#   subshell_id_from_thread_idz*SubshellManager.subshell_id_from_thread_id   s      	$D//555	$ 	$ !% 1 1 3 H>>Y.I	$ 	$ ym+\]Cs##	$ 	$s   B /B !B .B  B	c           	     ,   t               j                  t        k(  sJ t        t	        j
                               }t        || j                        }| j                  5  || j                  vsJ || j                  |<   ddd       |j                  j                  |j                  t        t        | j                  |                   |j                   j                  | j"                  | j$                         |j'                          |S # 1 sw Y   xY w)z'Create and start a new subshell thread.N)r   r'   r   struuiduuid4r
   r   r   r   r/   r   io_loopr   r   rE   r5   r   r   start)r   r1   r-   s      r#   _create_subshellz SubshellManager._create_subshell   s    $$(AAAA$**,'(dmmD 	7dkk111'6DKK$	7 	1199##gd&<&<kJK	

 	1199'')D)D	
 		7 	7s    D

Dc                    t               j                  t        k(  sJ | j                  5  | j                  j                  |      }ddd       | j                         y# 1 sw Y   xY w)zjDelete subshell identified by subshell_id.

        Raises key error if subshell_id not in cache.
        N)r   r'   r   r   r   popr*   )r   r1   subshell_threwads      r#   _delete_subshellz SubshellManager._delete_subshell   s^    
 $$(AAAA 	<#{{{;	< 	,-	< 	<s   A  A)c                   t               j                  t        k(  sJ 	 t        j                  |d         }|d   }ddi}|dk(  r| j                         |d<   nE|dk(  r|d   }| j                  |       n)|dk(  r| j                         |d<   nd	|}t        |      | j                  j                  j                  |       y# t        $ r}d
t        |      d}Y d}~Bd}~ww xY w)zProcess a control request message received on the control inproc
        socket and return the reply.  Runs in the shell channel thread.
        r   typestatusokcreater1   deleterB   zUnrecognised message type error)ra   evalueN)r   r'   r   jsonloadsrZ   r^   rC   rN   BaseExceptionrU   r   	to_socket	send_json)r   requestdecodedr`   replyr1   rR   errs           r#   r   z(SubshellManager._process_control_request   s     $$(AAAA	jj,G6?D'/&6Ex'+'<'<'>m$!%m4%%k2'+'9'9';m$24(;"3'' 	%%//99%@  	!c(E	s   A?C 	C%C  C%c                t    t               j                  t        k(  sJ | j                  j	                  |       y )N)r   r'   r   r   send_multipart)r   rR   s     r#   r   z&SubshellManager._send_on_shell_channel   s.    $$(AAAA))#.r%   c                    t               j                  t        k(  sJ |j                         r!|j	                          |j                          yy)z6Stop a subshell thread and close all of its resources.N)r   r'   r   is_alivestopjoin)r   r-   s     r#   r*   zSubshellManager._stop_subshell   sC    $$(AAAA##%  "  " &r%   N)r    zzmq.Context[t.Any]r!   r   r"   zmq.Socket[t.Any])returnNone)r1   
str | Nonerw   r	   )r1   ry   rw   rv   )r1   rU   rw   bool)r1   rU   rw   zasyncio.Lock)rw   z	list[str])r1   rU   r;   rz   rw   rx   )rO   intrw   ry   )rw   rU   )r1   rU   rw   rx   )rl   zlist[t.Any]rw   rx   )r-   r
   rw   rx   )__name__
__module____qualname____doc__r$   r+   r2   r6   r8   r<   r@   rC   rH   rJ   rS   rZ   r^   r   r   r*    r%   r#   r   r      s     
#
  &
 (	
B,FRP5
9
%
9
$ .
.AA 
AB/#r%   r   )r   
__future__r   asynciorg   typingtrV   	functoolsr   	threadingr   r   zmqtornado.ioloopr   socket_pairr	   rQ   r
   threadr   utilsr   r   r   r%   r#   <module>r      s;    ' "      * 
 ! # $ - $W# W#r%   