B
    \XM                 @   s4  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	Z	ddl
Z
ddl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mZmZmZ dd
lmZmZmZmZmZmZ ddlm Z m!Z! dddZ"dddZ#dddZ$ej%ej&ej'ej&ej&dZ(dd dD Z)G dd deZ*dddgZ+dS ) zUtilities for connecting to jupyter kernels

The :class:`ConnectionFileMixin` class in this module encapsulates the logic
related to writing and reading connections files.
    )absolute_importN)getpass)LoggingConfigurable   )	localhost)filefind)bytes_to_str
cast_bytescast_bytes_py2string_types)BoolIntegerUnicodeCaselessStrEnumInstanceType)jupyter_data_dirjupyter_runtime_dir     tcphmac-sha256c             C   s  |s
t  }| s&td\}} t| g }t|dkt|dk t|dk t|dk t|dk }|dkrxBt|D ]6}t }|tj	tj
d ||df || qxW xt|D ]$\}}| d }|  |||< qW nPd}xJt|D ]>}x&tjd|t|f r|d7 }qW || |d7 }qW |dkrJ|d}|dkr^|d}|dkrr|d}|dkr|d}|dkr|d}t|||||d}||d< t||d	< ||d
< |	|d< |
|d< t| d}|tj|dd W dQ R X ttdr| g}tj| }|r0|| x|D ]}t|j}|tjB }||kr6yt|| W nR tk
r } z2|j t j!kr||krnt"#d||f t$ W dd}~X Y nX q6W | |fS )a  Generates a JSON config file, including the selection of random ports.

    Parameters
    ----------

    fname : unicode
        The path to the file to write

    shell_port : int, optional
        The port to use for ROUTER (shell) channel.

    iopub_port : int, optional
        The port to use for the SUB channel.

    stdin_port : int, optional
        The port to use for the ROUTER (raw input) channel.

    control_port : int, optional
        The port to use for the ROUTER (control) channel.

    hb_port : int, optional
        The port to use for the heartbeat REP channel.

    ip  : str, optional
        The ip address the kernel will bind to.

    key : str, optional
        The Session key used for message authentication.

    signature_scheme : str, optional
        The scheme used for message authentication.
        This has the form 'digest-hash', where 'digest'
        is the scheme used for digests, and 'hash' is the name of the hash function
        used by the digest scheme.
        Currently, 'hmac' is the only supported digest scheme,
        and 'sha256' is the default hash function.

    kernel_name : str, optional
        The name of the kernel currently connected to.
    z.jsonr   r   s           r   z%s-%s)
shell_port
iopub_port
stdin_portcontrol_porthb_portipkey	transportsignature_schemekernel_namew   )indentNS_ISVTXzmFailed to set sticky bit on %r: %s
Probably not a big deal, but runtime files may be cleaned up periodically.)%r   tempfileZmkstemposcloseintrangesocket
setsockoptZ
SOL_SOCKETZ	SO_LINGERZbindappend	enumerateZgetsocknamepathexistsstrpopdictr   openwritejsondumpshasattrstatdirnamest_moder%   chmodOSErrorerrnoZEPERMwarningswarnRuntimeWarning)fnamer   r   r   r   r   r   r   r   r    r!   fdportsZports_neededisockportNcfgfpathsZruntime_dirr/   ZpermissionsZnew_permissionse rM   5lib/python3.7/site-packages/jupyter_client/connect.pywrite_connection_file%   s    ,
.














rO   kernel-*.jsonc          	   C   s   |dk	rt d|  |dkr(dt g}t|tr8|g}y
t| |S  tk
rV   Y nX d| krf| }nd|  }g }x&|D ]}|tt	j
|| qxW dd |D }|std| |f n(t|d	kr|d
 S t|dd dd S dS )a  find a connection file, and return its absolute path.

    The current working directory and optional search path
    will be searched for the file if it is not given by absolute path.

    If the argument does not match an existing file, it will be interpreted as a
    fileglob, and the matching file in the profile's security dir with
    the latest access time will be used.

    Parameters
    ----------
    filename : str
        The connection file or fileglob to search for.
    path : str or list of strs[optional]
        Paths in which to search for connection files.

    Returns
    -------
    str : The absolute path of the connection file.
    Nz5Jupyter has no profiles. profile=%s has been ignored..*z*%s*c             S   s   g | ]}t j|qS rM   )r'   r/   abspath).0mrM   rM   rN   
