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 == {}
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)
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()