# Path: paco/each.py
# @overload
# @asyncio.coroutine
# def each(coro, iterable, limit=0, loop=None,
#          collect=False, timeout=None, return_exceptions=False, *args, **kw):
#     """
#     Concurrently iterates values yielded from an iterable, passing them to
#     an asynchronous coroutine.
# 
#     You can optionally collect yielded values passing collect=True param,
#     which would be equivalent to `paco.map()``.
# 
#     Mapped values will be returned as an ordered list.
#     Items order is preserved based on origin iterable order.
# 
#     Concurrency level can be configurable via `limit` param.
# 
#     All coroutines will be executed in the same loop.
# 
#     This function is a coroutine.
# 
#     This function can be composed in a pipeline chain with ``|`` operator.
# 
#     Arguments:
#         coro (coroutinefunction): coroutine iterator function that accepts
#             iterable values.
#         iterable (iterable|asynchronousiterable): an iterable collection
#             yielding coroutines functions.
#         limit (int): max iteration concurrency limit. Use ``0`` for no limit.
#         collect (bool): return yielded values from coroutines. Default False.
#         loop (asyncio.BaseEventLoop): optional event loop to use.
#         return_exceptions (bool): enable/disable returning exceptions in case
#             of error. `collect` param must be True.
#         timeout (int|float): timeout can be used to control the maximum number
#             of seconds to wait before returning. timeout can be an int or
#             float. If timeout is not specified or None, there is no limit to
#             the wait time.
#         *args (mixed): optional variadic arguments to pass to the
#             coroutine iterable function.
# 
#     Returns:
#         results (list): ordered list of values yielded by coroutines
# 
#     Raises:
#         TypeError: in case of invalid input arguments.
# 
#     Usage::
# 
#         async def mul_2(num):
#             return num * 2
# 
#         await paco.each(mul_2, [1, 2, 3, 4, 5])
#         # => None
# 
#         await paco.each(mul_2, [1, 2, 3, 4, 5], collect=True)
#         # => [2, 4, 6, 8, 10]
# 
#     """
#     assert_corofunction(coro=coro)
#     assert_iter(iterable=iterable)
# 
#     # By default do not collect yielded values from coroutines
#     results = None
# 
#     if collect:
#         # Store ordered results
#         results = [None] * len(iterable)
# 
#     # Create concurrent executor
#     pool = ConcurrentExecutor(limit=limit, loop=loop)
# 
#     @asyncio.coroutine
#     def collector(index, item):
#         result = yield from safe_run(coro(item, *args, **kw),
#                                      return_exceptions=return_exceptions)
#         if collect:
#             results[index] = result
# 
#         return result
# 
#     # Iterate and pass elements to coroutine
#     for index, value in enumerate(iterable):
#         pool.add(collector(index, value))
# 
#     # Wait until all the coroutines finishes
#     yield from pool.run(return_exceptions=return_exceptions,
#                         ignore_empty=True,
#                         timeout=timeout)
# 
#     # Returns list of mapped results in order
#     return results
# 
# Path: tests/helpers.py
# def run_in_loop(coro, *args, **kw):
#     loop = asyncio.get_event_loop()
#     if asyncio.iscoroutinefunction(coro) or isfunction(coro):
#         coro = coro(*args, **kw)
#     return loop.run_until_complete(coro)


import time
import pytest
import asyncio
from paco import each
from .helpers import run_in_loop
    init = time.time()
    task = each(coro, [1, 2, 3, 4, 5], limit=1)
    assert run_in_loop(task) is None
    assert time.time() - init >= 0.5


def test_each_exception():
    @asyncio.coroutine
    def coro(num):
        yield from asyncio.sleep(0.1)
        if num == 4:
            raise ValueError('foo')
        return num

    init = time.time()
    task = each(coro, [1, 2, 3, 4, 5], limit=1)

    with pytest.raises(ValueError):
        run_in_loop(task)

    assert time.time() - init >= 0.3


def test_each_invalid_input():
    with pytest.raises(TypeError):
        run_in_loop(each(coro, None))


def test_each_invalid_coro():
    with pytest.raises(TypeError):

