MagicStack / asyncpg

A fast PostgreSQL Database Client Library for Python/asyncio.
Apache License 2.0
6.86k stars 396 forks source link

when using Asyncsession.stream() method, TypeError: object method can't be used in 'await' expression #1044

Closed yuheinoda closed 1 year ago

yuheinoda commented 1 year ago

Describe the bug

when using Asyncsession.stream() method, TypeError: object method can't be used in 'await' expression

How can I work around this error?

Optional link from https://docs.sqlalchemy.org which documents the behavior that is expected

https://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html#sqlalchemy.ext.asyncio.AsyncSession.stream

asyncpg version

version = "0.27.0"

Do you use pgbouncer?

No

Did you install asyncpg with pip?

No, I use poetry.

SQLAlchemy Version in Use

sqlalchemy 2.0.17

DBAPI (i.e. the database driver)

asyncpg

Database Vendor and Major Version

postgreSQL 13

Python Version

3.10

Operating system

OSX

To Reproduce


`Genre model`
class Genre(Base):
    __tablename__ = 'genres'

    id: int = Column(Integer, primary_key=True, autoincrement=True)
    genre_name: str = Column(String(1024), nullable=False, unique=True)
    songs: Mapped[List["Song"]] = relationship("Song", secondary=song_genre_association, back_populates="genres")

`Song model`
class Song(Base):
    __tablename__ = 'songs'

    id: int = Column(Integer, primary_key=True, autoincrement=True)
    title: str = Column(String(1024), nullable=False, unique=True)
    done: bool = Column(Boolean, default=False, nullable=False)
    genres: Mapped[List["Genre"]] = relationship("Genre", secondary=song_genre_association, back_populates="songs")

    @classmethod
    async def read_all(cls, session: AsyncSession) -> AsyncIterator["Song"]:
        statement = select(cls.title, Genre.genre_name)
        result = await session.stream(statement)
        async for row in result:
            yield Song(title=row.title, genres=[Genre(genre_name=row.genre_name)])

Error

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py", line 428, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/fastapi/applications.py", line 276, in __call__
    await super().__call__(scope, receive, send)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/starlette/applications.py", line 122, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/starlette/routing.py", line 718, in __call__
    await route.handle(scope, receive, send)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/fastapi/routing.py", line 237, in app
    raw_response = await run_endpoint_function(
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/fastapi/routing.py", line 163, in run_endpoint_function
    return await dependant.call(**values)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/fastapi_fullstack/routers/songs.py", line 16, in list_all_songs
    return SongReadAllResponse(songs=[song async for song in use_case.execute()])
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/fastapi_fullstack/routers/songs.py", line 16, in <listcomp>
    return SongReadAllResponse(songs=[song async for song in use_case.execute()])
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/fastapi_fullstack/crud/songs.py", line 42, in execute
    async for song in Song.read_all(session):
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/fastapi_fullstack/models/songs.py", line 28, in read_all
    result = await session.stream(statement)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/ext/asyncio/session.py", line 645, in stream
    result = await greenlet_spawn(
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 190, in greenlet_spawn
    result = context.throw(*sys.exc_info())
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 2246, in execute
    return self._execute_internal(
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 2131, in _execute_internal
    conn = self._connection_for_bind(bind)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 1998, in _connection_for_bind
    return trans._connection_for_bind(engine, execution_options)
  File "<string>", line 2, in _connection_for_bind
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/orm/state_changes.py", line 139, in _go
    ret_value = fn(self, *arg, **kw)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 1123, in _connection_for_bind
    conn = bind.connect()
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 3264, in connect
    return self._connection_cls(self)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 145, in __init__
    self._dbapi_connection = engine.raw_connection()
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 3288, in raw_connection
    return self.pool.connect()
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 452, in connect
    return _ConnectionFairy._checkout(self)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 1267, in _checkout
    fairy = _ConnectionRecord.checkout(pool)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 716, in checkout
    rec = pool._do_get()
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/pool/impl.py", line 169, in _do_get
    with util.safe_reraise():
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/util/langhelpers.py", line 147, in __exit__
    raise exc_value.with_traceback(exc_tb)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/pool/impl.py", line 167, in _do_get
    return self._create_connection()
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 393, in _create_connection
    return _ConnectionRecord(self)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 678, in __init__
    self.__connect()
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 916, in __connect
    )._exec_w_sync_on_first_run(self.dbapi_connection, self)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/event/attr.py", line 473, in _exec_w_sync_on_first_run
    self(*args, **kw)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/event/attr.py", line 487, in __call__
    fn(*args, **kw)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/util/langhelpers.py", line 1913, in go
    return once_fn(*arg, **kw)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/engine/create.py", line 732, in first_connect
    dialect.initialize(c)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/dialects/postgresql/base.py", line 3038, in initialize
    super().initialize(connection)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 513, in initialize
    self.server_version_info = self._get_server_version_info(
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/dialects/postgresql/base.py", line 3222, in _get_server_version_info
    v = connection.exec_driver_sql("select pg_catalog.version()").scalar()
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1774, in exec_driver_sql
    ret = self._execute_context(
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1844, in _execute_context
    return self._exec_single_context(
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1984, in _exec_single_context
    self._handle_dbapi_exception(
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 2342, in _handle_dbapi_exception
    raise exc_info[1].with_traceback(exc_info[2])
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1965, in _exec_single_context
    self.dialect.do_execute(
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 921, in do_execute
    cursor.execute(statement, parameters)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 561, in execute
    self._adapt_connection.await_(
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 125, in await_only
    return current.driver.switch(awaitable)  # type: ignore[no-any-return]
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 185, in greenlet_spawn
    value = await result
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 498, in _prepare_and_execute
    await adapt_connection._start_transaction()
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 818, in _start_transaction
    self._handle_exception(error)
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 780, in _handle_exception
    raise error
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 816, in _start_transaction
    await self._transaction.start()
  File "/Users/nodayuuhei/handson/fastapi_fullstack/fastapi_fullstack/.venv/lib/python3.10/site-packages/asyncpg/transaction.py", line 138, in start
    await self._connection.execute
TypeError: object method can't be used in 'await' expression

Additional context

elprans commented 1 year ago

Seems like an SQLAlchemy bug to me (it probably overrides the Connection class in a weird way). I suggest reporting it there.