Beispiel #1
0
    def close(self):
        """Close this receive channel object synchronously.

        All channel objects have an asynchronous `~.AsyncResource.aclose` method.
        Memory channels can also be closed synchronously. This has the same
        effect on the channel and other tasks using it, but `close` is not a
        trio checkpoint. This simplifies cleaning up in cancelled tasks.

        Using ``with receive_channel:`` will close the channel object on
        leaving the with block.

        """
        if self._closed:
            return
        self._closed = True
        for task in self._tasks:
            trio.lowlevel.reschedule(task, Error(trio.ClosedResourceError()))
            del self._state.receive_tasks[task]
        self._tasks.clear()
        self._state.open_receive_channels -= 1
        if self._state.open_receive_channels == 0:
            assert not self._state.receive_tasks
            for task in self._state.send_tasks:
                task.custom_sleep_data._tasks.remove(task)
                trio.lowlevel.reschedule(task,
                                         Error(trio.BrokenResourceError()))
            self._state.send_tasks.clear()
            self._state.data.clear()
Beispiel #2
0
 async def _call_func(self, func, args, kwargs):
     try:
         retval = await func(*args, **kwargs)
     except Exception as exc:
         self._result_queue.append(Error(exc))
     except BaseException as exc:
         self._result_queue.append(Error(exc))
         raise
     else:
         self._result_queue.append(Value(retval))
Beispiel #3
0
 def close(self):
     if self.closed:
         return
     self.closed = True
     for task in list(self._tasks):
         _core.reschedule(task, Error(ClosedResourceError()))
     self._buf.put_channels -= 1
     if self._buf.put_channels == 0:
         assert not self._buf.put_tasks
         for task in list(self._buf.get_tasks):
             _core.reschedule(task, Error(EndOfChannel()))
Beispiel #4
0
 async def __aexit__(self, exc_type, exc, tb):
     if self._recv_data_task:
         trio.hazmat.reschedule(self._recv_data_task, Error(Exception('Quit Context Manager')))
         self._recv_data_task = None
     while self._pings:
         cancelled, task = self._pings.popleft()
         if not cancelled:
             trio.hazmat.reschedule(task, Error(Exception('Quit Context Manager')))
     for msg_id in self._message_ids.ids:
         cancelled, task = self._message_ids.pop(msg_id)
         if not cancelled:
             trio.hazmat.reschedule(task, Error(Exception('Quit Context Manager')))
     self._cancel_recv.cancel()
Beispiel #5
0
 def close(self):
     if self.closed:
         return
     self.closed = True
     for task in list(self._tasks):
         _core.reschedule(task, Error(ClosedResourceError()))
     self._buf.get_channels -= 1
     if self._buf.get_channels == 0:
         assert not self._buf.get_tasks
         for task in list(self._buf.put_tasks):
             _core.reschedule(task, Error(BrokenChannelError()))
         # XX: or if we're losing data, maybe we should raise a
         # BrokenChannelError here?
         self._buf.data.clear()
Beispiel #6
0
    async def run_sync(self, sync_fn: Callable, *args) -> Optional[Outcome]:
        import trio

        try:
            job = dumps((sync_fn, args), protocol=HIGHEST_PROTOCOL)
        except BaseException as exc:
            return Error(exc)

        try:
            try:
                await self._send_chan.send(job)
            except trio.BrokenResourceError:
                with trio.CancelScope(shield=True):
                    await self.wait()
                return None

            try:
                return loads(await self._receive_chan.receive())
            except trio.EndOfChannel:
                self._send_pipe.close(
                )  # edge case: free proc spinning on recv_bytes
                with trio.CancelScope(shield=True):
                    await self.wait()
                raise BrokenWorkerProcessError("Worker died unexpectedly:",
                                               self.proc) from None
        except BaseException:
            # cancellations require kill by contract
            # other exceptions will almost certainly leave us in an
            # unrecoverable state requiring kill as well
            self.kill()
            with trio.CancelScope(shield=True):
                await self.wait()
            raise
