Open spencerwilson opened 7 months ago
Another gotcha: When using _future=True
the object returned is a concurrent.futures.Future, which is not an awaitable. This type is distinct from asyncio.Future, which is awaitable.
The former can in most cases be adapted into the latter using asyncio.wrap_future. The complete working code looks like:
import asyncio
from synchronicity import Synchronizer
synchronizer = Synchronizer()
@synchronizer.create_blocking
async def f(x):
await asyncio.sleep(1.0)
return x**2
# Running f in a synchronous context blocks until the result is available
assert type(f(42)) == int
async def g():
# Running f in an asynchronous context works the normal way
ret = asyncio.wrap_future(f(42, _future=True))
assert type(await ret) == int
asyncio.run(g())
Hello 👋
Setup
Adding some
assert
statements to the code in the 0.6.6. README:Expected behavior
f
returns anint
when called from a sync contextf
returns anAwaitable[int]
when called from a coroutine functionActual behavior
Running this on synchronicity 0.6.6 in Python 3.11 one observes the following:
More info
It seems that when calling a wrapped function from inside a coroutine function (in the example case: calling
f
fromg
), the wrapped function does not return a coroutine as suggested; instead the wrapped function blocks and returns the non-coroutine value. AFAICT it does this because it takes a code path that leads here: https://github.com/modal-labs/synchronicity/blob/daa99f36d3cd69d38f3d87b4138324145272de63/synchronicity/synchronizer.py#L307The prose in the README also suggests that when calling a wrapped function from a coroutine function, the value returned should be an
Awaitable
:It's curious because the README also documents how one can pass
_future=True
to a wrapped function to coax it into returning an awaitable. It's a bit confusing that this is opt in after having just read both the sample code (which throws the aboveTypeError
) and the words "In the asynchronous case, it works just like the usual business of calling asynchronous code".