async def _call_func(self, func, args, kwargs): try: retval = await func(*args, **kwargs) except BaseException as exc: self._result_queue.append(Error(exc)) else: self._result_queue.append(Value(retval))
async def _recv_pong(self) -> None: try: cancelled, task = self._pings.popleft() except IndexError as ex: raise exception.UnexpectedPong() from ex if not cancelled: trio.hazmat.reschedule(task, Value(None))
async def _recv_ack(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, Value(None))
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))
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)
async def _recv_data_any(self, msg_id, data_type, plen): if plen >= self.max_data: raise exception.LimitBreached('Peer tried to send us {} bytes, limit is {}'.format(plen, self.max_data)) payload = await self.stream.recv_exactly(plen) data = Data(self, msg_id, data_type, payload) if not self._recv_data_task: raise Exception('Was not expecting any data') trio.hazmat.reschedule(self._recv_data_task, Value(data)) self._recv_data_task = None await data._unblock.wait()
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}
def cutin_nowait(self, value): if self._closed: raise trio.ClosedResourceError if self._state.open_receive_channels == 0: raise trio.BrokenResourceError if self._state.receive_tasks: assert not self._state.data task, _ = self._state.receive_tasks.popitem(last=False) task.custom_sleep_data._tasks.remove(task) trio.lowlevel.reschedule(task, Value(value)) elif len(self._state.data) < self._state.max_buffer_size: self._state.data.appendleft(value) else: raise trio.WouldBlock
def put_nowait(self, value): if self.closed: raise _core.ClosedResourceError if not self._buf.get_channels: raise BrokenChannelError if self._buf.get_tasks: assert not self._buf.data task, _ = self._buf.get_tasks.popitem(last=False) task.custom_sleep_data._tasks.remove(task) _core.reschedule(task, Value(value)) elif len(self._buf.data) < self._buf.capacity: self._buf.data.append(value) else: raise _core.WouldBlock
async def test_acapture(): async def add(x, y): await asyncio.sleep(0) return x + y v = await outcome.acapture(add, 3, y=4) assert v == Value(7) async def raise_ValueError(x): await asyncio.sleep(0) raise ValueError(x) e = await outcome.acapture(raise_ValueError, 9) assert type(e.error) is ValueError assert e.error.args == (9, )
def send_nowait(self, value): """Like `~trio.abc.SendChannel.send`, but if the channel's buffer is full, raises `WouldBlock` instead of blocking. """ if self._closed: raise trio.ClosedResourceError if self._state.open_receive_channels == 0: raise trio.BrokenResourceError if self._state.receive_tasks: assert not self._state.data task, _ = self._state.receive_tasks.popitem(last=False) task.custom_sleep_data._tasks.remove(task) trio.hazmat.reschedule(task, Value(value)) elif len(self._state.data) < self._state.max_buffer_size: self._state.data.append(value) else: raise trio.WouldBlock
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)
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)
def process_events(self, received): for i in range(received): entry = self._events[i] if entry.lpCompletionKey == CKeys.AFD_POLL: lpo = entry.lpOverlapped op = self._afd_ops.pop(lpo) waiters = op.waiters if waiters.current_op is not op: # Stale op, nothing to do pass else: waiters.current_op = None # I don't think this can happen, so if it does let's crash # and get a debug trace. if lpo.Internal != 0: # pragma: no cover code = ntdll.RtlNtStatusToDosError(lpo.Internal) raise_winerror(code) flags = op.poll_info.Handles[0].Events if waiters.read_task and flags & READABLE_FLAGS: _core.reschedule(waiters.read_task) waiters.read_task = None if waiters.write_task and flags & WRITABLE_FLAGS: _core.reschedule(waiters.write_task) waiters.write_task = None self._refresh_afd(op.poll_info.Handles[0].Handle) elif entry.lpCompletionKey == CKeys.WAIT_OVERLAPPED: # Regular I/O event, dispatch on lpOverlapped waiter = self._overlapped_waiters.pop(entry.lpOverlapped) overlapped = entry.lpOverlapped transferred = entry.dwNumberOfBytesTransferred info = CompletionKeyEventInfo( lpOverlapped=overlapped, dwNumberOfBytesTransferred=transferred) _core.reschedule(waiter, Value(info)) elif entry.lpCompletionKey == CKeys.LATE_CANCEL: # Post made by a regular I/O event's abort_fn # after it failed to cancel the I/O. If we still # have a waiter with this lpOverlapped, we didn't # get the regular I/O completion and almost # certainly the user forgot to call # register_with_iocp. self._posted_too_late_to_cancel.remove(entry.lpOverlapped) try: waiter = self._overlapped_waiters.pop(entry.lpOverlapped) except KeyError: # Looks like the actual completion got here before this # fallback post did -- we're in the "expected" case of # too-late-to-cancel, where the user did nothing wrong. # Nothing more to do. pass else: exc = _core.TrioInternalError( "Failed to cancel overlapped I/O in {} and didn't " "receive the completion either. Did you forget to " "call register_with_iocp()?".format(waiter.name)) # Raising this out of handle_io ensures that # the user will see our message even if some # other task is in an uncancellable wait due # to the same underlying forgot-to-register # issue (if their CancelIoEx succeeds, we # have no way of noticing that their completion # won't arrive). Unfortunately it loses the # task traceback. If you're debugging this # error and can't tell where it's coming from, # try changing this line to # _core.reschedule(waiter, outcome.Error(exc)) raise exc elif entry.lpCompletionKey == CKeys.FORCE_WAKEUP: pass else: # dispatch on lpCompletionKey queue = self._completion_key_queues[entry.lpCompletionKey] overlapped = int(ffi.cast("uintptr_t", entry.lpOverlapped)) transferred = entry.dwNumberOfBytesTransferred info = CompletionKeyEventInfo( lpOverlapped=overlapped, dwNumberOfBytesTransferred=transferred) queue.put_nowait(info)
def test_Value_compare(): assert Value(1) < Value(2) assert not Value(3) < Value(2) with pytest.raises(TypeError): Value(1) < Value("foo")
def set_result(self, result): self._outcome = Value(result) self._event.set()
async def test_the_future(): async with trio.open_nursery() as nursery: fut = run(nursery, my_fn) func_outcome = await fut.outcome() assert func_outcome == Value(7)
async def test_gather(): async with trio.open_nursery() as nursery: future_list = [run(nursery, my_fn) for _ in range(10)] joined_future = gather(nursery, future_list) assert await joined_future.outcome() == Value([7] * 10)
async def put(self, x): await self._s.send(Value(x))