Beispiel #7
0
def test_Error_unwrap_does_not_create_reference_cycles():
    # See comment in Error.unwrap for why reference cycles are tricky
    exc = ValueError()
    err = Error(exc)
    try:
        err.unwrap()
    except ValueError:
        pass
    # Top frame in the traceback is the current test function; we don't care
    # about its references
    assert exc.__traceback__.tb_frame is sys._getframe()
    # The next frame down is the 'unwrap' frame; we want to make sure it
    # doesn't reference the exception (or anything else for that matter, just
    # to be thorough)
    unwrap_frame = exc.__traceback__.tb_next.tb_frame
    assert unwrap_frame.f_code.co_name == "unwrap"
    assert unwrap_frame.f_locals == {}
Beispiel #8
0
 async def _recv_error_undef(self) -> None:
     msg_id, = await self.stream.recv_struct('>L')
     try:
         cancelled, task = self._message_ids.pop(msg_id)
     except KeyError as ex:
         raise exception.UnexpectedAck(msg_id) from ex
     if not cancelled:
         trio.hazmat.reschedule(task, Error(exception.DataError(None, None)))
Beispiel #9
0
 async def aclose(self):
     if self._closed:
         await trio.hazmat.checkpoint()
         return
     self._closed = True
     for task in self._tasks:
         trio.hazmat.reschedule(task, Error(trio.ClosedResourceError()))
         del self._state.send_tasks[task]
     self._tasks.clear()
     self._state.open_send_channels -= 1
     if self._state.open_send_channels == 0:
         assert not self._state.send_tasks
         for task in self._state.receive_tasks:
             task.custom_sleep_data._tasks.remove(task)
             trio.hazmat.reschedule(task, Error(trio.EndOfChannel()))
         self._state.receive_tasks.clear()
     await trio.hazmat.checkpoint()
Beispiel #10
0
 async def _call_func(self, func: Callable[..., Awaitable[object]],
                      args: tuple, kwargs: dict) -> None:
     try:
         retval = await func(*args, **kwargs)
     except BaseException as exc:
         self._result_queue.append(Error(exc))
     else:
         self._result_queue.append(Value(retval))
Beispiel #11
0
 async def aclose(self):
     if self._closed:
         await _core.checkpoint()
         return
     self._closed = True
     for task in self._tasks:
         _core.reschedule(task, Error(_core.ClosedResourceError()))
         del self._state.receive_tasks[task]
     self._tasks.clear()
     self._state.open_receive_channels -= 1
     if self._state.open_receive_channels == 0:
         assert not self._state.receive_tasks
         for task in self._state.send_tasks:
             task.custom_sleep_data._tasks.remove(task)
             _core.reschedule(task, Error(_core.BrokenResourceError()))
         self._state.send_tasks.clear()
         self._state.data.clear()
     await _core.checkpoint()
Beispiel #12
0
 async def _recv_error(self) -> None:
     msg_id, error_type, plen = await self.stream.recv_struct('>LHL')
     if plen >= self.max_error:
         raise exception.LimitBreached('Peer tried to send us {} bytes, limit is {}'.format(plen, self.max_error))
     payload = await self.stream.recv_exactly(plen)
     try:
         cancelled, task = self._message_ids.pop(msg_id)
     except KeyError as ex:
         raise exception.UnexpectedAck(msg_id) from ex
     if not cancelled:
         trio.hazmat.reschedule(task, Error(exception.DataError(error_type, payload)))
Beispiel #13
0
def test_Outcome_eq_hash():
    v1 = Value(["hello"])
    v2 = Value(["hello"])
    v3 = Value("hello")
    v4 = Value("hello")
    assert v1 == v2
    assert v1 != v3
    with pytest.raises(TypeError):
        {v1}
    assert {v3, v4} == {v3}

    # exceptions in general compare by identity
    exc1 = RuntimeError("oops")
    exc2 = KeyError("foo")
    e1 = Error(exc1)
    e2 = Error(exc1)
    e3 = Error(exc2)
    e4 = Error(exc2)
    assert e1 == e2
    assert e3 == e4
    assert e1 != e3
    assert {e1, e2, e3, e4} == {e1, e3}
