U
    ·ÜŸjy&  ã                
   @   s¼   d 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	giZd
ddgZG dd„ dƒZed dd„ƒZdd„ Zdd„ Zddddedddddœ	dd„Zdd
„ Zdd„ Zddœdd„ZdS )!z,
Thin wrappers around `concurrent.futures`.
é    N)Úcontextmanager©Úlength_hinté   )Útqdm)ÚTqdmWarningzgithub.com/Z	casperdclÚ
thread_mapÚprocess_mapÚinterpreter_mapc                   @   sR   e Zd ZdZddlmZ ddlmZ dd„ Z	dd	d
„Z
dd„ Zdd„ Zdd„ ZdS )Ú_InterpreterLockz3Reentrant lock backed by a cross-interpreter queue.r   )Ú	get_ident)Ú	monotonicc                 C   s*   ddl m} || _|ƒ | _d | _d| _d S )Nr   )ÚRLock)Ú	threadingr   Ú_queueÚ_lockÚ_ownerÚ_depth)ÚselfÚqueuer   © r   ú;/tmp/pip-unpacked-wheel-ktn_y856/tqdm/contrib/concurrent.pyÚ__init__   s
    z_InterpreterLock.__init__Téÿÿÿÿc                 C   sÚ   ddl m} |  ¡ }|dkr*| j |¡}n| j ||¡}|s@dS | jrX|  jd7  _dS zL|sj| j ¡  n8|dkr~| j ¡  n$t	d||  ¡ |  ƒ}| jj|d� W n  |k
rÄ   | j 
¡  Y dS X |  ¡ | _d| _dS )Nr   )ÚEmptyr   Fé   T)Útimeout)r   r   Ú_timer   Úacquirer   r   Ú
get_nowaitÚgetÚmaxÚreleaser   r   )r   Úblockingr   r   ÚstartZacquiredÚ	remainingr   r   r   r      s.    

z_InterpreterLock.acquirec                 C   sJ   | j |  ¡ krtdƒ‚|  jd8  _| js<d | _ | j d ¡ | j ¡  d S )Nzcannot release un-acquired lockr   )r   r   ÚRuntimeErrorr   r   Úputr   r"   ©r   r   r   r   r"   6   s    z_InterpreterLock.releasec                 C   s   |   ¡  | S ©N)r   r(   r   r   r   Ú	__enter__?   s    z_InterpreterLock.__enter__c                 G   s   |   ¡  d S r)   )r"   )r   Úexcr   r   r   Ú__exit__C   s    z_InterpreterLock.__exit__N)Tr   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   Útimer   r   r   r   r"   r*   r,   r   r   r   r   r      s   
	r   Ú c                 c   sX   t | ddƒ}|dkr |p|  ¡ }t |||ƒ}|  |¡ |V  |dkrJ| `n
|  |¡ dS )z>get (create if necessary) and then restore `tqdm_class`'s lockr   N)ÚgetattrZget_lockÚset_lockr   )Ú
tqdm_classÚ	lock_nameÚlockZold_lockr   r   r   Úensure_lockG   s    
r8   c              	   C   s4   dt j›d| j›d| j d¡›d|›d�	}t|ffS )zGReturn an initializer which bootstraps the parent import path and lock.zimport sys
sys.path[:] = z™
from concurrent import interpreters
from importlib import import_module
from tqdm.contrib.concurrent import _InterpreterLock
tqdm_class = import_module(z)
for name in Ú.z…:
    tqdm_class = getattr(tqdm_class, name)
tqdm_class.monitor_interval = 0
tqdm_class.set_lock(_InterpreterLock(interpreters.Queue(z))))ÚsysÚpathr.   r/   ÚsplitÚexec)r5   Zlock_queue_idÚcoder   r   r   Ú_get_interpreter_initV   s    (ÿr?   c                    s   t ‡ fdd„| D ƒƒS )z min(map(length_hint, iterables))c                 3   s&   | ]}t |d  ƒ ‰ dkrˆ V  qdS )r   r   Nr   )Ú.0Úit©Únr   r   Ú	<genexpr>h   s      z_min_map_len.<locals>.<genexpr>)Úmin)Ú	iterablesr   rB   r   Ú_min_map_lenf   s    rG   r   g        )	Úmax_workersr   Ú	chunksizer6   r5   Ú	smoothingr   Ú_initializerÚ	_initargsc       	            s¬  |  ¡ }d|krt|ƒ|d< i }d|kr6| d¡|d< i }dD ]}||kr>| |¡||< q>d}|d rÐd|krÐzddlm} W n  tk
rž   ddlm} Y nX |p¶td	|ƒ p°d
d ƒ}|d |krÐ||d< d}t|||d��Ä}|	dkrô|j	}	|f}
| f ||	|
dœ|—Ž�Ž}|f d|i|—Ž�p‰|dk	�r0dˆ_
|j‰ ‡ ‡fdd„}||_t|j|f|ž||dœ|—ŽƒW  5 Q R £ W  5 Q R £ W  5 Q R £ S Q R X W 5 Q R X W 5 Q R X dS )a  
    Implementation of `thread_map`, `process_map` and `interpreter_map`.

    Parameters
    ----------
    max_workers  : int
    timeout  : int
    buffersize  : int
        Requires Python>=3.14.
    thread_name_prefix  : str
    max_tasks_per_child  : int
    mp_context  : str
    ÚtotalZ
buffersize)Zthread_name_prefixZmax_tasks_per_childZ
mp_contextNZminitersr   )Úprocess_cpu_count)Ú	cpu_counté    r   é   T)r6   r7   )rH   ÚinitializerÚinitargsrJ   c                     s    ˆ | |Ž}|  ‡fdd„¡ |S )Nc                    s   ˆ   ¡ S r)   )Úupdate)Ú_)Úpbarr   r   Ú<lambda>    ó    z4_executor_map.<locals>.patchsubmit.<locals>.<lambda>)Úadd_done_callback)ÚargsÚkwargsÚfut©Z	orisubmitrV   r   r   Úpatchsubmitž   s    
z"_executor_map.<locals>.patchsubmit)r   rI   )ÚcopyrG   ÚpopÚosrN   ÚImportErrorrO   rE   r8   r4   Údynamic_minitersÚsubmitÚlistÚmap)ZPoolExecutorÚfnrH   r   rI   r6   r5   rJ   r   rK   rL   rF   Útqdm_kwargsr[   Z
map_kwargsÚpool_kwargsÚkrc   rO   Z	rough_maxZlkÚexr^   r   r]   r   Ú_executor_mapk   sX    ÿ
ÿÿ ÿÿrl   c                 O   s   ddl m} t|| f|ž|ŽS )a°  
    Equivalent of `list(map(fn, *iterables))`
    driven by `concurrent.futures.ThreadPoolExecutor`.

    Parameters
    ----------
    max_workers  : int, optional
        Maximum number of workers to spawn; passed to `concurrent.futures.ThreadPoolExecutor`.
    thread_name_prefix  : str, optional
        Passed to `concurrent.futures.ThreadPoolExecutor` [default: ''].
    timeout  : int or float, optional
        Seconds to wait before raising `TimeoutError` if `__next__` is called and the
        result isn't available. [default: None].
    buffersize  : int, optional
        Requires Python>=3.14 [default: None].
    tqdm_class  : optional
        `tqdm` class to use for bars [default: tqdm.auto.tqdm].
    smoothing  : float, optional
        Passed to `tqdm_class`; the [default: 0] is average (due to erratic update frequency).
    lock_name  : str, optional
        Member of `tqdm_class.get_lock()` to use [default: ''].
    r   )ÚThreadPoolExecutor)Úconcurrent.futuresrm   rl   )rg   rF   rh   rm   r   r   r   r   §   s    c           	      O   sh   ddl m} ddlm} | ¡ }| d¡ | dt¡}t||j	ƒ\}}t
|| f|žt|ƒ||dœ|—ŽS )aj  
    Equivalent of `list(map(fn, *iterables))`
    driven by `concurrent.futures.InterpreterPoolExecutor` (Python 3.14+).

    Parameters
    ----------
    Same as `thread_map`.

    Notes
    -----
    `fn`, its arguments, and its return values must be pickleable.
    Worker progress bars using the same `tqdm_class` share a cross-interpreter write lock.
    r   )Úinterpreters)ÚInterpreterPoolExecutorNr5   )r   rK   rL   )Ú
concurrentro   rn   rp   Zcreate_queuer'   r    Ú	tqdm_autor?   Úidrl   r   )	rg   rF   rh   ro   rp   Z
lock_queuer5   rR   rS   r   r   r   r
   Â   s$    
 ÿÿ þþZmp_lock)r6   c                O   s`   ddl m} |rFd|krFt|ƒ}|dkrFddlm} |d| tdd� t|| f|žd	|i|—ŽS )
