U
    lufIX                     @  s   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Zddl	Z	ddl
mZ ddlmZ ddlZddlmZmZmZmZmZmZmZ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%m&Z& G dd de'Z(dddddZ)G dd deZ*G dd de*Z+dS )z%A kernel manager for multiple kernels    )annotationsNwraps)Path)AnyBoolDictDottedObjectNameInstanceUnicodedefaultobserve)LoggingConfigurable)import_item   )KernelConnectionInfo)NATIVE_KERNEL_NAMEKernelSpecManager)KernelManager)ensure_asyncrun_syncutcnowc                   @  s   e Zd ZdS )DuplicateKernelErrorN)__name__
__module____qualname__ r   r   E/tmp/pip-unpacked-wheel-naub1w99/jupyter_client/multikernelmanager.pyr      s   r   
t.Callable)freturnc                   s&   t  dddddd fdd}|S )zDdecorator for proxying MKM.method(kernel_id) to individual KMs by IDt.Anystrzt.Callable | t.Awaitable)self	kernel_idargskwargsr    c                   s6   |  |}t| j}|||} | |f|| |S N)
get_kernelgetattrr   )r#   r$   r%   r&   kmmethodrr   r   r   wrapped!   s
    

zkernel_method.<locals>.wrappedr   )r   r.   r   r-   r   kernel_method   s    r/   c                      s  e Zd ZdZeeddjddZee	ddZ
edddjddZed	d
ddddZeddZedddddZddddZedddjddZedZedZe ZeddddZedddddZed Zed!ddZe Zd
d
dd" fd#d$Z dd fd%d&Z!d'dd(d)Z"d*dd+d,Z#d-d.d/d0d1Z$d2d
d3d4d5d6Z%d-d7dd8d9d:Z&d-d;d<dd=d>d?Z'd-d<dd@dAdBZ(d.ddCdDZ)d!dEd2d
d-d4dFdGZ*e+e*Z,dd-dHdHddIdJdKZ-e+e-Z.e/dd-dHddLdMdNZ0e/dd-dPdPddQdRdSZ1e/dd-d.ddLdTdUZ2d-d;d/dVdWZ3dd.ddXdYdZZ4e+e4Z5d-dd/d[d\Z6e/d-d*dd]d^d_Z7dd-d.dd`dadbZ8e+e8Z9e/d-d.d/dcddZ:d-dd/dedfZ;d-d;d/dgdhZ<e/dd-dd-ddjdkdlZ=e/dd-dd-ddjdmdnZ>e/d-dod/dpdqZ?e/dd-drdsdtdudvZ@e/dd-drdsdtdwdxZAe/dd-drdsdtdydzZBe/dd-drdsdtd{d|ZCe/dd-drdsdtd}d~ZDd
d-dddZE  ZFS )MultiKernelManagerz&A class for managing multiple kernels.z'The name of the default kernel to starthelpTconfig)
allow_nonez)jupyter_client.ioloop.IOLoopKernelManagerzThe kernel manager class.  This is configurable to allow
        subclassing of the KernelManager for customized behavior.
        kernel_manager_classr!   None)changer    c                 C  s   |   | _d S r'   )_create_kernel_manager_factorykernel_manager_factory)r#   r8   r   r   r   _kernel_manager_class_changedC   s    z0MultiKernelManager._kernel_manager_class_changedz)this is kernel_manager_class after importr:   r   r    c                 C  s   |   S r'   )r9   r#   r   r   r   _kernel_manager_factory_defaultI   s    z2MultiKernelManager._kernel_manager_factory_defaultc                   s&   t j dddd fdd}|S )Nr!   r   r%   r&   r    c                    s4   j r&jjr _|dj  | |}|S )Ncontext)shared_contextr@   closed_context_default
setdefault)r%   r&   r*   Zkernel_manager_ctorr#   r   r   create_kernel_managerP   s    

zPMultiKernelManager._create_kernel_manager_factory.<locals>.create_kernel_manager)r   r6   )r#   rF   r   rE   r   r9   M   s    
	z1MultiKernelManager._create_kernel_manager_factoryz4Share a single zmq.Context to talk to all my kernelszzmq.ContextFdictc                 C  s   | j S )z#A shim for backwards compatibility.)_pending_kernelsr=   r   r   r   _starting_kernelsf   s    z$MultiKernelManager._starting_kernelsr@   c                 C  s   d| _ t S NT)_created_contextzmqContextr=   r   r   r   rC   k   s    z#MultiKernelManager._context_default Nr?   c                   s   t  j|| i | _d S r'   )super__init__kernel_id_to_connection_file)r#   r%   r&   	__class__r   r   rP   u   s    zMultiKernelManager.__init__c                   s^   | j r2| jr2| jjs2| jr(| jd|  | j  zt j}W n tk
rR   Y nX |  dS )z:Handle garbage collection.  Destroy context if applicable.zDestroying zmq context for %sN)	rK   r@   rB   logdebugdestroyrO   __del__AttributeError)r#   Z	super_delrR   r   r   rW   y   s    
zMultiKernelManager.__del__z	list[str]c           	   	   C  sd  | j dk	rVt| j }| rVdd | D }t| j }t| j }t| j D ]*}||kr\||| }| j|= | j	|= q\|D ]}|| j krqzt
| }W n tk
r   Y qY nX | jd| d|krd|ksq|  }|| j|< | j| | jdd}|| t |_d	|_d
|_||_|d |_|jd || j	|< qt| j	 S )z6Return a list of the kernel ids of the active kernels.Nc                 S  s   g | ]}|  r|qS r   )is_file).0pr   r   r   
<listcomp>   s      z6MultiKernelManager.list_kernel_ids.<locals>.<listcomp>zLoading connection file %skernel_namekeyF)parentrT   Zowns_kernelZidler   )external_connection_dirr   is_diriterdirlistrQ   keysvaluesindex_kernelsjsonloads	read_text	ExceptionrT   rU   new_kernel_idr:   Zload_connection_infor   Zlast_activityZexecution_stateconnectionsr$   r]   readyZ
set_result)	r#   r`   Zconnection_fileskvconnection_filer$   Zconnection_infor*   r   r   r   list_kernel_ids   sN    