Beispiel #14
0
class Future:
    """A very simple Future for trio based on `trio.Event`."""
    def __init__(self):
        self._outcome = None
        self._event = trio.Event()

    def set_result(self, result):
        self._outcome = Value(result)
        self._event.set()

    def set_exception(self, exc):
        self._outcome = Error(exc)
        self._event.set()

    async def get(self):
        await self._event.wait()
        return self._outcome.unwrap()
Beispiel #15
0
async def test_asend():
    async def my_agen_func():
        assert (yield 1) == "value"
        with pytest.raises(KeyError):
            yield 2
        yield 3

    my_agen = my_agen_func().__aiter__()
    v = Value("value")
    e = Error(KeyError())
    assert (await my_agen.asend(None)) == 1
    assert (await v.asend(my_agen)) == 2
    with pytest.raises(AlreadyUsedError):
        await v.asend(my_agen)

    assert (await e.asend(my_agen)) == 3
    with pytest.raises(AlreadyUsedError):
        await e.asend(my_agen)
    with pytest.raises(StopAsyncIteration):
        await my_agen.asend(None)
Beispiel #16
0
async def test_asend():
    @async_generator
    async def my_agen_func():
        assert (await yield_(1)) == "value"
        with pytest.raises(KeyError):
            await yield_(2)
        await yield_(3)

    my_agen = my_agen_func().__aiter__()
    if sys.version_info < (3, 5, 2):
        my_agen = await my_agen
    v = Value("value")
    e = Error(KeyError())
    assert (await my_agen.asend(None)) == 1
    assert (await v.asend(my_agen)) == 2
    with pytest.raises(AlreadyUsedError):
        await v.asend(my_agen)

    assert (await e.asend(my_agen)) == 3
    with pytest.raises(AlreadyUsedError):
        await e.asend(my_agen)
    with pytest.raises(StopAsyncIteration):
        await my_agen.asend(None)
Beispiel #17
0
 async def put_error(self, x):
     await self._s.send(Error(x))
Beispiel #18
0
 def set_exception(self, exc):
     self._outcome = Error(exc)
     self._event.set()
Beispiel #19
0
 def set_result(self, result):
     self._outcome = Value(result)
     self._event.set()
Beispiel #20
0
def test_Outcome():
    v = Value(1)
    assert v.value == 1
    assert v.unwrap() == 1
    assert repr(v) == "Value(1)"

    with pytest.raises(AlreadyUsedError):
        v.unwrap()

    v = Value(1)

    exc = RuntimeError("oops")
    e = Error(exc)
    assert e.error is exc
    with pytest.raises(RuntimeError):
        e.unwrap()
    with pytest.raises(AlreadyUsedError):
        e.unwrap()
    assert repr(e) == f"Error({exc!r})"

    e = Error(exc)
    with pytest.raises(TypeError):
        Error("hello")
    with pytest.raises(TypeError):
        Error(RuntimeError)

    def expect_1():
        assert (yield) == 1
        yield "ok"

    it = iter(expect_1())
    next(it)
    assert v.send(it) == "ok"
    with pytest.raises(AlreadyUsedError):
        v.send(it)

    def expect_RuntimeError():
        with pytest.raises(RuntimeError):
            yield
        yield "ok"

    it = iter(expect_RuntimeError())
    next(it)
    assert e.send(it) == "ok"
    with pytest.raises(AlreadyUsedError):
        e.send(it)
Beispiel #21
0
 def safe_dumps(result):
     try:
         return dumps(result, protocol=HIGHEST_PROTOCOL)
     except BaseException as exc:
         return dumps(Error(exc), protocol=HIGHEST_PROTOCOL)