aI  
    Equivalent of `list(map(fn, *iterables))`
    driven by `concurrent.futures.ProcessPoolExecutor`.

    Parameters
    ----------
    max_workers  : int, optional
        Maximum number of workers to spawn; passed to `concurrent.futures.ProcessPoolExecutor`.
    timeout  : int or float, optional
        Seconds to wait before raising `TimeoutError` if `__next__` is called and the
        result isn't available. [default: None].
    chunksize  : int, optional
        Approximate size of chunks sent to worker processes; passed to
        `concurrent.futures.ProcessPoolExecutor.map`. [default: 1].
    buffersize  : int, optional
        Requires Python>=3.14 [default: None].
    max_tasks_per_child  : int, optional
        Maximum number of tasks a worker process can complete before being replaced
        with a new process; passed to `concurrent.futures.ProcessPoolExecutor`.
    mp_context  : multiprocessing.BaseContext, optional
        Multiprocessing context to use, e.g. `multiprocessing.get_context('fork')`.
    lock_name  : str, optional
        Member of `tqdm_class.get_lock()` to use [default: mp_lock].
    tqdm_class  : optional
        `tqdm` class to use for bars [default: tqdm.auto.tqdm].
    smoothing  : float, optional
        Passed to `tqdm_class`; the [default: 0] is average (due to erratic update frequency).
    r   )ÚProcessPoolExecutorrI   iè  )Úwarnz…Iterable length %d > 1000 but `chunksize` is not set. This may seriously degrade multiprocess performance. Set `chunksize=1` or more.r   )Ú
stacklevelr6   )rn   rt   rG   Úwarningsru   r   rl   )rg   r6   rF   rh   rt   Zshortest_iterable_lenru   r   r   r   r	   Û   s    þ ý)r2   N)r0   r:   Ú
contextlibr   Úoperatorr   Úautor   rr   Zstdr   Ú
__author__Ú__all__r   r8   r?   rG   rl   r   r
   r	   r   r   r   r   Ú<module>   s2   

8       þ<