U
    /e                     @  sv   d dl mZ d dlmZ d dlmZ d dlmZ ddgZG dd dZ	dd	 Z
edddZdd ZG dd dZd
S )    )annotations)Callable)contextmanager)ClassVarCallbackadd_callbacksc                   @  sh   e Zd ZU dZe Zded< dddZeddd	d
Z	dd Z
dd ZddddZddddZdS )r   a  Base class for using the callback mechanism

    Create a callback with functions of the following signatures:

    >>> def start(dsk):
    ...     pass
    >>> def start_state(dsk, state):
    ...     pass
    >>> def pretask(key, dsk, state):
    ...     pass
    >>> def posttask(key, result, dsk, state, worker_id):
    ...     pass
    >>> def finish(dsk, state, failed):
    ...     pass

    You may then construct a callback object with any number of them

    >>> cb = Callback(pretask=pretask, finish=finish)

    And use it either as a context manager over a compute/get call

    >>> with cb:            # doctest: +SKIP
    ...     x.compute()

    Or globally with the ``register`` method

    >>> cb.register()
    >>> cb.unregister()

    Alternatively subclass the ``Callback`` class with your own methods.

    >>> class PrintKeys(Callback):
    ...     def _pretask(self, key, dask, state):
    ...         print("Computing: {0}!".format(repr(key)))

    >>> with PrintKeys():   # doctest: +SKIP
    ...     x.compute()
    z*ClassVar[set[tuple[Callable | None, ...]]]activeNc                 C  s6   |r
|| _ |r|| _|r|| _|r(|| _|r2|| _d S N)_start_start_state_pretask	_posttask_finish)selfstartZstart_stateZpretaskZposttaskfinish r   2/tmp/pip-unpacked-wheel-dbjnr7gq/dask/callbacks.py__init__4   s    zCallback.__init__ztuple[Callable | None, ...])returnc                   s$   dddddg}t  fdd|D S )Nr
   r   r   r   r   c                 3  s   | ]}t  |d V  qd S r	   )getattr.0ir   r   r   	<genexpr>E   s     z%Callback._callback.<locals>.<genexpr>)tuple)r   fieldsr   r   r   	_callbackB   s    zCallback._callbackc                 C  s   t | | _| j  | S r	   )r   _cm	__enter__r   r   r   r   r    G   s    

zCallback.__enter__c                 G  s   | j j|  d S r	   )r   __exit__)r   argsr   r   r   r!   L   s    zCallback.__exit__Nonec                 C  s   t j| j d S r	   )r   r   addr   r   r   r   r   registerO   s    zCallback.registerc                 C  s   t j| j d S r	   )r   r   remover   r   r   r   r   
unregisterR   s    zCallback.unregister)NNNNN)__name__
__module____qualname____doc__setr   __annotations__r   propertyr   r    r!   r%   r'   r   r   r   r   r   
   s   
'         
c                 C  s(   | rdd t |  D S dddddgS dS )z>Take an iterable of callbacks, return a list of each callback.c                 S  s   g | ]}d d |D qS )c                 S  s   g | ]}|r|qS r   r   r   r   r   r   
<listcomp>Y   s      z/unpack_callbacks.<locals>.<listcomp>.<listcomp>r   )r   fr   r   r   r/   Y   s     z$unpack_callbacks.<locals>.<listcomp>r   N)zip)Zcbsr   r   r   unpack_callbacksV   s    r2   Nc                 c  s<   | dk}|rt jt  } t _z| p$dV  W 5 |r6| t _X dS )zAllows callbacks to work with nested schedulers.

    Callbacks will only be used by the first started scheduler they encounter.
    This means that only the outermost scheduler will use global callbacks.Nr   )r   r   r,   )	callbacksZglobal_callbacksr   r   r   local_callbacks^   s    r4   c                 C  s*   t | tr| jS t | tr| S tddS )z Normalizes a callback to a tuplez.Callbacks must be either `Callback` or `tuple`N)
isinstancer   r   r   	TypeError)cbr   r   r   normalize_callbackn   s
    

r8   c                   @  s(   e Zd ZdZdd Zdd Zdd ZdS )	r   a  Context manager for callbacks.

    Takes several callbacks and applies them only in the enclosed context.
    Callbacks can either be represented as a ``Callback`` object, or as a tuple
    of length 4.

    Examples
    --------
    >>> def pretask(key, dsk, state):
    ...     print("Now running {0}").format(key)
    >>> callbacks = (None, pretask, None, None)
    >>> with add_callbacks(callbacks):    # doctest: +SKIP
    ...     res.compute()
    c                 G  s"   dd |D | _ tj| j  d S )Nc                 S  s   g | ]}t |qS r   )r8   )r   cr   r   r   r/      s     z*add_callbacks.__init__.<locals>.<listcomp>)r3   r   r   update)r   r3   r   r   r   r      s    zadd_callbacks.__init__c                 C  s   d S r	   r   r   r   r   r   r       s    zadd_callbacks.__enter__c                 C  s   | j D ]}tj| qd S r	   )r3   r   r   discard)r   typevalue	tracebackr9   r   r   r   r!      s    
zadd_callbacks.__exit__N)r(   r)   r*   r+   r   r    r!   r   r   r   r   r   x   s   )N)
__future__r   collections.abcr   
contextlibr   typingr   __all__r   r2   r4   r8   r   r   r   r   r   <module>   s   L
