Exemple #1
0
async def test_can_nest_nurseries():
    """
    When nesting nurseries, nested exceptions are gathered into a tree
    of MultiErrors.
    """
    outer_error = RuntimeError('outer')
    inner_error = RuntimeError('inner')

    async def child(outer):
        if outer:
            raise outer_error
        else:
            raise inner_error

    with pytest.raises(MultiError) as exc_info:
        async with Nursery() as outer:
            outer.start_soon(child(outer=True))
            async with Nursery() as inner:
                inner.start_soon(child(outer=False))

    assert len(exc_info.value) == 2
    first, second = exc_info.value
    assert first is outer_error
    assert isinstance(second, MultiError)
    assert second[0] is inner_error
async def test_nursery_cant_be_reused():
    """
    An already used nursery raises NurseryClosed when used again.
    """
    nursery = Nursery()
    async with nursery:
        pass

    with pytest.raises(NurseryClosed):
        async with nursery:
            pass

    with pytest.raises(NurseryClosed):
        nursery.start_soon(asyncio.sleep(0))
Exemple #3
0
    async def test_nursery_already_stopped(self):
        async with Nursery() as nursery:
            pass

        exc = pytest.raises(NurseryError, nursery.start_soon, self.async_error,
                            'fail')
        exc.match('This nursery has already been closed')
Exemple #4
0
async def test_timeout_is_respected():
    """
    When using ``async_timeout``, the timeout is respected and all tasks
    (both parent and children) are properly cancelled.
    """
    parent_cancelled = child_cancelled = False

    async def sleepy():
        nonlocal child_cancelled
        try:
            await asyncio.sleep(1000 * 1000)
        except asyncio.CancelledError:
            child_cancelled = True
            raise

    # The outer timeout is for terminating the test
    # in case the code doesn't work as intended.
    async with async_timeout.timeout(1):
        async with async_timeout.timeout(0.01):
            try:
                async with Nursery() as nursery:
                    nursery.start_soon(sleepy())
                    await asyncio.sleep(1000 * 1000)
            except asyncio.CancelledError:
                parent_cancelled = True

    assert parent_cancelled and child_cancelled
Exemple #5
0
    async def test_success(self, queue):
        async with Nursery() as nursery:
            nursery.start_soon(queue.put, 'a')
            nursery.start_soon(queue.put, 'b')

        assert queue.get_nowait() == 'a'
        assert queue.get_nowait() == 'b'
Exemple #6
0
async def test_can_cancel_remaining():
    """
    A child task can cancel other remaining children.
    """

    cancelled = False

    async def runs_forever():
        nonlocal cancelled
        try:
            await asyncio.sleep(1000)
        except asyncio.CancelledError:
            cancelled = True
            raise

    async def canceller(nursery):
        nursery.cancel_remaining()

    async with Nursery() as nursery:
        nursery.start_soon(runs_forever())
        nursery.start_soon(canceller(nursery))
        # This allows children to be actually executed
        await asyncio.sleep(0)
        # This allows to execute cancellation logic in `runs_forever`
        await asyncio.sleep(0)
        # assert within context manager to be sure
        # `runs_forever` hasn't been cancelled by the nursery
        assert cancelled
Exemple #7
0
    async def test_host_cancelled_before_aexit(self, queue):
        with pytest.raises(asyncio.CancelledError):
            async with Nursery() as nursery:
                nursery.start_soon(self.delayed_put, queue, 'a')
                raise CancelledError

        assert queue.empty()
Exemple #8
0
    async def test_host_cancelled_during_aexit(self, event_loop, queue):
        with pytest.raises(asyncio.CancelledError):
            async with Nursery() as nursery:
                nursery.start_soon(self.delayed_put, queue, 'a')
                event_loop.call_soon(asyncio.Task.current_task().cancel)

        assert queue.empty()
async def test_child_crash_propagation():
    """
    An error in one child cancels other children
    and the context manager's body.
    """
    looper_cancelled = False

    async def looper():
        nonlocal looper_cancelled
        try:
            while True:
                await asyncio.sleep(0)
        except asyncio.CancelledError:
            looper_cancelled = True

    error = ValueError('crashed')

    async def crasher():
        raise error

    with pytest.raises(ValueError) as excinfo:
        async with Nursery() as nursery:
            nursery.start_soon(looper())
            nursery.start_soon(crasher())

    assert looper_cancelled
    assert excinfo.value is error
