Last active
June 2, 2022 19:39
-
-
Save erikbern/54a0f33cc61e3198b1d183d62c310b39 to your computer and use it in GitHub Desktop.
Send data to coroutines that do async things
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
async def intercept_coro(coro, interceptor): | |
# This roughly corresponds to https://gist.github.com/erikbern/ad7615d22b700e8dbbafd8e4d2f335e1 | |
# The underlying idea is that we can execute a coroutine ourselves and use it to intercept | |
# any awaitable object. This lets the coroutine await arbitrary awaitable objects, not just | |
# asyncio futures. See how this is used in object.load. | |
value_to_send = None | |
while True: | |
try: | |
awaitable = coro.send(value_to_send) | |
assert inspect.isawaitable(awaitable) | |
if asyncio.isfuture(awaitable): | |
# This is an asyncio future, just pass it higher up | |
# TODO: is there some cleaner way to do this? | |
await asyncio.gather(awaitable) | |
else: | |
# Intercept this one | |
value_to_send = await interceptor(awaitable) | |
except StopIteration as exc: | |
return exc.value | |
# Usage: | |
class Thing: | |
def __init__(self, n): | |
self._n = n | |
def __await__(self): | |
return (yield self) | |
async def fib(n): | |
if n <= 1: | |
# First, do some asyncio stuff | |
await asyncio.sleep(1e-6) | |
# Now, resolve a Thing class into an int through the interceptor | |
return await Thing(n) | |
else: | |
return await fib(n - 2) + await fib(n - 1) | |
async def interceptor(thing): | |
# This just translates a Thing object into the value it's carrying | |
return thing._n | |
async def test_intercept_coro(): | |
coro = fib(10) | |
assert await intercept_coro(coro, interceptor) == 55 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment