a
    &ñ»jÂ-  ã                   @  sT  d Z ddlm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	m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 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 ddlmZ ddlmZ ddlmZ ddlmZ e
�r
ddlmZ eƒ Z G dd„ dƒZ!G dd„ dƒZ"ddddœd d!„Z#e!ƒ Z$e$j%Z%e$j&Z&dS )"zk
Managing Gateway Groups and interactions with multiple channels.

(c) 2008-2014, Holger Krekel and others
é    )ÚannotationsN©Úpartial)ÚLock)ÚTYPE_CHECKING)ÚAny)ÚCallable)ÚIterable)ÚIterator)ÚLiteral)ÚSequence)Úoverloadé   )Úgateway_bootstrap)Ú
gateway_io)ÚChannel)Ú	ExecModel)Ú
WorkerPool)Úget_execmodel)Útrace)ÚXSpec)ÚGatewayc                   @  s  e Zd ZdZdZd=ddddœd	d
„Zeddœdd„ƒZeddœdd„ƒZd>ddddœdd„Z	ddœdd„Z
dddœdd„Zdddœdd„Zd dœd!d"„Zd#dœd$d%„Zd?d&dd'œd(d)„Zd*dd'œd+d,„Zddd-œd.d/„Zddd-œd0d1„Zddœd2d3„Zd@d4dd5œd6d7„Zd8d9d:œd;d<„ZdS )AÚGroupzGateway Group.Úpopen© ÚthreadzIterable[XSpec | str | None]ÚstrÚNone)ÚxspecsÚ	execmodelÚreturnc                 C  sH   g | _ d| _tƒ | _g | _|  |¡ |D ]}|  |¡ q(t | j	¡ dS )z|Initialize a group and make gateways as specified.

        execmodel can be one of the supported execution models.
        r   N)
Ú	_gatewaysÚ_autoidcounterr   Ú_autoidlockÚ_gateways_to_joinÚset_execmodelÚmakegatewayÚatexitÚregisterÚ_cleanup_atexit)Úselfr   r   Úxspecr   r   ú3E:\soccer\ml_env\Lib\site-packages\execnet/multi.pyÚ__init__+   s    
zGroup.__init__r   ©r    c                 C  s   | j S ©N)Ú
_execmodel©r*   r   r   r,   r   @   s    zGroup.execmodelc                 C  s   | j S r/   )Ú_remote_execmodelr1   r   r   r,   Úremote_execmodelD   s    zGroup.remote_execmodelNz
str | None)r   r3   r    c                 C  s2   | j rtdƒ‚|du r|}t|ƒ| _t|ƒ| _dS )ae  Set the execution model for local and remote site.

        execmodel can be one of the supported execution models.
        It determines the execution model for any newly created gateway.
        If remote_execmodel is not specified it takes on the value of execmodel.

        NOTE: Execution models can only be set before any gateway is created.
        zBcan not set execution models if gateways have been created alreadyN)r!   Ú
ValueErrorr   r0   r2   )r*   r   r3   r   r   r,   r%   H   s    ÿ
zGroup.set_execmodelc                 C  s   dd„ | D ƒ}d| S )Nc                 S  s   g | ]
}|j ‘qS r   )Úid©Ú.0Úgwr   r   r,   Ú
<listcomp>]   ó    z"Group.__repr__.<locals>.<listcomp>z
<Group %r>r   )r*   Z
idgatewaysr   r   r,   Ú__repr__\   s    zGroup.__repr__zint | str | Gatewayr   ©Úkeyr    c                 C  sF   t |tƒr| j| S | jD ]}||ks0|j|kr|  S qt|ƒ‚d S r/   )Ú
isinstanceÚintr!   r5   ÚKeyError)r*   r=   r8   r   r   r,   Ú__getitem__`   s    



zGroup.__getitem__Úboolc                 C  s(   z| |  W dS  t y"   Y dS 0 d S )NTF)r@   ©r*   r=   r   r   r,   Ú__contains__h   s
    zGroup.__contains__r?   c                 C  s
   t | jƒS r/   )Úlenr!   r1   r   r   r,   Ú__len__o   s    zGroup.__len__zIterator[Gateway]c                 C  s   t t| jƒƒS r/   )ÚiterÚlistr!   r1   r   r   r,   Ú__iter__r   s    zGroup.__iter__zXSpec | str | None)Úspecr    c                 C  sd  |s
| j }t|tƒst|ƒ}|  |¡ |jdu r:| jj|_|jrˆ|jrJJ ‚| |j }| 	t
¡}| t|ƒ¡ t
 || j¡}t ||¡}nr|jsš|jsš|jr¸t
j|| jd�}t ||¡}nB|jrêddlm} |j|| | jd�}t ||¡}ntd|j›�ƒ‚||_|  |¡ |j�s"|j�s"|j�r`| 	d¡}	|j�r@t|jƒ�pBd}
|	 |j|
|jf¡ |	 ¡  |S )a�  Create and configure a gateway to a Python interpreter.

        The ``spec`` string encodes the target gateway type
        and configuration information. The general format is::

            key1=value1//key2=value2//...

        If you leave out the ``=value`` part a True value is assumed.
        Valid types: ``popen``, ``ssh=hostname``, ``socket=host:port``.
        Valid configuration::

            id=<string>     specifies the gateway id
            python=<path>   specifies which python interpreter to execute
            execmodel=model 'thread', 'main_thread_only', 'eventlet', 'gevent' execution model
            chdir=<path>    specifies to which directory to change
            nice=<path>     specifies process priority of new process
            env:NAME=value  specifies a remote environment variable setting.

        If no spec is given, self.defaultspec is used.
        N)r   r   )Úgateway_socketzno gateway type found for a¿  
                import os
                path, nice, env = channel.receive()
                if path:
                    if not os.path.exists(path):
                        os.mkdir(path)
                    os.chdir(path)
                if nice and hasattr(os, 'nice'):
                    os.nice(nice)
                if env:
                    for name, value in env.items():
                        os.environ[name] = value
            r   )Údefaultspecr>   r   Úallocate_idr   r3   ÚbackendÚviaÚsocketÚremote_execr   ÚsendÚvarsZProxyIOr   Z	bootstrapr   ÚsshZvagrant_sshZ	create_ioÚ rK   r4   Ú_specrJ   Ú	_registerÚchdirÚniceÚenvr?   Ú	waitclose)r*   rJ   ZmasterZproxy_channelZproxy_io_masterr8   ÚiorK   ÚsioÚchannelrY   r   r   r,   r&   u   s@    







