Cannot load table object with sqlalchemy asyncio

Question:

I am attempting to load a table using sqlalchemy asyncio. The synchronous way I would run it is as follows:

connect_string = 'db_handle://user:password@db_address:port/database' 
# where db_handle is postgressql+psycopg2
engine = create_engine(connect_string)
table = Table(table, metadata, autoload=True, autoload_with=engine)

None of the solutions I implemented allow me (sqlalchemy core user) to load my table object to then use for querying (ie stmt=select([table.c.col])

I have attempted the following:

connect_string = 'db_handle://user:password@db_address:port/database' 
# where db_handle is postgressql+asyncpg
engine = create_async_engine(connect_string, echo=True)
metadata = MetaData()
#try 1
table = await Table(table, metadata, autoload=True, autoload_with=engine)
# error 1: sqlalchemy.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. (Background on this error at: https://sqlalche.me/e/14/xd3s)
#try 2
metadata.bind(db_engine_object)
table = await Table(table, metadata, autoload=True)
# error 2: TypeError: 'NoneType' object is not callable
#try 3
connection = db_engine_object.connect()
table = await Table(table, metadata, autoload=True, autoload_with=connection)
# error 3: sqlalchemy.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. (Background on this error at: https://sqlalche.me/e/14/xd3s)
#try 4
connection = db_engine_object.connect()
table = await Table(table, metadata, autoload=True, autoload_with=connection.run_sync())
# error 4: TypeError: run_sync() missing 1 required positional argument: 'fn'

I can’t run a query without having a table to direct the query to, and I can’t find out how to get the table object.

Asked By: Christina Stebbins

||

Answers:

This works for me. The lambda inside run_sync creates a function that run_sync can call. Credit to @zzzeek‘s answer to this discussion on GitHub.

import asyncio

import sqlalchemy as sa
from sqlalchemy.ext.asyncio import create_async_engine


async def async_main():
    engine = create_async_engine(
        "postgresql+asyncpg:///test",
        echo=True,
    )

    async with engine.begin() as conn:
        tbl = await conn.run_sync(
            lambda conn: sa.Table('users', sa.MetaData(), autoload_with=conn)
        )

    async with engine.connect() as conn:
        # select a Result, which will be delivered with buffered
        # results
        result = await conn.execute(sa.select(tbl))

        print(result.fetchall())

    # for AsyncEngine created in function scope, close and
    # clean-up pooled connections
    await engine.dispose()


asyncio.run(async_main())
Answered By: snakecharmerb
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.