# Path: paco/each.py
# @overload
# @asyncio.coroutine
# def each(coro, iterable, limit=0, loop=None,
#          collect=False, timeout=None, return_exceptions=False, *args, **kw):
#     """
#     Concurrently iterates values yielded from an iterable, passing them to
#     an asynchronous coroutine.
# 
#     You can optionally collect yielded values passing collect=True param,
#     which would be equivalent to `paco.map()``.
# 
#     Mapped values will be returned as an ordered list.
#     Items order is preserved based on origin iterable order.
# 
#     Concurrency level can be configurable via `limit` param.
# 
#     All coroutines will be executed in the same loop.
# 
#     This function is a coroutine.
# 
#     This function can be composed in a pipeline chain with ``|`` operator.
# 
#     Arguments:
#         coro (coroutinefunction): coroutine iterator function that accepts
#             iterable values.
#         iterable (iterable|asynchronousiterable): an iterable collection
#             yielding coroutines functions.
#         limit (int): max iteration concurrency limit. Use ``0`` for no limit.
#         collect (bool): return yielded values from coroutines. Default False.
#         loop (asyncio.BaseEventLoop): optional event loop to use.
#         return_exceptions (bool): enable/disable returning exceptions in case
#             of error. `collect` param must be True.
#         timeout (int|float): timeout can be used to control the maximum number
#             of seconds to wait before returning. timeout can be an int or
#             float. If timeout is not specified or None, there is no limit to
#             the wait time.
#         *args (mixed): optional variadic arguments to pass to the
#             coroutine iterable function.
# 
#     Returns:
#         results (list): ordered list of values yielded by coroutines
# 
#     Raises:
#         TypeError: in case of invalid input arguments.
# 
#     Usage::
# 
#         async def mul_2(num):
#             return num * 2
# 
#         await paco.each(mul_2, [1, 2, 3, 4, 5])
#         # => None
# 
#         await paco.each(mul_2, [1, 2, 3, 4, 5], collect=True)
#         # => [2, 4, 6, 8, 10]
# 
#     """
#     assert_corofunction(coro=coro)
#     assert_iter(iterable=iterable)
# 
#     # By default do not collect yielded values from coroutines
#     results = None
# 
#     if collect:
#         # Store ordered results
#         results = [None] * len(iterable)
# 
#     # Create concurrent executor
#     pool = ConcurrentExecutor(limit=limit, loop=loop)
# 
#     @asyncio.coroutine
#     def collector(index, item):
#         result = yield from safe_run(coro(item, *args, **kw),
#                                      return_exceptions=return_exceptions)
#         if collect:
#             results[index] = result
# 
#         return result
# 
#     # Iterate and pass elements to coroutine
#     for index, value in enumerate(iterable):
#         pool.add(collector(index, value))
# 
#     # Wait until all the coroutines finishes
#     yield from pool.run(return_exceptions=return_exceptions,
#                         ignore_empty=True,
#                         timeout=timeout)
# 
#     # Returns list of mapped results in order
#     return results
# 
# Path: tests/helpers.py
# def run_in_loop(coro, *args, **kw):
#     loop = asyncio.get_event_loop()
#     if asyncio.iscoroutinefunction(coro) or isfunction(coro):
#         coro = coro(*args, **kw)
#     return loop.run_until_complete(coro)


# Path: tests/each_test.py
import time
import pytest
import asyncio
from paco import each
from .helpers import run_in_loop

    init = time.time()
    task = each(coro, [1, 2, 3, 4, 5], limit=1)
    assert run_in_loop(task) is None
    assert time.time() - init >= 0.5


def test_each_exception():
    @asyncio.coroutine
    def coro(num):
        yield from asyncio.sleep(0.1)
        if num == 4:
            raise ValueError('foo')
        return num

    init = time.time()
    task = each(coro, [1, 2, 3, 4, 5], limit=1)

    with pytest.raises(ValueError):
        run_in_loop(task)

    assert time.time() - init >= 0.3


def test_each_invalid_input():
    with pytest.raises(TypeError):
        run_in_loop(each(coro, None))


def test_each_invalid_coro():
    with pytest.raises(TypeError):

        run_in_loop(each(None))