ÿzGroup.makegatewayr   c                 C  sl   |j du rh| j�H dt| jƒ }|  jd7  _|| v rDtd|›�ƒ‚||_ W d  ƒ n1 s^0    Y  dS )z4(re-entrant) allocate id for the given xspec object.Nr8   r   zalready have gateway with id )r5   r#   r   r"   r4   )r*   rJ   r5   r   r   r,   rM   ¹   s    
zGroup.allocate_id)Úgatewayr    c                 C  s<   t |dƒrJ ‚|jsJ ‚|j| vs&J ‚| j |¡ | |_d S )NÚ_group)Úhasattrr5   r!   Úappendr`   ©r*   r_   r   r   r,   rW   Ã   s
    
zGroup._registerc                 C  s   | j  |¡ | j |¡ d S r/   )r!   Úremover$   rb   rc   r   r   r,   Ú_unregisterÊ   s    zGroup._unregisterc                 C  s    t d| ›d�ƒ | jdd� d S )Nz=== atexit cleanup z ===g      ð?©Útimeout)r   Ú	terminater1   r   r   r,   r)   Î   s    zGroup._cleanup_atexitúfloat | None)rg   r    c                   sš   | r–t ƒ }| D ]}|jjr| |jj¡ q| D ]}|j|vr.| ¡  q.dddœdd„‰ dddœdd„‰t| j|‡ ‡fdd	„| jD ƒƒ g | jd
d
…< q d
S )aB  Trigger exit of member gateways and wait for termination
        of member gateways and associated subprocesses.

        After waiting timeout seconds try to to kill local sub processes of
        popen- and ssh-gateways.

        Timeout defaults to None meaning open-ended waiting and no kill
        attempts.
        r   r   )r8   r    c                 S  s   |   ¡  | j ¡  d S r/   )ÚjoinÚ_ioÚwait©r8   r   r   r,   Ú	join_waitå   s    z"Group.terminate.<locals>.join_waitc                 S  s   t d|  ƒ | j ¡  d S )Nz,Gateways did not come down after timeout: %r)r   rk   Úkillrm   r   r   r,   ro   é   s    zGroup.terminate.<locals>.killc                   s    g | ]}t ˆ |ƒt ˆ|ƒf‘qS r   r   r6   ©rn   ro   r   r,   r9   ð   s   ÿz#Group.terminate.<locals>.<listcomp>N)	ÚsetrJ   rO   Úaddr5   ÚexitÚsafe_terminater   r$   )r*   rg   Zviasr8   r   rp   r,   rh   Ò   s$    


þýzGroup.terminatezCstr | types.FunctionType | Callable[..., object] | types.ModuleTypeÚMultiChannel)Úsourcer    c                 K  s.   g }| D ]}|  |j|fi |¤Ž¡ qt|ƒS )zlremote_exec source on all member gateways and return
        a MultiChannel connecting to all sub processes.)rb   rQ   ru   )r*   rv   ÚkwargsÚchannelsr8   r   r   r,   rQ   ÷   s    zGroup.remote_exec)r   r   )N)N)N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__rL   r-   Úpropertyr   r3   r%   r;   rA   rD   rF   rI   r&   rM   rW   re   r)   rh   rQ   r   r   r   r,   r   &   s,    ÿ ÿD
%r   c                   @  sÄ   e Zd Zdddœdd„Zddœdd	„Zd
dœdd„Zdddœdd„Zdddœdd„Zdddœdd„Ze	d+dddœdd„ƒZ
e	dd dœd!d„ƒZ
d,dd#dœd$d„Z
efdd%œd&d'„Zddœd(d)„Zd*S )-ru   zSequence[Channel]r   )rx   r    c                 C  s
   || _ d S r/   ©Ú	_channels)r*   rx   r   r   r,   r-     s    zMultiChannel.__init__r?   r.   c                 C  s
   t | jƒS r/   )rE   r   r1   r   r   r,   rF     s    zMultiChannel.__len__zIterator[Channel]c                 C  s
   t | jƒS r/   )rG   r   r1   r   r   r,   rI     s    zMultiChannel.__iter__r   r<   c                 C  s
   | j | S r/   r~   rC   r   r   r,   rA     s    zMultiChannel.__getitem__rB   )Úchanr    c                 C  s
   || j v S r/   r~   )r*   r€   r   r   r,   rD     s    zMultiChannel.__contains__Úobject)Úitemr    c                 C  s   | j D ]}| |¡ qd S r/   )r   rR   )r*   r‚   Úchr   r   r,   Ú	send_each  s    
zMultiChannel.send_each.zLiteral[False]z	list[Any])Úwithchannelr    c                 C  s   d S r/   r   ©r*   r…   r   r   r,   Úreceive_each  s    zMultiChannel.receive_eachzLiteral[True]zlist[tuple[Channel, Any]]c                 C  s   d S r/   r   r†   r   r   r,   r‡     s    Fz%list[tuple[Channel, Any]] | list[Any]c                 C  sH   t | dƒrJ ‚g }| jD ]*}| ¡ }|r8| ||f¡ q| |¡ q|S )NÚ_queue)ra   r   Zreceiverb   )r*   r…   Úlrƒ   Úobjr   r   r,   r‡      s    
©Ú	endmarkerc              	     sŒ   zˆ j W S  ty†   d ˆ _ ˆ jD ]X}ˆ j d u r@|jjj ¡ ˆ _ |fdddœ‡ fdd„}|tu rl| |¡ q"|j||d� q"ˆ j  Y S 0 d S )Nr   r   )r^   r    c                   s   ˆ j  || f¡ d S r/   )rˆ   Úput)rŠ   r^   r1   r   r,   Úputreceived6  s    z4MultiChannel.make_receive_queue.<locals>.putreceivedr‹   )	rˆ   ÚAttributeErrorr   r_   r   ÚqueueÚQueueÚNO_ENDMARKER_WANTEDZsetcallback)r*   rŒ   rƒ   rŽ   r   r1   r,   Úmake_receive_queue-  s    

zMultiChannel.make_receive_queuec                 C  s\   d }| j D ]D}z| ¡  W q
 |jyL } z|d u r8|}W Y d }~q
d }~0 0 q
|rX|‚d S r/   )r   r[   ZRemoteError)r*   Úfirstrƒ   Úexcr   r   r,   r[   ?  s    
zMultiChannel.waitcloseN).)F)ry   rz   r{   r-   rF   rI   rA   rD   r„   r   r‡   r’   r“   r[   r   r   r   r,   ru     s    ÿru   r   ri   r   )r   rg   r    c                   sh   t | ƒ‰ddœ‡ ‡fdd„}g }|D ] \}}ˆ |||¡}| |¡ q$|D ]}| ¡  qJˆjˆ d� d S )Nr   r.   c                   s8   ˆ  | ¡}z|jˆ d� W n ty2   |ƒ  Y n0 d S )Nrf   )ÚspawnÚgetÚOSError)ÚtermfuncÚkillfuncZ	termreply©rg   Z
workerpoolr   r,   ÚtermkillP  s
    
z safe_terminate.<locals>.termkillrf   )r   r–   rb   r—   Zwaitall)r   rg   Zlist_of_paired_functionsrœ   Z	replylistr™   rš   Zreplyr   r›   r,   rt   K  s    
rt   )'r|   Ú
__future__r   r'   ÚtypesÚ	functoolsr   Ú	threadingr   Útypingr   r   r   r	   r
   r   r   r   rU   r   r   Zgateway_baser   r   r   r   r   r+   r   r_   r   r�   r’   r   ru   rt   Zdefault_groupr&   r%   r   r   r   r,   Ú<module>   s>    _G