This is a no-argument callable that provides a new asyncio connection,
using the asyncio database driver directly. The
:func:`.create_async_engine` function will wrap the driver-level connection
- in the appropriate structures. Pull request curtesy of Jack Wotherspoon.
+ in the appropriate structures. Pull request courtesy of Jack Wotherspoon.
.. change::
:tags: bug, orm, regression
* ``@?`` using :meth:`_postgresql.JSONB.Comparator.path_exists`
* ``#-`` using :meth:`_postgresql.JSONB.Comparator.delete_path`
- Pull request curtesy of Guilherme Martins Crocetti.
+ Pull request courtesy of Guilherme Martins Crocetti.
.. changelog::
:version: 2.0.0rc1
--- /dev/null
+.. change::
+ :tags: bug, asyncio
+ :tickets: 10421
+
+ Fixed bug with method :meth:`_asyncio.AsyncSession.close_all`
+ that was not working correctly.
+ Also added function :func:`_asyncio.close_all_sessions` that's
+ the equivalent of :func:`_orm.close_all_sessions`.
+ Pull request courtesy of Bryan不可思议.
.. autofunction:: async_session
+.. autofunction:: close_all_sessions
+
.. autoclass:: async_sessionmaker
:members:
:inherited-members:
from .session import AsyncAttrs as AsyncAttrs
from .session import AsyncSession as AsyncSession
from .session import AsyncSessionTransaction as AsyncSessionTransaction
+from .session import close_all_sessions as close_all_sessions
return self._proxied.info
@classmethod
- async def close_all(self) -> None:
+ async def close_all(cls) -> None:
r"""Close all :class:`_asyncio.AsyncSession` sessions.
.. container:: class_bases
Proxied for the :class:`_asyncio.AsyncSession` class on
behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
+ .. deprecated:: 2.0 The :meth:`.AsyncSession.close_all` method is deprecated and will be removed in a future release. Please refer to :func:`_asyncio.close_all_sessions`.
+
""" # noqa: E501
return await AsyncSession.close_all()
from .result import AsyncResult
from .result import AsyncScalarResult
from ... import util
+from ...orm import close_all_sessions as _sync_close_all_sessions
from ...orm import object_session
from ...orm import Session
from ...orm import SessionTransaction
await greenlet_spawn(self.sync_session.invalidate)
@classmethod
- async def close_all(self) -> None:
+ @util.deprecated(
+ "2.0",
+ "The :meth:`.AsyncSession.close_all` method is deprecated and will be "
+ "removed in a future release. Please refer to "
+ ":func:`_asyncio.close_all_sessions`.",
+ )
+ async def close_all(cls) -> None:
"""Close all :class:`_asyncio.AsyncSession` sessions."""
- await greenlet_spawn(self.sync_session.close_all)
+ await close_all_sessions()
async def __aenter__(self: _AS) -> _AS:
return self
return AsyncSession._retrieve_proxy_for_target(session, regenerate=False)
+async def close_all_sessions() -> None:
+ """Close all :class:`_asyncio.AsyncSession` sessions.
+
+ .. versionadded:: 2.0.23
+
+ .. seealso::
+
+ :func:`.session.close_all_sessions`
+
+ """
+ await greenlet_spawn(_sync_close_all_sessions)
+
+
_instance_state._async_provider = async_session # type: ignore
metadata.update(format_argspec_plus(spec, grouped=False))
metadata["name"] = fn.__name__
+ if inspect.iscoroutinefunction(fn):
+ metadata["prefix"] = "async "
+ metadata["target_prefix"] = "await "
+ else:
+ metadata["prefix"] = ""
+ metadata["target_prefix"] = ""
+
# look for __ positional arguments. This is a convention in
# SQLAlchemy that arguments should be passed positionally
# rather than as keyword
if "__" in repr(spec[0]):
code = (
"""\
-def %(name)s%(grouped_args)s:
- return %(target)s(%(fn)s, %(apply_pos)s)
+%(prefix)sdef %(name)s%(grouped_args)s:
+ return %(target_prefix)s%(target)s(%(fn)s, %(apply_pos)s)
"""
% metadata
)
else:
code = (
"""\
-def %(name)s%(grouped_args)s:
- return %(target)s(%(fn)s, %(apply_kw)s)
+%(prefix)sdef %(name)s%(grouped_args)s:
+ return %(target_prefix)s%(target)s(%(fn)s, %(apply_kw)s)
"""
% metadata
)
from sqlalchemy.ext.asyncio import async_sessionmaker
from sqlalchemy.ext.asyncio import AsyncAttrs
from sqlalchemy.ext.asyncio import AsyncSession
+from sqlalchemy.ext.asyncio import close_all_sessions
from sqlalchemy.ext.asyncio import exc as async_exc
from sqlalchemy.ext.asyncio.base import ReversibleProxy
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.testing import is_true
from sqlalchemy.testing import mock
from sqlalchemy.testing.assertions import expect_deprecated
+from sqlalchemy.testing.assertions import in_
from sqlalchemy.testing.assertions import is_false
+from sqlalchemy.testing.assertions import not_in
from sqlalchemy.testing.entities import ComparableEntity
from sqlalchemy.testing.provision import normalize_sequence
from .test_engine_py3k import AsyncFixture as _AsyncFixture
sync_connection.dialect.default_sequence_base,
)
+ @async_test
+ async def test_close_all(self, async_engine):
+ User = self.classes.User
+
+ s1 = AsyncSession(async_engine)
+ u1 = User()
+ s1.add(u1)
+
+ s2 = AsyncSession(async_engine)
+ u2 = User()
+ s2.add(u2)
+
+ in_(u1, s1)
+ in_(u2, s2)
+
+ await close_all_sessions()
+
+ not_in(u1, s1)
+ not_in(u2, s2)
+
+ @async_test
+ async def test_session_close_all_deprecated(self, async_engine):
+ User = self.classes.User
+
+ s1 = AsyncSession(async_engine)
+ u1 = User()
+ s1.add(u1)
+
+ s2 = AsyncSession(async_engine)
+ u2 = User()
+ s2.add(u2)
+
+ in_(u1, s1)
+ in_(u2, s2)
+
+ with expect_deprecated(
+ r"The AsyncSession.close_all\(\) method is deprecated and will "
+ "be removed in a future release. "
+ ):
+ await AsyncSession.close_all()
+
+ not_in(u1, s1)
+ not_in(u2, s2)
+
class AsyncSessionQueryTest(AsyncFixture):
@async_test