Skip to content

Commit fd3ca82

Browse files
zzzeekGerrit Code Review
authored andcommitted
Merge "Improve error message when await_ call errors"
2 parents b290352 + bb846d1 commit fd3ca82

File tree

4 files changed

+34
-7
lines changed

4 files changed

+34
-7
lines changed

doc/build/errors.rst

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1130,7 +1130,23 @@ with a non compatible :term:`DBAPI`.
11301130

11311131
.. seealso::
11321132

1133-
:ref:`asyncio extension <asyncio_toplevel>`
1133+
:ref:`asyncio_toplevel`
1134+
1135+
.. _error_xd2s:
1136+
1137+
MissingGreenlet
1138+
---------------
1139+
1140+
A call to the async :term:`DBAPI` was initiated outside the greenlet spawn context
1141+
usually setup by the SQLAlchemy AsyncIO proxy classes.
1142+
Usually this error happens when an IO was attempted in an unexpected
1143+
place, without using the provided async api.
1144+
When using the ORM this may be due to a lazy loading attempt, which
1145+
is unsupported when using SQLAlchemy with AsyncIO dialects.
1146+
1147+
.. seealso::
1148+
1149+
:ref:`_session_run_sync`
11341150

11351151

11361152
Core Exception Classes

lib/sqlalchemy/exc.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,15 @@ class AwaitRequired(InvalidRequestError):
294294
code = "xd1r"
295295

296296

297+
class MissingGreenlet(InvalidRequestError):
298+
r"""Error raised by the async greenlet await\_ if called while not inside
299+
the greenlet spawn context.
300+
301+
"""
302+
303+
code = "xd2s"
304+
305+
297306
class NoReferencedTableError(NoReferenceError):
298307
"""Raised by ``ForeignKey`` when the referred ``Table`` cannot be
299308
located.

lib/sqlalchemy/util/_concurrency_py3k.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ def await_only(awaitable: Coroutine) -> Any:
4444
# this is called in the context greenlet while running fn
4545
current = greenlet.getcurrent()
4646
if not isinstance(current, _AsyncIoGreenlet):
47-
raise exc.InvalidRequestError(
48-
"greenlet_spawn has not been called; can't call await_() here."
47+
raise exc.MissingGreenlet(
48+
"greenlet_spawn has not been called; can't call await_() here. "
49+
"Was IO attempted in an unexpected place?"
4950
)
5051

5152
# returns the control to the driver greenlet passing it
@@ -69,9 +70,10 @@ def await_fallback(awaitable: Coroutine) -> Any:
6970
if not isinstance(current, _AsyncIoGreenlet):
7071
loop = asyncio.get_event_loop()
7172
if loop.is_running():
72-
raise exc.InvalidRequestError(
73+
raise exc.MissingGreenlet(
7374
"greenlet_spawn has not been called and asyncio event "
74-
"loop is already running; can't call await_() here."
75+
"loop is already running; can't call await_() here. "
76+
"Was IO attempted in an unexpected place?"
7577
)
7678
return loop.run_until_complete(awaitable)
7779

test/base/test_concurrency_py3k.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def test_await_fallback_no_greenlet(self):
6363
async def test_await_only_no_greenlet(self):
6464
to_await = run1()
6565
with expect_raises_message(
66-
exc.InvalidRequestError,
66+
exc.MissingGreenlet,
6767
r"greenlet_spawn has not been called; can't call await_\(\) here.",
6868
):
6969
await_only(to_await)
@@ -86,7 +86,7 @@ def go():
8686
await_fallback(inner_await())
8787

8888
with expect_raises_message(
89-
exc.InvalidRequestError,
89+
exc.MissingGreenlet,
9090
"greenlet_spawn has not been called and asyncio event loop",
9191
):
9292
await greenlet_spawn(go)

0 commit comments

Comments
 (0)