diff options
author | mike bayer <mike_mp@zzzcomputing.com> | 2021-01-23 15:33:50 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@bbpush.zzzcomputing.com> | 2021-01-23 15:33:50 +0000 |
commit | fd3ca828f05198068eaf89c1f37f63fecad72a55 (patch) | |
tree | d3e5b98fbd09ab9772b9e75b0e23b31de18a8c35 | |
parent | b290352ae7980d0263310c167da33e26be83b16b (diff) | |
parent | bb846d1650423ce8013feb93b3c8837b4c5498a0 (diff) | |
download | sqlalchemy-fd3ca828f05198068eaf89c1f37f63fecad72a55.tar.gz |
Merge "Improve error message when await_ call errors"
-rw-r--r-- | doc/build/errors.rst | 18 | ||||
-rw-r--r-- | lib/sqlalchemy/exc.py | 9 | ||||
-rw-r--r-- | lib/sqlalchemy/util/_concurrency_py3k.py | 10 | ||||
-rw-r--r-- | test/base/test_concurrency_py3k.py | 4 |
4 files changed, 34 insertions, 7 deletions
diff --git a/doc/build/errors.rst b/doc/build/errors.rst index 67a8a29b0..7d767a711 100644 --- a/doc/build/errors.rst +++ b/doc/build/errors.rst @@ -1130,7 +1130,23 @@ with a non compatible :term:`DBAPI`. .. seealso:: - :ref:`asyncio extension <asyncio_toplevel>` + :ref:`asyncio_toplevel` + +.. _error_xd2s: + +MissingGreenlet +--------------- + +A call to the async :term:`DBAPI` was initiated outside the greenlet spawn context +usually setup by the SQLAlchemy AsyncIO proxy classes. +Usually this error happens when an IO was attempted in an unexpected +place, without using the provided async api. +When using the ORM this may be due to a lazy loading attempt, which +is unsupported when using SQLAlchemy with AsyncIO dialects. + +.. seealso:: + + :ref:`_session_run_sync` Core Exception Classes diff --git a/lib/sqlalchemy/exc.py b/lib/sqlalchemy/exc.py index 08b1bb060..289b8dfab 100644 --- a/lib/sqlalchemy/exc.py +++ b/lib/sqlalchemy/exc.py @@ -294,6 +294,15 @@ class AwaitRequired(InvalidRequestError): code = "xd1r" +class MissingGreenlet(InvalidRequestError): + r"""Error raised by the async greenlet await\_ if called while not inside + the greenlet spawn context. + + """ + + code = "xd2s" + + class NoReferencedTableError(NoReferenceError): """Raised by ``ForeignKey`` when the referred ``Table`` cannot be located. diff --git a/lib/sqlalchemy/util/_concurrency_py3k.py b/lib/sqlalchemy/util/_concurrency_py3k.py index 663d3e0f4..8edd057ef 100644 --- a/lib/sqlalchemy/util/_concurrency_py3k.py +++ b/lib/sqlalchemy/util/_concurrency_py3k.py @@ -44,8 +44,9 @@ def await_only(awaitable: Coroutine) -> Any: # this is called in the context greenlet while running fn current = greenlet.getcurrent() if not isinstance(current, _AsyncIoGreenlet): - raise exc.InvalidRequestError( - "greenlet_spawn has not been called; can't call await_() here." + raise exc.MissingGreenlet( + "greenlet_spawn has not been called; can't call await_() here. " + "Was IO attempted in an unexpected place?" ) # returns the control to the driver greenlet passing it @@ -69,9 +70,10 @@ def await_fallback(awaitable: Coroutine) -> Any: if not isinstance(current, _AsyncIoGreenlet): loop = asyncio.get_event_loop() if loop.is_running(): - raise exc.InvalidRequestError( + raise exc.MissingGreenlet( "greenlet_spawn has not been called and asyncio event " - "loop is already running; can't call await_() here." + "loop is already running; can't call await_() here. " + "Was IO attempted in an unexpected place?" ) return loop.run_until_complete(awaitable) diff --git a/test/base/test_concurrency_py3k.py b/test/base/test_concurrency_py3k.py index 8eabece92..1492bc186 100644 --- a/test/base/test_concurrency_py3k.py +++ b/test/base/test_concurrency_py3k.py @@ -63,7 +63,7 @@ class TestAsyncioCompat(fixtures.TestBase): async def test_await_only_no_greenlet(self): to_await = run1() with expect_raises_message( - exc.InvalidRequestError, + exc.MissingGreenlet, r"greenlet_spawn has not been called; can't call await_\(\) here.", ): await_only(to_await) @@ -86,7 +86,7 @@ class TestAsyncioCompat(fixtures.TestBase): await_fallback(inner_await()) with expect_raises_message( - exc.InvalidRequestError, + exc.MissingGreenlet, "greenlet_spawn has not been called and asyncio event loop", ): await greenlet_spawn(go) |