17
17
from sniffio import current_async_library_cvar
18
18
19
19
import attr
20
- from async_generator import isasyncgen
21
20
from sortedcontainers import SortedDict
22
21
from outcome import Error , Value , capture
23
22
36
35
)
37
36
from .. import _core
38
37
from .._deprecate import deprecated
39
- from .._util import Final , NoPublicConstructor
38
+ from .._util import Final , NoPublicConstructor , coroutine_or_error
40
39
41
40
_NO_SEND = object ()
42
41
@@ -1247,86 +1246,7 @@ def spawn_impl(self, async_fn, args, nursery, name, *, system_task=False):
1247
1246
# Call the function and get the coroutine object, while giving helpful
1248
1247
# errors for common mistakes.
1249
1248
######
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 )
1330
1250
1331
1251
if name is None :
1332
1252
name = async_fn
@@ -1353,6 +1273,9 @@ async def python_wrapper(orig_coro):
1353
1273
LOCALS_KEY_KI_PROTECTION_ENABLED , system_task
1354
1274
)
1355
1275
1276
+ ######
1277
+ # Set up the Task object
1278
+ ######
1356
1279
task = Task ._create (
1357
1280
coro = coro ,
1358
1281
parent_nursery = nursery ,
0 commit comments