
    ^hp#                        S r SSKJr  SSKrSSKrSSKrSSKrSSKJ	r	  SSK
JrJrJr  SSKrSSKJr  SSKJr  SS	KJr  SS
KJr   " S S5      rg)z!Manager of subshells in a kernel.    )annotationsN)partial)Lockcurrent_threadmain_thread)IOLoop   )
SocketPair)SubshellThread)SHELL_CHANNEL_THREAD_NAMEc                      \ rS rSrSr      SS jrSS jrSS jrSS jrSS jr	SS jr
SS	 jrSS
 jrS rSS jrSS jrSS jrSS jr    S S jrSS jrS!S jrSrg)"SubshellManager   ae  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                   [        5       [        5       :X  d   eXl        X l        X0l        0 U l        [        5       U l        [        U R                  S5      U l	        U R                  R                  U R                  U R                  SS9  [        U R                  S5      U l        [        U R                  S5      U l        U R                  R                  U R                  U R                  5        g)z Initialize the subshell manager.controlT)copymainzmain-reverseN)r   r   _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       T/home/james-whalen/.local/lib/python3.13/site-packages/ipykernel/subshell_manager.py__init__SubshellManager.__init__%   s     ;=000,3&;#)136 )34==)(L%%%--'')F)FT 	. 	
 '1&G# '1&O###++'')D)D	
    c                   [        5       R                  [        :X  d   eU R                       U R                  R                  5       u  pU R                  U5        M0  ! [         a     Of = fSSS5        O! , (       d  f       O= fU R                  R                  5         U R                  R                  5         U R                  R                  5         g)z+Stop all subshells and close all resources.N)r   namer   r   r   popitemKeyError_stop_subshellr   closer   r   )r   _subshell_threads      r#   r,   SubshellManager.closeF   s    $$(AAAA)-)<)<)>&A ##O4    	  	%%++-##))+##))+s.   A6A
A6
A*'A6)A**A66
Bc                    Uc  U R                   $ U R                     U R                  U   R                  sSSS5        $ ! , (       d  f       g= f)zrReturn 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_pair2SubshellManager.get_shell_channel_to_subshell_pairU   s=     ...;;{+EE s	   ?
Ac                    Uc  U R                   R                  $ U R                     U R                  U   R                  R                  sSSS5        $ ! , (       d  f       g= f)zeReturn 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_channelr2   s     r#   $get_subshell_to_shell_channel_socket4SubshellManager.get_subshell_to_shell_channel_socket]   sI     ..:::;;{+EEQQ s   #A
A!c                8    U R                  U5      R                  $ )zeReturn the socket used by the shell channel to send messages to a particular
subshell or main shell.
)r4   r7   r2   s     r#   $get_shell_channel_to_subshell_socket4SubshellManager.get_shell_channel_to_subshell_socketf   s     66{COOOr&   c                    U R                      U R                  U   R                  sSSS5        $ ! , (       d  f       g= f)z8Get the boolean aborting flag of the specified subshell.Nr   r   abortingr2   s     r#   get_subshell_aborting%SubshellManager.get_subshell_abortingl   s)    ;;{+44    0
>c                    U R                      U R                  U   R                  sSSS5        $ ! , (       d  f       g= f)z<Return the asyncio lock belonging to the specified subshell.N)r   r   asyncio_lockr2   s     r#   get_subshell_asyncio_lock)SubshellManager.get_subshell_asyncio_lockq   s)    ;;{+88 rC   c                z    U R                      [        U R                  5      sSSS5        $ ! , (       d  f       g= f)z[Return list of current subshell ids.

Can be called by any subshell using %subshell magic.
N)r   listr   )r   s    r#   list_subshellSubshellManager.list_subshellv   s%    
 $ s   ,