z"MultiKernelManager.list_kernel_idsintc                 C  s   t |  S )z%Return the number of running kernels.)lenrr   r=   r   r   r   __len__   s    zMultiKernelManager.__len__r"   bool)r$   r    c                 C  s
   || j kS r'   )rg   r#   r$   r   r   r   __contains__   s    zMultiKernelManager.__contains__z
str | Noneztuple[KernelManager, str, str])r]   r&   r    c                 C  s   | d| jf |}|| kr(td| |d kr6| j}i }| jrJ| j|d< | jf tj| j	d| | | j
|d|}|||fS )Nr$   zKernel already exists: %skernel_spec_managerzkernel-%s.json)rq   r_   rT   r]   )poprl   r   default_kernel_namery   r:   ospathjoinconnection_dirrT   )r#   r]   r&   r$   Zconstructor_kwargsr*   r   r   r   pre_start_kernel   s"    
z#MultiKernelManager.pre_start_kernelzt.Dict[str, str])r$   envr    c                C  s   || kr| j | j|d dS )z
        Allow to update the environment of the given kernel.

        Forward the update env request to the corresponding kernel.

        .. version-added: 8.5
        )r   N)rg   
update_env)r#   r$   r   r   r   r   r      s    zMultiKernelManager.update_envr   zt.Awaitable)r$   r*   kernel_awaitabler    c              
     sZ   z&|I d H  || j |< | j|d  W n. tk
rT } z| j| W 5 d }~X Y nX d S r'   )rg   rH   rz   rk   rT   	exception)r#   r$   r*   r   er   r   r   _add_kernel_when_ready   s    

