import sys
 
import multiprocessing
 
 
 
 
 
_current = None
 
_total = None
 
 
 
 
 
def _init(current, total):
 
    global _current
 
    global _total
 
    _current = current
 
    _total = total
 
 
 
 
 
def _wrapped_func(func_and_args):
 
    func, argument, should_print_progress, filter_ = func_and_args
 
 
 
    if should_print_progress:
 
        with _current.get_lock():
 
            _current.value += 1
 
        sys.stdout.write('\r\t{} of {}'.format(_current.value, _total.value))
 
        sys.stdout.flush()
 
 
 
    return func(argument, filter_)
 
 
 
 
 
def pmap(func, iterable, processes, should_print_progress, filter_=None, *args, **kwargs):
 
    """
 
    A parallel map function that reports on its progress.
 
 
 
    Applies `func` to every item of `iterable` and return a list of the
 
    results. If `processes` is greater than one, a process pool is used to run
 
    the functions in parallel. `should_print_progress` is a boolean value that
 
    indicates whether a string 'N of M' should be printed to indicate how many
 
    of the functions have finished being run.
 
    """
 
    global _current
 
    global _total
 
    _current = multiprocessing.Value('i', 0)
 
    _total = multiprocessing.Value('i', len(iterable))
 
 
 
    func_and_args = [(func, arg, should_print_progress, filter_) for arg in iterable]
 
    if processes == 1:
 
        result = list(map(_wrapped_func, func_and_args, *args, **kwargs))
 
    else:
 
        pool = multiprocessing.Pool(initializer=_init,
 
                                    initargs=(_current, _total,),
 
                                    processes=processes)
 
        result = pool.map(_wrapped_func, func_and_args, *args, **kwargs)
 
        pool.close()
 
        pool.join()
 
 
 
    if should_print_progress:
 
        sys.stdout.write('\r')
 
    return result