Exemple #10
0
async def create_handy_nursery():
    try:
        async with Nursery() as nursery:
            yield nursery
    except MultiError as e:
        if len(e.exceptions) == 1:
            raise e.exceptions[0]
        raise
Exemple #11
0
    async def test_host_exception(self, queue):
        with pytest.raises(Exception) as exc:
            async with Nursery() as nursery:
                nursery.start_soon(self.delayed_put, queue, 'a', 5)
                raise Exception('dummy error')

        exc.match('dummy error')
        assert queue.empty()
Exemple #12
0
    async def test_multi_error(self):
        with pytest.raises(MultiError) as exc:
            async with Nursery() as nursery:
                nursery.start_soon(self.async_error, 'task1')
                nursery.start_soon(self.async_error, 'task2')

        assert len(exc.value.exceptions) == 2
        assert sorted(str(e)
                      for e in exc.value.exceptions) == ['task1', 'task2']
Exemple #13
0
    async def test_multi_error_host(self):
        with pytest.raises(MultiError) as exc:
            async with Nursery() as nursery:
                nursery.start_soon(self.async_error, 'child', delay=2)
                await asyncio.sleep(0.1)
                raise Exception('host')

        assert len(exc.value.exceptions) == 2
        assert [str(e) for e in exc.value.exceptions] == ['host', 'child']
async def test_parent_block_error_basic():
    """
    Context manager's body raises properly.
    """
    error = ValueError('whoops')

    with pytest.raises(ValueError) as excinfo:
        async with Nursery():
            raise error
    assert excinfo.value is error
async def test_child_crash_wakes_parent():
    """
    If a child task crashes, the context manager's body is cancelled.
    """
    async def crasher():
        raise ValueError

    with pytest.raises(ValueError):
        async with Nursery() as nursery:
            nursery.start_soon(crasher())
            await asyncio.sleep(1000 * 1000)
Exemple #16
0
async def test_two_child_crashes():
    """
    Multiple child crashes are propagated as a MultiError.
    """
    async def crasher(etype):
        raise etype

    with pytest.raises(MultiError) as excinfo:
        async with Nursery() as nursery:
            nursery.start_soon(crasher(KeyError))
            nursery.start_soon(crasher(ValueError))

    assert set(type(exc) for exc in excinfo.value) == {ValueError, KeyError}
async def test_child_crash_basic():
    """
    A child exception is propagated to the parent coroutine.
    """
    error = ValueError('whoops')

    async def child():
        raise error

    try:
        async with Nursery() as nursery:
            nursery.start_soon(child())
    except ValueError as exc:
        assert exc is error
Exemple #18
0
async def test_parent_and_child_both_crash():
    """
    When both parent and child crash, errors are propagated
    as a MultiError.
    """
    async def crasher():
        raise ValueError

    with pytest.raises(MultiError) as excinfo:
        async with Nursery() as nursery:
            nursery.start_soon(crasher())
            raise KeyError

    assert set(type(exc) for exc in excinfo.value) == {ValueError, KeyError}
Exemple #19
0
async def test_child_crash_basic():
    """
    A child exception is propagated to the parent coroutine.
    """
    error = ValueError('whoops')

    async def child():
        raise error

    with pytest.raises(MultiError) as excinfo:
        async with Nursery() as nursery:
            nursery.start_soon(child())

    assert len(excinfo.value) == 1
    assert excinfo.value[0] is error
Exemple #20
0
async def test_child_crash_wakes_parent():
    """
    If a child task crashes, the context manager's body is cancelled.
    """
    error = ValueError('crashed')

    async def crasher():
        raise error

    with pytest.raises(MultiError) as excinfo:
        async with Nursery() as nursery:
            nursery.start_soon(crasher())
            await asyncio.sleep(1000 * 1000)

    assert len(excinfo.value) == 1
    assert excinfo.value[0] is error
Exemple #21
0
async def test_child_can_spawn_children():
    """
    A child task can spawn even more children tasks.
    """
    i = 0

    async def child(nursery):
        nonlocal i
        i += 1
        if i == 3:
            return
        await asyncio.sleep(0)
        nursery.start_soon(child(nursery))

    async with Nursery() as nursery:
        nursery.start_soon(child(nursery))
async def test_basic_interleave():
    """
    Children are running one after another; when all finished, the task nursery
    is joined with no errors.
    """
    async def looper(whoami, record):
        for i in range(3):
            record.append((whoami, i))
            await asyncio.sleep(0)

    record = []
    async with Nursery() as nursery:
        nursery.start_soon(looper('a', record))
        nursery.start_soon(looper('b', record))

    assert record == [('a', 0), ('b', 0), ('a', 1), ('b', 1), ('a', 2),
                      ('b', 2)]