z)MultiKernelManager._add_kernel_when_ready)r$   r   r    c              
     sZ   z&|I d H  |  | | j|d  W n. tk
rT } z| j| W 5 d }~X Y nX d S r'   )remove_kernelrH   rz   rk   rT   r   )r#   r$   r   r   r   r   r   _remove_kernel_when_ready   s    

z,MultiKernelManager._remove_kernel_when_readyc                 C  s   t | ddS )zReturns a boolean; a clearer method for determining if
        this multikernelmanager is using pending kernels or not
        use_pending_kernelsF)r)   r=   r   r   r   _using_pending_kernels   s    z)MultiKernelManager._using_pending_kernels)r]   c                  s   |  ||\}}}t|ts4| jdj| jjd ||d< t|j	f |}t
| |||}|| j|< |  r~|| j|< n|I dH  |j r|j |S )zStart a new kernel.

        The caller can pick a kernel_id by passing one in as a keyword arg,
        otherwise one will be generated using new_kernel_id().

        The kernel ID for the newly started kernel is returned.
        zHKernel manager class ({km_class}) is not an instance of 'KernelManager'!)Zkm_classr$   N)r   
isinstancer   rT   warningformatr6   rS   r   start_kernelasyncioZcreate_taskr   rH   r   rg   rn   r   )r#   r]   r&   r*   r$   Zstartertaskr   r   r   _async_start_kernel   s"    




z&MultiKernelManager._async_start_kernelzbool | None)r$   nowrestartr    c                   s  | j d| || jkr| j| }z.|I dH  | |}ttj|jI dH  W n4 tj	k
rf   Y n  t
k
r   | | Y dS X | |}|j s|j r| | dS t|||}t| ||}|| j|< |  s|I dH  |j r|j dS )a3  Shutdown a kernel by its kernel uuid.

        Parameters
        ==========
        kernel_id : uuid
            The id of the kernel to shutdown.
        now : bool
            Should the kernel be shutdown forcibly using a signal.
        restart : bool
            Will the kernel be restarted?
        Kernel shutdown: %sN)rT   inforH   r(   tcastr   ZFuturern   CancelledErrorrk   r   Z	cancelledr   r   shutdown_kernelZensure_futurer   r   )r#   r$   r   r   r   r*   ZstopperZfutr   r   r   _async_shutdown_kernel!  s.    









z)MultiKernelManager._async_shutdown_kernel)r$   r   r    c                 C  s   dS )z,Ask a kernel to shut down by its kernel uuidNr   r#   r$   r   r   r   r   request_shutdownP  s    z#MultiKernelManager.request_shutdown皙?zfloat | None)r$   waittimepollintervalr    c                 C  s   | j d| dS )zDWait for a kernel to finish shutting down, and kill it if it doesn'tr   NrT   r   )r#   r$   r   r   r   r   r   finish_shutdownT  s    z"MultiKernelManager.finish_shutdownc                 C  s   dS )zClean up a kernel's resourcesNr   r   r   r   r   cleanup_resources^  s    z$MultiKernelManager.cleanup_resourcesc                 C  s   | j |dS )zremove a kernel from our mapping.

        Mainly so that a kernel can be removed if it is already dead,
        without having to call shutdown_kernel.

        The kernel object is returned, or `None` if not found.
        N)rg   rz   rw   r   r   r   r   b  s    z MultiKernelManager.remove_kernel)r   r    c              	     s     }|tj7 }tj } fddt|D }tj| I dH   r|D ]N}z|j	I dH  W qX tj
