o
    tfL                     @  s   d Z ddlmZ ddlZddlmZ ddlmZmZm	Z	m
Z
mZmZmZmZmZmZmZ ddlmZmZmZmZ ddlmZ erTddlZdd	lmZmZ dd
lmZmZ ddgZG dd deZ G dd deZ!eddG dd dZ"dddZ#dS )a  A SignalGroup class that allows connecting to all SignalInstances on the class.

Note that unlike a slot/callback connected to SignalInstance.connect, a slot connected
to SignalGroup.connect does *not* receive the direct arguments that were emitted by a
given SignalInstance. Instead, the slot/callback will receive an EmissionInfo named
tuple, which contains `.signal`: the SignalInstance doing the emitting, and `.args`:
the args that were emitted.

    )annotationsN)MappingProxyType)TYPE_CHECKINGAnyCallableClassVarContextManagerIterableIteratorLiteralMapping
NamedTupleoverload)_NULLSignalSignalInstance_SignalBlocker   )
mypyc_attr)FReducerFunc)RefErrorChoiceWeakCallbackEmissionInfoSignalGroupc                   @  s"   e Zd ZU dZded< ded< dS )r   zTuple containing information about an emission event.

    Attributes
    ----------
    signal : SignalInstance
    args: tuple
    r   signalztuple[Any, ...]argsN)__name__
__module____qualname____doc____annotations__ r"   r"   W/var/www/html/software/conda/envs/catlas/lib/python3.10/site-packages/psygnal/_group.pyr   *   s   
 c                      s   e Zd ZdZ	d5d6 fd	d
Zd7 fddZd8ddZd9 fddZd8ddZd:ddZ		d5dddddd;d$d%Z
d<d= fd)d*Zd8 fd+d,Z	&d<d>d.d/Zd?d@ fd3d4Z  ZS )ASignalRelaya  Special SignalInstance that can be used to connect to all signals in a group.

    This class will rarely be instantiated by a user (or anything other than a
    SignalGroup).

    Parameters
    ----------
    signals : Mapping[str, SignalInstance]
        A mapping of signal names to SignalInstance instances.
    instance : Any, optional
        An object to which this `SignalRelay` is bound, by default None
    NsignalsMapping[str, SignalInstance]instancer   returnNonec                   s&   t  jtf|d t|| _i | _d S )N)	signaturer'   )super__init__r   r   _signals_sig_was_blocked)selfr%   r'   	__class__r"   r#   r,   E   s   

zSignalRelay.__init__slotr   c                   s*   t  | t| jdkr|   d S d S )Nr   )r+   _append_slotlen_slots_connect_relayr/   r2   r0   r"   r#   r3   L   s   zSignalRelay._append_slotc                 C  s\   t    t d | j D ]}|j| jdddd qW d    d S 1 s'w   Y  d S )NignoreFT)check_nargscheck_typesunique)warningscatch_warningssimplefilterr-   valuesconnect_slot_relayr/   sigr"   r"   r#   r6   Q   s   


"zSignalRelay._connect_relay#int | WeakCallback | Literal['all']c                   s"   t  | | js|   d S d S N)r+   _remove_slotr5   _disconnect_relayr7   r0   r"   r#   rF   Z   s   zSignalRelay._remove_slotc                 C  s    | j  D ]}|| j qd S rE   )r-   r?   
disconnectrA   rB   r"   r"   r#   rG   _   s   zSignalRelay._disconnect_relayr   c                 G  s*   t   }rt||}| |f d S d S rE   )r   Zcurrent_emitterr   Z_run_emit_loop)r/   r   Zemitterinfor"   r"   r#   rA   c   s   
zSignalRelay._slot_relayFr9   r:   r;   max_argsCallable | Noner9   bool | Noner:   r;   
bool | strrK   
int | None)Callable[[Callable], Callable] | Callablec                  s*   d fdd}|du r|S ||S )aA  Connect `slot` to be called whenever *any* Signal in this group is emitted.

        Params are the same as `psygnal.SignalInstance.connect`.  It's probably
        best to check whether all signals are uniform (i.e. have the same signature).

        Parameters
        ----------
        slot : Callable
            A callable to connect to this signal.  If the callable accepts less
            arguments than the signature of this slot, then they will be discarded when
            calling the slot.
        check_nargs : bool | None
            If `True` and the provided `slot` requires more positional arguments than
            the signature of this Signal, raise `TypeError`. by default `True`.
        check_types : bool | None
            If `True`, An additional check will be performed to make sure that types
            declared in the slot signature are compatible with the signature
            declared by this signal, by default `False`.
        unique : bool | str
            If `True`, returns without connecting if the slot has already been
            connected.  If the literal string "raise" is passed to `unique`, then a
            `ValueError` will be raised if the slot is already connected.
            By default `False`.
        max_args : int, optional
            If provided, `slot` will be called with no more more than `max_args` when
            this SignalInstance is emitted.  (regardless of how many arguments are
            emitted).

        Returns
        -------
        Union[Callable[[Callable], Callable], Callable]
            [description]
        r2   r   r(   c                   s(   j  D ]}|j|  d q| S NrJ   )r-   r?   r@   )r2   rC   r9   r:   rK   r/   r;   r"   r#   _inner   s   z*SignalRelay.connect_direct.<locals>._innerN)r2   r   r(   r   r"   )r/   r2   r9   r:   r;   rK   rS   r"   rR   r#   connect_directh   s   +zSignalRelay.connect_directr"   excludeIterable[str | SignalInstance]c                   sL   t    | j D ]\}}|r||v s||v rq