async def test_shielded_child_continues_running():
    """
    A shielded child continues running.
    """
    work_done = False

    async def worker():
        nonlocal work_done
        await asyncio.sleep(0)
        work_done = True

    try:
        async with Nursery() as nursery:
            nursery.start_soon(asyncio.shield(worker()))
            raise RuntimeError
    except RuntimeError:
        pass

    assert work_done
Exemple #24
0
async def fetch_articles_scores(urls):
    morph = pymorphy2.MorphAnalyzer()
    charged_words = load_charged_words('charged_dict/negative_words.txt')
    async with aiohttp.ClientSession() as session:
        async with Nursery() as nursery:
            tasks = []
            for num, url in enumerate(urls):
                task = nursery.start_soon(
                    process_article(session, morph, charged_words, url))
                tasks.append(task)
            results = await asyncio.wait(tasks)
    scores = []
    for result in results[0]:
        scores.append({
            "status": str(result.result()[0]),
            "url": result.result()[1],
            "score": result.result()[2],
            "words_count": result.result()[3]
        })
    return scores
Exemple #25
0
    async def start(self, loop: asyncio.AbstractEventLoop = None) -> None:
        assert not self._closed_future, 'Consumer already started.'

        loop = loop or asyncio.get_event_loop()

        self._closed_future = asyncio.Future(loop=loop)
        self._closed_ok = asyncio.Event(loop=loop)

        reconnect_attempts = 0

        while True:
            connection_closed_future: asyncio.Future[None] = asyncio.Future(
                loop=loop)

            try:
                await self._connect(
                    connection_closed_future=connection_closed_future,
                    loop=loop,
                )

                reconnect_attempts = 0

                async with Nursery() as nursery:
                    nursery.start_soon(connection_closed_future)
                    nursery.start_soon(self._closed_future)
                    nursery.start_soon(self._process_queue(loop=loop))

            except (aioamqp.AioamqpException, OSError) as exc:
                logger.exception(str(exc))
                reconnect_attempts += 1
                timeout = min(
                    self.default_reconnect_timeout * reconnect_attempts,
                    self.max_reconnect_timeout)
                logger.info('Trying to reconnect in %d seconds.', timeout)
                await asyncio.sleep(timeout, loop=loop)
            except _ConsumerCloseException:
                break

        await self._disconnect()
        self._closed_future = None
        self._closed_ok.set()
Exemple #26
0
    async def process(self):
        cancelled = set()

        async def cancelled_watcher():
            try:
                while True:
                    await asyncio.sleep(100)
            except asyncio.CancelledError:
                cancelled.add(True)

        try:
            async with Nursery() as nursery:
                nursery.start_soon(cancelled_watcher())
                nursery.start_soon(self._process_data(self._reader))
                nursery.start_soon(self._process_heartbeat(self._writer))
        except MultiError as e:
            if len(e.exceptions) == 1:
                raise e.exceptions[0] from e

        if cancelled:
            raise asyncio.CancelledError
async def test_timeout_is_respected():
    """
    When using ``async_timeout``, the timeout is respected and all tasks
    (both parent and children) are properly cancelled.
    """
    parent_cancelled = child_cancelled = False

    async def sleepy():
        nonlocal child_cancelled
        try:
            await asyncio.sleep(1000 * 1000)
        except asyncio.CancelledError:
            child_cancelled = True

    async with async_timeout.timeout(0.01):
        try:
            async with Nursery() as nursery:
                nursery.start_soon(sleepy())
                await asyncio.sleep(1000 * 1000)
        except asyncio.CancelledError:
            parent_cancelled = True

    assert parent_cancelled and child_cancelled
Exemple #28
0
 async def main(self):
     async with Nursery() as ns:
         ns.start_soon(self.queue_monitor_task)
         ns.start_soon(self.cb_feed.run())
         ns.start_soon(self.pull_sink())
Exemple #29
0
 def test_nursery_not_opened(self):
     exc = pytest.raises(NurseryError,
                         Nursery().start_soon, self.async_error, 'fail')
     exc.match('This nursery has not been opened yet')
Exemple #30
0
    async def test_nursery_already_running(self):
        with pytest.raises(NurseryError) as exc:
            async with Nursery() as nursery, nursery:
                pass

        exc.match('This nursery is already running')