Skip to content

Instantly share code, notes, and snippets.

@erikbern
Last active June 2, 2022 19:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erikbern/54a0f33cc61e3198b1d183d62c310b39 to your computer and use it in GitHub Desktop.
Save erikbern/54a0f33cc61e3198b1d183d62c310b39 to your computer and use it in GitHub Desktop.
Send data to coroutines that do async things
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