|j| j|< |  q
dS )z1Block this signal and all emitters from emitting.N)r+   blockr-   itemsZ_is_blockedr.   )r/   rU   namerC   r0   r"   r#   rW      s   

zSignalRelay.blockc                   s8   t    | j D ]\}}| j|ds|  q
dS )z<Unblock this signal and all emitters, allowing them to emit.FN)r+   unblockr-   rX   r.   pop)r/   rY   rC   r0   r"   r#   rZ      s   
zSignalRelay.unblockContextManager[None]c                 C  s   t | |dS )a  Context manager to temporarily block all emitters in this group.

        Parameters
        ----------
        exclude : iterable of str or SignalInstance, optional
            An iterable of signal instances or names to exempt from the block,
            by default ()
        rU   )r   r/   rU   r"   r"   r#   blocked   s   zSignalRelay.blockedT
missing_okboolc                   s.   | j  D ]}||| qt || dS )a  Disconnect slot from all signals.

        Parameters
        ----------
        slot : callable, optional
            The specific slot to disconnect.  If `None`, all slots will be disconnected,
            by default `None`
        missing_ok : bool, optional
            If `False` and the provided `slot` is not connected, raises `ValueError.
            by default `True`

        Raises
        ------
        ValueError
            If `slot` is not connected and `missing_ok` is False.
        N)r-   r?   rH   r+   )r/   r2   r`   rC   r0   r"   r#   rH      s   zSignalRelay.disconnectrE   )r%   r&   r'   r   r(   r)   )r2   r   r(   r)   r(   r)   )r2   rD   r(   r)   )r   r   r(   r)   r2   rL   r9   rM   r:   rM   r;   rN   rK   rO   r(   rP   r"   rU   rV   r(   r)   rU   rV   r(   r\   NTr2   rL   r`   ra   r(   r)   )r   r   r   r    r,   r3   r6   rF   rG   rA   rT   rW   rZ   r_   rH   __classcell__r"   r"   r0   r#   r$   7   s*    
	

8	r$   T)Zallow_interpreted_subclassesc                	      s  e Zd ZU dZded< dZded< ded< d	ed
< ded< dodpddZdi fdq fddZedrddZ	edsddZ
dtd!d"Zdud&d'Zdvd)d*Zdwd,d-Zdxd.d/Zdyd0d1Zedzd2d3Zedzd4d5Zd{d8d9Zed:d:d:d:dd:d:d;d|dIdJZed:d:d:d:dd:d:d;d}dMdJZ	doddddddNdOd;d~dRdJZ	dodddddSddVdWZdddZd[Zddd_d`ZddadbZ	\dddddeZddfdgZdefddkdlZdefddmdnZ  Z S )r   a'  A collection of signals that can be connected to as a single unit.

    This class is not intended to be instantiated directly.  Instead, it should be
    subclassed, and the subclass should define Signal instances as class attributes.
    The SignalGroup will then automatically collect these signals and provide a
    SignalRelay instance (at `group.all`) that can be used to connect to all of the
    signals in the group.

    This class is used in both the EventedModels and the evented dataclass patterns.
    See also: `psygnal.SignalGroupDescriptor`, which provides convenient and explicit
    way to create a SignalGroup on a dataclass-like class.

    Parameters
    ----------
    instance : Any, optional
        An object to which this `SignalGroup` is bound, by default None

    Attributes
    ----------
    all : SignalRelay
        A special SignalRelay instance that can be used to connect to all signals in
        this group.

    Examples
    --------
    ```python
    from psygnal import Signal, SignalGroup


    class MySignals(SignalGroup):
        sig1 = Signal()
        sig2 = Signal()


    group = MySignals()
    group.all.connect(print)  # connect to all signals in the group

    list(group)  # ['sig1', 'sig2']
    len(group)  # 2
    group.sig1 is group["sig1"]  # True
    ```
    zClassVar[Mapping[str, Signal]]_psygnal_signalsFzClassVar[bool]_psygnal_uniformzClassVar[set[str]]_psygnal_name_conflictszClassVar[dict[str, str | None]]_psygnal_aliaseszdict[str, SignalInstance]_psygnal_instancesNr'   r   r(   r)   c                   sH   t  t dstd fdd j D _tj|_d S )Nrj   zCCannot instantiate `SignalGroup` directly.  Use a subclass instead.c                   s2   i | ]\}}|| j v r|n| qS r"   )rl   Z_create_signal_instance__get__).0rY   rC   clsr/   r"   r#   