k
r   j|j   Y qX tk
r   Y qXX qXdS )zShutdown all kernels.c                   s   g | ]}j | d qS )r   )r   )rZ   Zkidr   r#   r   r   r\   q  s     z:MultiKernelManager._async_shutdown_all.<locals>.<listcomp>N)rr   rc   rH   rg   re   setr   Zgatherr   rn   r   r$   cancelrk   )r#   r   ZkidsZkmsZfutsr*   r   r   r   _async_shutdown_alll  s    z&MultiKernelManager._async_shutdown_allc                 C  s:   |  |}|j s d}t|| }| jd| |S )zInterrupt (SIGINT) the kernel by its uuid.

        Parameters
        ==========
        kernel_id : uuid
            The id of the kernel to interrupt.
        z/Kernel is in a pending state. Cannot interrupt.zKernel interrupted: %s)r(   rn   doneRuntimeErrorinterrupt_kernelrT   r   )r#   r$   kernelmsgoutr   r   r   r     s    

z#MultiKernelManager.interrupt_kernel)r$   signumr    c                 C  s   | j d|| dS )aR  Sends a signal to the kernel by its uuid.

        Note that since only SIGTERM is supported on Windows, this function
        is only useful on Unix systems.

        Parameters
        ==========
        kernel_id : uuid
            The id of the kernel to signal.
        signum : int
            Signal number to send kernel.
        zSignaled Kernel %s with %sNr   )r#   r$   r   r   r   r   signal_kernel  s    z MultiKernelManager.signal_kernel)r$   r   r    c                   sP   |  |}|  r(|j s(d}t|t|j|dI dH  | jd| dS )aE  Restart a kernel by its uuid, keeping the same ports.

        Parameters
        ==========
        kernel_id : uuid
            The id of the kernel to interrupt.
        now : bool, optional
            If True, the kernel is forcefully restarted *immediately*, without
            having a chance to do any cleanup action.  Otherwise the kernel is
            given 1s to clean up before a forceful restart is issued.

            In all cases the kernel is restarted, the only difference is whether
            it is given a chance to perform a clean shutdown or not.
        z-Kernel is in a pending state. Cannot restart.r   NzKernel restarted: %s)	r(   r   rn   r   r   r   restart_kernelrT   r   )r#   r$   r   r   r   r   r   r   _async_restart_kernel  s    
z(MultiKernelManager._async_restart_kernelc                 C  s   dS )zIs the kernel alive.

        This calls KernelManager.is_alive() which calls Popen.poll on the
        actual kernel subprocess.

        Parameters
        ==========
        kernel_id : uuid
            The id of the kernel.
        Nr   rw   r   r   r   is_alive  s    zMultiKernelManager.is_alivec                 C  s   || krt d| dS )zcheck that a kernel id is validzKernel with id not found: %sN)KeyErrorrw   r   r   r   _check_kernel_id  s    z#MultiKernelManager._check_kernel_idc                 C  s   |  | | j| S )zGet the single KernelManager object for a kernel by its uuid.

        Parameters
        ==========
        kernel_id : uuid
            The id of the kernel.
        )r   rg   rw   r   r   r   r(     s    
zMultiKernelManager.get_kernelr   )r$   callbackeventr    c                 C  s   dS )z&add a callback for the KernelRestarterNr   r#   r$   r   r   r   r   r   add_restart_callback  s    z'MultiKernelManager.add_restart_callbackc                 C  s   dS )z)remove a callback for the KernelRestarterNr   r   r   r   r   remove_restart_callback  s    z*MultiKernelManager.remove_restart_callbackzdict[str, t.Any]c                 C  s   dS )a  Return a dictionary of connection data for a kernel.

        Parameters
        ==========
        kernel_id : uuid
            The id of the kernel.

        Returns
        =======
        connection_dict : dict
            A dict of the information needed to connect to a kernel.
            This includes the ip address and the integer port
            numbers of the different channels (stdin_port, iopub_port,
            shell_port, hb_port).
        Nr   rw   r   r   r   get_connection_info  s    z&MultiKernelManager.get_connection_infozbytes | Nonezsocket.socket)r$   identityr    c                 C  s   dS )a6  Return a zmq Socket connected to the iopub channel.

        Parameters
        ==========
        kernel_id : uuid
            The id of the kernel
        identity : bytes (optional)
            The zmq identity of the socket

        Returns
        =======
        stream : zmq Socket or ZMQStream
        Nr   r#   r$   r   r   r   r   connect_iopub  s    z MultiKernelManager.connect_iopubc                 C  s   dS )a6  Return a zmq Socket connected to the shell channel.

        Parameters
        ==========
        kernel_id : uuid
            The id of the kernel
        identity : bytes (optional)
            The zmq identity of the socket

        Returns
        =======
        stream : zmq Socket or ZMQStream
        Nr   r   r   r   r   connect_shell  s    z MultiKernelManager.connect_shellc                 C  s   dS )a8  Return a zmq Socket connected to the control channel.

        Parameters
        ==========
        kernel_id : uuid
            The id of the kernel
        identity : bytes (optional)
            The zmq identity of the socket

        Returns
        =======
        stream : zmq Socket or ZMQStream
        Nr   r   r   r   r   connect_control  s    z"MultiKernelManager.connect_controlc                 C  s   dS )a6  Return a zmq Socket connected to the stdin channel.

        Parameters
        ==========
        kernel_id : uuid
            The id of the kernel
        identity : bytes (optional)
            The zmq identity of the socket

        Returns
        =======
        stream : zmq Socket or ZMQStream
        Nr   r   r   r   r   connect_stdin)  s    z MultiKernelManager.connect_stdinc                 C  s   dS )a3  Return a zmq Socket connected to the hb channel.

        Parameters
        ==========
        kernel_id : uuid
            The id of the kernel
        identity : bytes (optional)
            The zmq identity of the socket

        Returns
        =======
        stream : zmq Socket or ZMQStream
        Nr   r   r   r   r   
