:ref:`asyncio_orm_avoid_lazyloads` - covers most ORM scenarios where
this problem can occur and how to mitigate.
+.. _error_xd3s:
+
+No Inspection Avaliable
+-----------------------
+
+Using the :func:`_sa.inspect` function directly on an
+:class:`_asyncio.AsyncConnection` or :class:`_asyncio.AsyncEngine` object is
+not currently supported, as there is not yet an awaitable form of the
+:class:`_reflection.Inspector` object available. Instead, the object
+is used by acquiring it using the
+:func:`_sa.inspect` function in such a way that it refers to the underlying
+:attr:`_asyncio.AsyncConnection.sync_connection` attribute of the
+:class:`_asyncio.AsyncConnection` object; the :class:`_engine.Inspector` is
+then used in a "synchronous" calling style by using the
+:meth:`_asyncio.AsyncConnection.run_sync` method along with a custom function
+that performs the desired operations::
+
+ async def async_main():
+ async with engine.connect() as conn:
+ tables = await conn.run_sync(
+ lambda sync_conn: inspect(sync_conn).get_table_names()
+ )
+
+.. seealso::
+
+ :ref:`asyncio_inspector` - additional examples of using :func:`_sa.inspect`
+ with the asyncio extension.
+
Core Exception Classes
======================
.. currentmodule:: sqlalchemy.ext.asyncio
+.. _asyncio_inspector:
+
Using the Inspector to inspect schema objects
---------------------------------------------------
class ReversibleProxy:
# weakref.ref(async proxy object) -> weakref.ref(sync proxied object)
_proxy_objects = {}
+ __slots__ = ("__weakref__",)
def _assign_proxied(self, target):
if target is not None:
class StartableContext(abc.ABC):
+ __slots__ = ()
+
@abc.abstractmethod
async def start(self, is_ctxmanager=False):
pass
class ProxyComparable(ReversibleProxy):
+ __slots__ = ()
+
def __hash__(self):
return id(self)
from .base import StartableContext
from .result import AsyncResult
from ... import exc
+from ... import inspection
from ... import util
from ...engine import create_engine as _create_engine
from ...engine.base import NestedTransaction
# create a new AsyncConnection that matches this one given only the
# "sync" elements.
__slots__ = (
+ "engine",
"sync_engine",
"sync_connection",
)
raise exc.ArgumentError(
"AsyncEngine expected, got %r" % async_engine
) from e
+
+
+@inspection._inspects(AsyncConnection)
+def _no_insp_for_async_conn_yet(subject):
+ raise exc.NoInspectionAvailable(
+ "Inspection on an AsyncConnection is currently not supported. "
+ "Please use ``run_sync`` to pass a callable where it's possible "
+ "to call ``inspect`` on the passed connection.",
+ code="xd3s",
+ )
+
+
+@inspection._inspects(AsyncEngine)
+def _no_insp_for_async_engine_xyet(subject):
+ raise exc.NoInspectionAvailable(
+ "Inspection on an AsyncEngine is currently not supported. "
+ "Please obtain a connection then use ``conn.run_sync`` to pass a "
+ "callable where it's possible to call ``inspect`` on the "
+ "passed connection.",
+ code="xd3s",
+ )
from sqlalchemy import event
from sqlalchemy import exc
from sqlalchemy import func
+from sqlalchemy import inspect
from sqlalchemy import Integer
from sqlalchemy import select
from sqlalchemy import String
[mock.call(sync_conn, mock.ANY, "select 1", (), mock.ANY, False)],
)
+ @async_test
+ async def test_event_on_sync_connection(self, async_engine):
+ canary = mock.Mock()
+
+ async with async_engine.connect() as conn:
+ event.listen(conn.sync_connection, "begin", canary)
+ async with conn.begin():
+ eq_(
+ canary.mock_calls,
+ [mock.call(conn.sync_connection)],
+ )
+
+
+class AsyncInspection(EngineFixture):
+ __backend__ = True
+
+ @async_test
+ async def test_inspect_engine(self, async_engine):
+ with testing.expect_raises_message(
+ exc.NoInspectionAvailable,
+ "Inspection on an AsyncEngine is currently not supported.",
+ ):
+ inspect(async_engine)
+
+ @async_test
+ async def test_inspect_connection(self, async_engine):
+ async with async_engine.connect() as conn:
+ with testing.expect_raises_message(
+ exc.NoInspectionAvailable,
+ "Inspection on an AsyncConnection is currently not supported.",
+ ):
+ inspect(conn)
+
class AsyncResultTest(EngineFixture):
@testing.combinations(
is_not(async_connection.engine, None)
@testing.requires.predictable_gc
+ @async_test
async def test_gc_engine(self, testing_engine):
ReversibleProxy._proxy_objects.clear()
@async_test
async def test_no_async_listeners(self, async_session):
- with testing.expect_raises(
+ with testing.expect_raises_message(
NotImplementedError,
- "NotImplementedError: asynchronous events are not implemented "
- "at this time. Apply synchronous listeners to the "
- "AsyncEngine.sync_engine or "
- "AsyncConnection.sync_connection attributes.",
+ "asynchronous events are not implemented at this time. "
+ "Apply synchronous listeners to the AsyncSession.sync_session.",
):
event.listen(async_session, "before_flush", mock.Mock())