<dictcomp>  s    


z(SignalGroup.__init__.<locals>.<dictcomp>)typehasattr	TypeErrorrj   rX   rn   r$   _psygnal_relay)r/   r'   r"   rq   r#   r,     s   
zSignalGroup.__init__strictra   signal_aliasesMapping[str, str | None]c                   sT  dd t | ddD }|rtd| i }t| D ]}t | |d}t|tr+|||< qi t | di || _ttt  fdd| jD  | _}|r|D ]}tt | |tr]t	| | qNt
|d	krfd
nd}	t
|d	krpdnd}
tj|	 dt|d|
 dtdd t | di }i ||| _t| j | _|r| jstdt   dS )zHCollects all Signal instances on the class under `cls._psygnal_signals`.c                 S  s   h | ]	}| d r|qS )_psygnal
startswithrp   kr"   r"   r#   	<setcomp>$  s
    
z0SignalGroup.__init_subclass__.<locals>.<setcomp>__dict__r"   zMSignalGroup subclass cannot have attributes starting with '_psygnal'. Found: Nrj   c                   s"   h | ]}| v s| d r|qS ))r{   Zpsygnalr|   r~   reservedr"   r#   r   =  s
    r   NamesNameZareis z reserved. You cannot use these names to access SignalInstances as attributes on a SignalGroup. (You may still access them as keys to __getitem__: `group['name']`).   
stacklevelrm   z@All Signals in a strict SignalGroup must have the same signature)getattrrv   dir
isinstancer   rj   setr   rl   delattrr4   r<   warnsortedUserWarningrm   _is_uniformr?   rk   r+   __init_subclass__)rr   rx   ry   	forbiddenrj   r   val	conflictsrY   r   ZArealiasesr0   r   r#   r     sX   





zSignalGroup.__init_subclass__r$   c                 C     | j S )a  SignalInstance that can be used to connect to all signals in this group.

        Examples
        --------
        ```python
        from psygnal import Signal, SignalGroup


        class MySignals(SignalGroup):
            sig1 = Signal()
            sig2 = Signal()


        group = MySignals()
        group.sig2.connect(...)  # connect to a single signal by name
        group.all.connect(...)  # connect to all signals in the group
        ```
        )rw   r/   r"   r"   r#   allY  s   zSignalGroup.allr&   c                 C  
   t | jS )z6A mapping of signal names to SignalInstance instances.)r   rn   r   r"   r"   r#   r%   o  s   
zSignalGroup.signalsintc                 C  r   )zDReturn the number of signals in the group (not including the relay).)r4   rn   r   r"   r"   r#   __len__|     
zSignalGroup.__len__itemstrr   c                 C  s
   | j | S )Get a signal instance by name.rn   r/   r   r"   r"   r#   __getitem__  r   zSignalGroup.__getitem___SignalGroup__namec                 C  s   t t| jd|)r   z object has no attribute )AttributeErrorrt   r   )r/   r   r"   r"   r#   __getattr__  s   zSignalGroup.__getattr__Iterator[str]c                 C  r   )z,Yield the names of all signals in the group.)iterrn   r   r"   r"   r#   __iter__  r   zSignalGroup.__iter__c                 C  s
   || j v S )z?Return True if the group contains a signal with the given name.r   r   r"   r"   r#   __contains__  s   
