
    Q3j                         U d Z ddlZddlZddlmZmZmZ ddlmZ ddl	m
Z
mZ  G d de      Zi Zeeef   ed<   i Zeee
f   ed	<   i Zeeef   ed
<   dddZd Zd Zd Zy)a  Cross-process transport for callback messages.

When a callback is registered on an estimator that uses multiple worker processes, every
worker ends up with its own copy of the callback (sent there by pickling). However, the
user-visible state (e.g. logs being filled in or progress bars advancing) lives on the
main process. This module provides a way for the worker copies to ship their messages
back to the main process over a local endpoint (a UNIX socket on Unix, a Windows named
pipe on Windows).

Remark: we don't use a `multiprocessing.Manager` because its proxy objects become
unusable once the Manager subprocess is gone, e.g. after unpickling in a fresh
interpreter. The only ways to work around that either rely on multiprocessing private
API or give up cross-process capabilities.
    N)Client
ConnectionListener)Thread)Callable
NamedTuplec                   &    e Zd ZU dZeed<   eed<   y)ListenerHandlea  A picklable reference to a main-process listener.

    Attributes
    ----------
    address : str
        Address of the local endpoint the listener is bound to.
        Workers use this to connect, and the main process also uses it as a key into
        this module's registries to find the live listener.

    authkey : bytes
        Shared secret used to authenticate connections to the listener.
    addressauthkeyN)__name__
__module____qualname____doc__str__annotations__bytes     H/DATA/.local/lib/python3.12/site-packages/sklearn/callback/_transport.pyr
   r
      s     LNr   r
   
_listeners_message_consumers_worker_connections)ownerc                P    t        j                  d      }t        |d      t        j                  |      }t
        |j                  <    t        |j                  <   |t        j                  |t        |        fdfd}t        |d      j                          |S )	a  Create a listener for incoming messages on the main process.

    Also registers the listener and its message consumer in the module-level dicts.

    Parameters
    ----------
    message_consumer : callable
        A one-argument function, `message_consumer(message)`, that processes incoming
        message to update the callback's state. This callable may be called from
        multiple different threads, and must therefore behave in a thread-safe manner.

    owner : callback instance, default=None
        Optional owner callback. When provided, the listener is automatically closed
        when `owner` gets garbage-collected.

    Returns
    -------
    listener_handle : ListenerHandle
        A reference to the listener.
           )r   backlog)r   r   c                     	 	  | j                                | j                  d        (# t        t        f$ r Y y w xY w)N)recvsendEOFErrorOSError)connmessage_consumers    r   _handlezopen_listener.<locals>._handlei   sB    	 -		$  '" 		s   ), >>c                      	 	 j                         } t        | fd      j                          /# t        $ r Y y w xY w)NT)targetargsdaemon)acceptr#   r   start)r$   r&   listeners    r   _acceptzopen_listener.<locals>._acceptt   sI    ( '=CCE   s   2 	>>T)r(   r*   )osurandomr   r
   r   r   r   weakreffinalizeclose_listenerr   r,   )r%   r   r   listener_handler.   r&   r-   s   `    @@r   open_listenerr5   D   s    * jjnG 5H$X-=-=wOO*2J&&'2B../@	F '$'--/r   c                     t         j                  | j                  d       t        j                  | j                  d      }||j	                          yy)zEStop listening for `listener_handle` and free its background threads.N)r   popr   r   close)r4   r-   s     r   r3   r3      sC    ?22D9~~o55t<H r   c                     | j                   t        v ry	 t        | j                   | j                        j	                          y# t
        $ r Y yw xY w)a  Whether the listener at `listener_handle` is usable from this process.

    Helper for callbacks that open their listener eagerly (e.g. in `__init__`) and
    therefore have to decide, on unpickling, whether to keep the inherited handle
    or open a fresh listener. The listener is not reusable when:

    - We are the process that originally opened the listener. Reusing the handle
      would route messages through the in-process fast path of `send`, into the
      original instance's message consumer instead of the unpickled instance's.

    - The listener is no longer reachable, e.g. unpickling in a fresh interpreter,
      or on a host that cannot reach the original listener.
    Fr   T)r   r   r   r   r8   r#   )r4   s    r   can_reuse_listenerr;      sR     *,&&0G0GHNNP   s   /A 	AAc                     t         j                  | j                        }|	 ||       y| j                  }t        j                  |      }| t	        || j
                        }|t        |<   |j                  |       |j                          y)a  Deliver `message` to whoever is listening on `listener_handle`.

    There are two possible delivery paths:

    - In-process fast path: `send` is called in the same process that called
      `open_listener` for this listener handle. The message consumer can directly be
      called without any serialization overhead.

    - Cross-process path: `send` is called in a different process. The worker opens
      a `Client` connection to the main-process listener on first use and caches it
      in `_worker_connections`, so all subsequent messages reuse the same socket.
      `send` then waits for an acknowledgement from the main process so that, by
      the time it returns, the message has actually been processed by the consumer.
    Nr:   )r   getr   r   r   r   r!   r    )r4   messager%   r   
connections        r   r!   r!      s     *--o.E.EF#!%%G$((1JG_-D-DE
'1G$OOGOOr   )r   r/   r1   multiprocessing.connectionr   r   r   	threadingr   typingr   r   r
   r   dictr   r   r   r   r5   r3   r;   r!   r   r   r   <module>rD      s    
  C C  'Z B #%
Dh $*, Dh' ,
 .0 T#z/* / .2 9x.r   