1717from sniffio import current_async_library_cvar
1818
1919import attr
20- from async_generator import isasyncgen
2120from sortedcontainers import SortedDict
2221from outcome import Error , Value , capture
2322
3635)
3736from .. import _core
3837from .._deprecate import deprecated
39- from .._util import Final , NoPublicConstructor
38+ from .._util import Final , NoPublicConstructor , coroutine_or_error
4039
4140_NO_SEND = object ()
4241
@@ -1247,86 +1246,7 @@ def spawn_impl(self, async_fn, args, nursery, name, *, system_task=False):
12471246 # Call the function and get the coroutine object, while giving helpful
12481247 # errors for common mistakes.
12491248 ######
1250-
1251- def _return_value_looks_like_wrong_library (value ):
1252- # Returned by legacy @asyncio.coroutine functions, which includes
1253- # a surprising proportion of asyncio builtins.
1254- if isinstance (value , collections .abc .Generator ):
1255- return True
1256- # The protocol for detecting an asyncio Future-like object
1257- if getattr (value , "_asyncio_future_blocking" , None ) is not None :
1258- return True
1259- # This janky check catches tornado Futures and twisted Deferreds.
1260- # By the time we're calling this function, we already know
1261- # something has gone wrong, so a heuristic is pretty safe.
1262- if value .__class__ .__name__ in ("Future" , "Deferred" ):
1263- return True
1264- return False
1265-
1266- try :
1267- coro = async_fn (* args )
1268- except TypeError :
1269- # Give good error for: nursery.start_soon(trio.sleep(1))
1270- if isinstance (async_fn , collections .abc .Coroutine ):
1271- raise TypeError (
1272- "Trio was expecting an async function, but instead it got "
1273- "a coroutine object {async_fn!r}\n "
1274- "\n "
1275- "Probably you did something like:\n "
1276- "\n "
1277- " trio.run({async_fn.__name__}(...)) # incorrect!\n "
1278- " nursery.start_soon({async_fn.__name__}(...)) # incorrect!\n "
1279- "\n "
1280- "Instead, you want (notice the parentheses!):\n "
1281- "\n "
1282- " trio.run({async_fn.__name__}, ...) # correct!\n "
1283- " nursery.start_soon({async_fn.__name__}, ...) # correct!"
1284- .format (async_fn = async_fn )
1285- ) from None
1286-
1287- # Give good error for: nursery.start_soon(future)
1288- if _return_value_looks_like_wrong_library (async_fn ):
1289- raise TypeError (
1290- "Trio was expecting an async function, but instead it got "
1291- "{!r} – are you trying to use a library written for "
1292- "asyncio/twisted/tornado or similar? That won't work "
1293- "without some sort of compatibility shim."
1294- .format (async_fn )
1295- ) from None
1296-
1297- raise
1298-
1299- # We can't check iscoroutinefunction(async_fn), because that will fail
1300- # for things like functools.partial objects wrapping an async
1301- # function. So we have to just call it and then check whether the
1302- # return value is a coroutine object.
1303- if not isinstance (coro , collections .abc .Coroutine ):
1304- # Give good error for: nursery.start_soon(func_returning_future)
1305- if _return_value_looks_like_wrong_library (coro ):
1306- raise TypeError (
1307- "start_soon got unexpected {!r} – are you trying to use a "
1308- "library written for asyncio/twisted/tornado or similar? "
1309- "That won't work without some sort of compatibility shim."
1310- .format (coro )
1311- )
1312-
1313- if isasyncgen (coro ):
1314- raise TypeError (
1315- "start_soon expected an async function but got an async "
1316- "generator {!r}" .format (coro )
1317- )
1318-
1319- # Give good error for: nursery.start_soon(some_sync_fn)
1320- raise TypeError (
1321- "Trio expected an async function, but {!r} appears to be "
1322- "synchronous" .format (
1323- getattr (async_fn , "__qualname__" , async_fn )
1324- )
1325- )
1326-
1327- ######
1328- # Set up the Task object
1329- ######
1249+ coro = coroutine_or_error (async_fn , * args )
13301250
13311251 if name is None :
13321252 name = async_fn
@@ -1353,6 +1273,9 @@ async def python_wrapper(orig_coro):
13531273 LOCALS_KEY_KI_PROTECTION_ENABLED , system_task
13541274 )
13551275
1276+ ######
1277+ # Set up the Task object
1278+ ######
13561279 task = Task ._create (
13571280 coro = coro ,
13581281 parent_nursery = nursery ,
0 commit comments