zSignalGroup.__contains__c                 C  s   | j j}d|dt|  dS )zReturn repr(self).z<SignalGroup z with z	 signals>)r1   r   r4   )r/   rY   r"   r"   r#   __repr__  s   zSignalGroup.__repr__c                 C  r   )@Return true if all signals in the group have the same signature.)rk   rr   r"   r"   r#   psygnals_uniform  s   zSignalGroup.psygnals_uniformc                 C  s   t jdtdd | jS )r   zuThe `is_uniform` method on SignalGroup is deprecated. Use `psygnals_uniform` instead. This will be an error in v0.11.r   r   )r<   r   FutureWarningrk   r   r"   r"   r#   
is_uniform  s   zSignalGroup.is_uniformmemodict[int, Any]c                 C  s   t | | jjdS )N)r'   )rt   rw   r'   )r/   r   r"   r"   r#   __deepcopy__  s   zSignalGroup.__deepcopy__.threadr9   r:   r;   rK   on_ref_errorpriorityr   4threading.Thread | Literal['main', 'current'] | Noner9   rM   r:   r;   rN   rK   rO   r   r   r   Callable[[F], F]c                C     d S rE   r"   )r/   r   r9   r:   r;   rK   r   r   r"   r"   r#   r@     s   zSignalGroup.connectr2   r   c          	      C  r   rE   r"   	r/   r2   r   r9   r:   r;   rK   r   r   r"   r"   r#   r@     s   r   r   F | NoneCallable[[F], F] | Fc          	   
   C  s>   |d u r| j j|||||||dS | j j||||||||dS )Nr   )rw   r@   r   r"   r"   r#   r@     s(   
rJ   rL   rP   c                C  s   | j j|||||dS rQ   )rw   rT   )r/   r2   r9   r:   r;   rK   r"   r"   r#   rT     s   	zSignalGroup.connect_directTr`   c                 C     | j j||dS )N)r2   r`   )rw   rH   )r/   r2   r`   r"   r"   r#   rH        zSignalGroup.disconnectr"   rU   rV   c                 C     | j j|dS Nr]   )rw   rW   r^   r"   r"   r#   rW   	  s   zSignalGroup.blockc                 C  
   | j  S rE   )rw   rZ   r   r"   r"   r#   rZ        
zSignalGroup.unblockr\   c                 C  r   r   )rw   r_   r^   r"   r"   r#   r_     s   zSignalGroup.blockedc                 C  r   rE   )rw   pauser   r"   r"   r#   r     r   zSignalGroup.pausereducerReducerFunc | Noneinitialc                 C  r   N)r   r   )rw   resumer/   r   r   r"   r"   r#   r     r   zSignalGroup.resumec                 C  r   r   )rw   pausedr   r"   r"   r#   r     s   zSignalGroup.pausedrE   )r'   r   r(   r)   )rx   ra   ry   rz   r(   r)   )r(   r$   )r(   r&   )r(   r   )r   r   r(   r   )r   r   r(   r   )r(   r   )r   r   r(   ra   )r(   r   )r(   ra   )r   r   r(   r   )r   r   r9   rM   r:   rM   r;   rN   rK   rO   r   r   r   r   r(   r   )r2   r   r   r   r9   rM   r:   rM   r;   rN   rK   rO   r   r   r   r   r(   r   )r2   r   r   r   r9   rM   r:   rM   r;   rN   rK   rO   r   r   r   r   r(   r   rc   rg   rh   rd   re   rb   rf   )r   r   r   r   r(   r)   )r   r   r   r   r(   r\   )!r   r   r   r    r!   rk   r,   r   propertyr   r%   r   r   r   r   r   r   classmethodr   r   r   r   r@   rT   rH   rW   rZ   r_   r   r   r   r   ri   r"   r"   r0   r#   r      s   
 +=







$

r%   Iterable[Signal]r(   ra   c                 C  sJ   t  }| D ]}tdd |jj D }|r||vr dS || qdS )z3Return True if all signals have the same signature.c                 s  s    | ]}t |jV  qd S rE   )r   
annotation)rp   pr"   r"   r#   	<genexpr>$  s    z_is_uniform.<locals>.<genexpr>FT)r   tupler*   
parametersr?   add)r%   seensvr"   r"   r#   r      s   r   )r%   r   r(   ra   )$r    
__future__r   r<   typesr   typingr   r   r   r   r   r	   r
   r   r   r   r   Zpsygnal._signalr   r   r   r   Z_mypycr   	threadingr   r   Zpsygnal._weak_callbackr   r   __all__r   r$   r   r   r"   r"   r"   r#   <module>   s(    
4 !  J