<listcomp>   s    z(find_connection_file.<locals>.<listcomp>zCould not find %r in %rr   r   c             S   s   t | jS )N)r'   r9   st_atime)rJ   rM   rM   rN   <lambda>   s    z&find_connection_file.<locals>.<lambda>)r   )r?   r@   r   
isinstancer   r   IOErrorextendglobr'   r/   joinlensorted)filenamer/   ZprofileZpatZmatchesprM   rM   rN   find_connection_file   s,    



rc   c          	   C   s   ddl m} t| tr8t| }t| } W dQ R X | }|d}|d |d |d |d f}|d	 }|	||r|d
}	nt
dt| }	x*t||D ]\}
}||
|||||	 qW t|S )a  tunnel connections to a kernel via ssh

    This will open four SSH tunnels from localhost on this machine to the
    ports associated with the kernel.  They can be either direct
    localhost-localhost tunnels, or if an intermediate server is necessary,
    the kernel must be listening on a public IP.

    Parameters
    ----------
    connection_info : dict or str (path)
        Either a connection dict, or the path to a JSON connection file
    sshserver : str
        The ssh sever to use to tunnel to the kernel. Can be a full
        `user@server:port` string. ssh config aliases are respected.
    sshkey : str [optional]
        Path to file containing ssh key to use for authentication.
        Only necessary if your ssh config does not already associate
        a keyfile with the host.

    Returns
    -------

    (shell, iopub, stdin, hb) : ints
        The four ports on localhost that have been forwarded to the kernel.
    r   )tunnelN   r   r   r   r   r   FzSSH Password for %s: )Zzmq.sshrd   rZ   r   r4   r6   loadsreadZselect_random_portsZtry_passwordless_sshr   r
   zipZ
ssh_tunneltuple)Zconnection_infoZ	sshserverZsshkeyrd   rJ   ZcfZlportsZrportsZ	remote_ipZpasswordZlpZrprM   rM   rN   tunnel_to_kernel   s    


rj   )hbshelliopubstdincontrolc             C   s   g | ]}d | qS )z%s_portrM   )rT   channelrM   rM   rN   rV      s    rV   )rl   rn   rm   rk   ro   c               @   sj  e Zd ZdZe Zdd ZeddddZedZ	e
d	d
gd	ddZe ZedddZdd Zdd ZeddddZeddddZeddddZeddddZeddddZdZedd ZedZdd Zd?ddZeedd Zd!d" Z d#d$ Z!d%d& Z"d'd( Z#d)d* Z$d+d, Z%d@d-d.Z&d/d0 Z'd1d2 Z(dAd3d4Z)dBd5d6Z*dCd7d8Z+dDd9d:Z,dEd;d<Z-dFd=d>Z.dS )GConnectionFileMixinz>Mixin for configurable classes that work with connection filesc             C   s   t  S )N)r   )selfrM   rM   rN   _data_dir_default&  s    z%ConnectionFileMixin._data_dir_defaultr   Ta:  JSON file in which to store connection info [default: kernel-<pid>.json]

    This file will contain the IP, ports, and authentication key needed to connect
    clients to this kernel. By default, this file will be created in the security dir
    of the current profile, but can be specified by absolute path.
    )confighelpFr   ipc)default_valuert   zSet the kernel's IP address [default localhost].
        If the IP address is something other than localhost, then
        Consoles on other machines will be able to connect
        to the Kernel, so be careful!c             C   s6   | j dkr,| jr&tj| jd d S dS nt S d S )Nrv   r   z-ipcz
kernel-ipc)r   connection_filer'   r/   splitextr   )rr   rM   rM   rN   _ip_default=  s
    