:c                    [        5       [        5       :X  d   eXl        U R                  R	                  [
        R                  " 5       [        U R                  S5      5        g)zrSet 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   on_recv_callbacks     r#   set_on_recv_callback$SubshellManager.set_on_recv_callback~   sH     ;=000!1##++FNN,<gdF\F\^b>cdr&   c                v    U R                      X R                  U   l        SSS5        g! , (       d  f       g= f)z0Set the aborting flag of the specified subshell.Nr?   )r   r3   r@   s      r#   set_subshell_aborting%SubshellManager.set_subshell_aborting   s&    08KK$- s   *
8c                &   U R                      U[        5       R                  :X  a
   SSS5        gU R                  R	                  5        H"  u  p#UR                  U:X  d  M  Us  sSSS5        $    SU< S3n[        U5      e! , (       d  f       g= f)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_id*SubshellManager.subshell_id_from_thread_id   s     KM///  !% 1 1 3>>Y.I  !4 ym+\]Cs## s   B-B!B.B
Bc                &   [        5       R                  [        :X  d   e[        [        R
                  " 5       5      n[        XR                  5      nU R                     XR                  ;  d   eX R                  U'   SSS5        UR                  R                  UR                  [        U R                  U5      5        UR                  R                  U R                   U R"                  5        UR%                  5         U$ ! , (       d  f       N= f)z'Create and start a new subshell thread.N)r   r(   r   struuiduuid4r   r   r   r   r1   r   io_loopr   rM   r8   r   r   start)r   r3   r.   s      r#   _create_subshell SubshellManager._create_subshell   s    $$(AAAA$**,'(mmDkk111'6KK$  	1199##D**K8	

 	1199'')D)D	
 	 s    D
Dc                    [        5       R                  [        :X  d   eU R                     U R                  R                  U5      nSSS5        U R                  W5        g! , (       d  f       N = f)zZDelete subshell identified by subshell_id.

Raises key error if subshell_id not in cache.
N)r   r(   r   r   r   popr+   )r   r3   subshell_threwads      r#   _delete_subshell SubshellManager._delete_subshell   sW    
 $$(AAAA#{{{;  	,- s   A!!
A/c                   [        5       R                  [        :X  d   e [        R                  " US   5      nUS   nSS0nUS:X  a  U R                  5       US'   OHUS:X  a  US   nU R                  U5        O+US:X  a  U R                  5       US'   OS	U< 3n[        U5      eU R                  R                  R                  U5        g! [         a  nS
[        U5      S.n SnANCSnAff = f)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creater3   deleterI   zUnrecognised message type error)rn   evalueN)r   r(   r   jsonloadsre   rj   rJ   rX   BaseExceptionr`   r   	to_socket	send_json)r   requestdecodedrm   replyr3   r\   errs           r#   r   (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)   ;C
 C
 9C
 C
 

C,C''C,c                v    [        5       R                  [        :X  d   eU R                  R	                  U5        g )N)r   r(   r   r   send_multipart)r   r\   s     r#   r   &SubshellManager._send_on_shell_channel   s.    $$(AAAA))#.r&   c                    [        5       R                  [        :X  d   eUR                  5       (       a!  UR	                  5         UR                  5         gg)z6Stop a subshell thread and close all of its resources.N)r   r(   r   is_alivestopjoin)r   r.   s     r#   r+   SubshellManager._stop_subshell   sF    $$(AAAA##%%  "  " &r&   )	r   r   r   r   rM   r   r   r   r   N)r    zzmq.Context[t.Any]r!   r   r"   zmq.Socket[t.Any])returnNone)r3   
str | Noner   r
   )r3   r   r   r   )r3   r`   r   bool)r3   r`   r   zasyncio.Lock)r   z	list[str])r3   r`   r@   r   r   r   )rY   intr   r   )r   r`   )r3   r`   r   r   )ry   zlist[t.Any]r   r   )r.   r   r   r   )__name__
__module____qualname____firstlineno____doc__r$   r,   r4   r9   r<   rA   rF   rJ   rP   rS   r]   re   rj   r   r   r+   __static_attributes__ r&   r#   r   r      s     
#
  &
 (	
B,FRP5
9
%e9
$ .
.AA 
AB/#r&   r   )r   
__future__r   asynciort   typingtra   	functoolsr   	threadingr   r   r   zmqtornado.ioloopr   socket_pairr
   r[   r   threadr   r   r   r&   r#   <module>r      s;    ' "      7 7 
 ! # $ -U# U#r&   