connect_hb;  s    zMultiKernelManager.connect_hb)r&   r    c                 K  s   t t S )z
        Returns the id to associate with the kernel for this request. Subclasses may override
        this method to substitute other sources of kernel ids.
        :param kwargs:
        :return: string-ized version 4 uuid
        )r"   uuidZuuid4)r#   r&   r   r   r   rl   M  s    z MultiKernelManager.new_kernel_id)FF)F)Nr   )F)F)F)r   )r   )N)N)N)N)N)Gr   r   r   __doc__r   r   tagr{   r
   r   ry   r	   r6   r   r;   r   r:   r   r>   r9   r   rA   r@   rK   r   rH   propertyrI   rC   r   r`   rg   rP   rW   rr   ru   rx   r   r   r   r   r   r   r   r   r   r   r/   r   r   r   r   r   shutdown_allr   r   r   r   r   r   r(   r   r   r   r   r   r   r   r   rl   __classcell__r   r   rR   r   r0   3   s    
3

!  -  	
       r0   c                   @  s   e Zd ZU eddddZedddjddZed	Z	e
d
d	dddZejZded< ejZded< ejZded< ejZded< dS )AsyncMultiKernelManagerz.jupyter_client.ioloop.AsyncIOLoopKernelManagerTzThe kernel manager class.  This is configurable to allow
        subclassing of the AsyncKernelManager for customized behavior.
        )r4   r2   FzWhether to make kernels available before the process has started.  The
        kernel has a `.ready` future which can be awaited before connectingr1   r3   zzmq.asyncio.Contextr@   r<   c                 C  s   d| _ tj S rJ   )rK   rL   r   rM   r=   r   r   r   rC   h  s    z(AsyncMultiKernelManager._context_defaultzt.Callable[..., t.Awaitable]r   r   r   r   N)r   r   r   r	   r6   r   r   r   r
   r@   r   rC   r0   r   r   __annotations__r   r   r   r   r   r   r   r   r   r   r   W  s$   
r   ),r   
__future__r   r   rh   r|   sockettypingr   r   	functoolsr   pathlibr   rL   Z	traitletsr   r   r   r	   r
   r   r   r   Ztraitlets.config.configurabler   Ztraitlets.utils.importstringr   connectr   Z
kernelspecr   r   managerr   utilsr   r   r   rk   r   r/   r0   r   r   r   r   r   <module>   s2   (    (