zConnectionFileMixin._ip_defaultc             C   s   |dkrd| _ d S )NrR   z0.0.0.0)r   )rr   nameoldnewrM   rM   rN   _ip_changedF  s    zConnectionFileMixin._ip_changedr   z(set the heartbeat port [default: random]z-set the shell (ROUTER) port [default: random]z*set the iopub (PUB) port [default: random]z-set the stdin (ROUTER) port [default: random]z/set the control (ROUTER) port [default: random]Nc                s    fddt D S )Nc                s   g | ]}t  |qS rM   )getattr)rT   r{   )rr   rM   rN   rV   \  s    z-ConnectionFileMixin.ports.<locals>.<listcomp>)
port_names)rr   rM   )rr   rN   rD   Z  s    zConnectionFileMixin.portszjupyter_client.session.Sessionc             C   s   ddl m} || dS )Nr   )Session)parent)Zjupyter_client.sessionr   )rr   r   rM   rM   rN   _session_default`  s    z$ConnectionFileMixin._session_defaultc          	   C   sV   t | j| j| j| j| j| j| jd}|r8| j	 |d< n|
t | jj| jjd |S )a  Return the connection info as a dict

        Parameters
        ----------
        session : bool [default: False]
            If True, return our session object will be included in the connection info.
            If False (default), the configuration parameters of our session object will be included,
            rather than the session object itself.

        Returns
        -------
        connect_info : dict
            dictionary of connection information.
        )r   r   r   r   r   r   r   session)r    r   )r3   r   r   r   r   r   r   r   r   Zcloneupdater    r   )rr   r   inforM   rM   rN   get_connection_infoh  s    
z'ConnectionFileMixin.get_connection_infoz#jupyter_client.BlockingKernelClient)klassrw   c             C   s,   |   }| |d< | jf |}| jj|j_|S )z-Make a blocking client connected to my kernelr   )r   blocking_classr   r   )rr   r   ZbcrM   rM   rN   blocking_client  s
    z#ConnectionFileMixin.blocking_clientc          
   C   s<   | j r8d| _ yt| j W n tttfk
r6   Y nX dS )z}Cleanup connection file *if we wrote it*

        Will not raise if the connection file was already removed somehow.
        FN)_connection_file_writtenr'   removerx   r[   r=   AttributeError)rr   rM   rM   rN   cleanup_connection_file  s    z+ConnectionFileMixin.cleanup_connection_filec          
   C   sX   | j dkrdS xD| jD ]:}d| j|f }yt| W q ttfk
rN   Y qX qW dS )z#Cleanup ipc files if we wrote them.rv   Nz%s-%i)r   rD   r   r'   r   r[   r=   )rr   rG   ZipcfilerM   rM   rN   cleanup_ipc_files  s    
z%ConnectionFileMixin.cleanup_ipc_filesc             C   sN   | j dkrdS | jdk	rdS g | _x&tD ]}t| |dkr(| j| q(W dS )zRecords which of the ports are randomly assigned.

        Records on first invocation, if the transport is tcp.
        Does nothing on later invocations.r   Nr   )r   _random_port_namesr   r   r-   )rr   r{   rM   rM   rN   _record_random_port_names  s    


z-ConnectionFileMixin._record_random_port_namesc             C   s2   | j s
dS x| j D ]}t| |d qW |   dS )zForgets randomly assigned port numbers and cleans up the connection file.

        Does nothing if no port numbers have been randomly assigned.
        In particular, does nothing unless the transport is tcp.
        Nr   )r   setattrr   )rr   r{   rM   rM   rN   cleanup_random_ports  s
    z(ConnectionFileMixin.cleanup_random_portsc             C   s   | j rtj| jrdS t| j| j| j| jj	| j
| j| j| j| j| jj| jd\| _}|   xtD ]}t| |||  qdW d| _ dS )z;Write connection info to JSON dict in self.connection_file.N)
r   r   r   r   r   r   r   r   r    r!   T)r   r'   r/   r0   rx   rO   r   r   r   r   r   r   r   r   r   r    r!   r   r   r   )rr   rI   r{   rM   rM   rN   rO     s    
z)ConnectionFileMixin.write_connection_filec          	   C   sH   |dkr| j }| jd| t|}t|}W dQ R X | | dS )a  Load connection info from JSON dict in self.connection_file.
        
        Parameters
        ----------
        connection_file: unicode, optional
            Path to connection file to load.
            If unspecified, use self.connection_file
        NzLoading connection file %s)rx   logdebugr4   r6   loadload_connection_info)rr   rx   rJ   r   rM   rM   rN   load_connection_file  s    	
z(ConnectionFileMixin.load_connection_filec             C   s   | d| j| _| d|  | _|   x2tD ]*}t| |dkr0||kr0t| |||  q0W d|krvt|d | j	_
d|kr|d | j	_dS )aa  Load connection info from a dict containing connection info.
        
        Typically this data comes from a connection file
        and is called by load_connection_file.
        
        Parameters
        ----------
        info: dict
            Dictionary containing connection_info.
            See the connection_file spec for details.
        r   r   r   r   r    N)getr   rz   r   r   r   r   r   r	   r   r   r    )rr   r   r{   rM   rM   rN   r     s    
z(ConnectionFileMixin.load_connection_infoc             C   s@   | j }| j}t| d| }|dkr.d||f S d|||f S dS )z&Make a ZeroMQ URL for a given channel.z%s_portr   ztcp://%s:%iz
%s://%s-%sN)r   r   r   )rr   rp   r   r   rG   rM   rM   rN   	_make_url  s    zConnectionFileMixin._make_urlc             C   sL   |  |}t| }| jd|  | j|}d|_|r>||_|| |S )z1Create a zmq Socket and connect it to the kernel.zConnecting to: %si  )	r   channel_socket_typesr   r   contextr+   ZlingeridentityZconnect)rr   rp   r   ZurlZsocket_typerF   rM   rM   rN   _create_connected_socket  s    

z,ConnectionFileMixin._create_connected_socketc             C   s    | j d|d}|tjd |S )z0return zmq Socket connected to the IOPub channelrm   )r   r   )r   r,   zmqZ	SUBSCRIBE)rr   r   rF   rM   rM   rN   connect_iopub'  s    z!ConnectionFileMixin.connect_iopubc             C   s   | j d|dS )z0return zmq Socket connected to the Shell channelrl   )r   )r   )rr   r   rM   rM   rN   connect_shell-  s    z!ConnectionFileMixin.connect_shellc             C   s   | j d|dS )z0return zmq Socket connected to the StdIn channelrn   )r   )r   )rr   r   rM   rM   rN   connect_stdin1  s    z!ConnectionFileMixin.connect_stdinc             C   s   | j d|dS )z4return zmq Socket connected to the Heartbeat channelrk   )r   )r   )rr   r   rM   rM   rN   
connect_hb5  s    zConnectionFileMixin.connect_hbc             C   s   | j d|dS )z2return zmq Socket connected to the Control channelro   )r   )r   )rr   r   rM   rM   rN   connect_control9  s    z#ConnectionFileMixin.connect_control)F)N)N)N)N)N)N)N)/__name__
__module____qualname____doc__r   Zdata_dirrs   rx   r   r   r   r   r!   r   rz   r~   r   r   r   r   r   r   r   propertyrD   r   r   r   r   r   objectr   r   r   r   r   r   rO   r   r   r   r   r   r   r   r   r   rM   rM   rM   rN   rq   "  sV   	
%





rq   )Nr   r   r   r   r   r   r   r   r   r   )rP   NN)N),r   Z
__future__r   r>   r]   r6   r'   r+   r9   r&   r?   r   r   Ztraitlets.configr   Zlocalinterfacesr   Zipython_genutils.pathr   Zipython_genutils.py3compatr   r	   r
   r   Z	traitletsr   r   r   r   r   r   Zjupyter_core.pathsr   r   rO   rc   rj   ZREQZDEALERZSUBr   r   rq   __all__rM   rM   rM   rN   <module>   sF      
 
9
7
  