From 56f7b5391a34eb013fee7150a72062756d2da11a Mon Sep 17 00:00:00 2001 From: Federico Caselli Date: Tue, 5 Dec 2023 23:18:57 +0100 Subject: [PATCH] Deprecate async_fallback mode Deprecate the async_fallback mode and await_fallback function. Additionally, this commit modifies the use of athrow to no longer use the "util" compat function which is removed; this has since been determined that it's not needed. Change-Id: I37e37400b6954f5ac7c957790932838862930453 --- .../unreleased_20/async_fallback.rst | 7 +++++++ lib/sqlalchemy/dialects/mysql/base.py | 2 +- lib/sqlalchemy/dialects/postgresql/asyncpg.py | 11 ---------- lib/sqlalchemy/engine/create.py | 8 ++++++++ lib/sqlalchemy/ext/asyncio/base.py | 2 +- lib/sqlalchemy/util/__init__.py | 1 - lib/sqlalchemy/util/_concurrency_py3k.py | 5 +++++ lib/sqlalchemy/util/compat.py | 20 ------------------- test/engine/test_deprecations.py | 18 +++++++++++++++++ 9 files changed, 40 insertions(+), 34 deletions(-) create mode 100644 doc/build/changelog/unreleased_20/async_fallback.rst diff --git a/doc/build/changelog/unreleased_20/async_fallback.rst b/doc/build/changelog/unreleased_20/async_fallback.rst new file mode 100644 index 0000000000..a0eccb5580 --- /dev/null +++ b/doc/build/changelog/unreleased_20/async_fallback.rst @@ -0,0 +1,7 @@ +.. change:: + :tags: change, asyncio + + The ``async_fallback`` dialect argument is now deprecated, and will be + removed in SQLAlchemy 2.1. This flag has not been used for SQLAlchemy's + test suite for some time. asyncio dialects can still run in a synchronous + style by running code within a greenlet using :func:`_util.greenlet_spawn`. diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index 749d42ea12..c51b3eefca 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -1571,7 +1571,7 @@ class MySQLCompiler(compiler.SQLCompiler): def get_select_precolumns(self, select, **kw): """Add special MySQL keywords in place of DISTINCT. - .. deprecated:: 1.4 This usage is deprecated. + .. deprecated:: 1.4 This usage is deprecated. :meth:`_expression.Select.prefix_with` should be used for special keywords at the start of a SELECT. diff --git a/lib/sqlalchemy/dialects/postgresql/asyncpg.py b/lib/sqlalchemy/dialects/postgresql/asyncpg.py index acfd2e5afb..00dbe6d959 100644 --- a/lib/sqlalchemy/dialects/postgresql/asyncpg.py +++ b/lib/sqlalchemy/dialects/postgresql/asyncpg.py @@ -25,17 +25,6 @@ This dialect should normally be used only with the from sqlalchemy.ext.asyncio import create_async_engine engine = create_async_engine("postgresql+asyncpg://user:pass@hostname/dbname") -The dialect can also be run as a "synchronous" dialect within the -:func:`_sa.create_engine` function, which will pass "await" calls into -an ad-hoc event loop. This mode of operation is of **limited use** -and is for special testing scenarios only. The mode can be enabled by -adding the SQLAlchemy-specific flag ``async_fallback`` to the URL -in conjunction with :func:`_sa.create_engine`:: - - # for testing purposes only; do not use in production! - engine = create_engine("postgresql+asyncpg://user:pass@hostname/dbname?async_fallback=true") - - .. versionadded:: 1.4 .. note:: diff --git a/lib/sqlalchemy/engine/create.py b/lib/sqlalchemy/engine/create.py index 684550e558..86e801f8d5 100644 --- a/lib/sqlalchemy/engine/create.py +++ b/lib/sqlalchemy/engine/create.py @@ -616,6 +616,14 @@ def create_engine(url: Union[str, _url.URL], **kwargs: Any) -> Engine: # assemble connection arguments (cargs_tup, cparams) = dialect.create_connect_args(u) cparams.update(pop_kwarg("connect_args", {})) + + if "async_fallback" in cparams and util.asbool(cparams["async_fallback"]): + util.warn_deprecated( + "The async_fallback dialect argument is deprecated and will be " + "removed in SQLAlchemy 2.1.", + "2.0", + ) + cargs = list(cargs_tup) # allow mutability # look for existing pool or create diff --git a/lib/sqlalchemy/ext/asyncio/base.py b/lib/sqlalchemy/ext/asyncio/base.py index 251f521254..69d9cce55c 100644 --- a/lib/sqlalchemy/ext/asyncio/base.py +++ b/lib/sqlalchemy/ext/asyncio/base.py @@ -182,7 +182,7 @@ class GeneratorStartableContext(StartableContext[_T_co]): # tell if we get the same exception back value = typ() try: - await util.athrow(self.gen, typ, value, traceback) + await self.gen.athrow(value) except StopAsyncIteration as exc: # Suppress StopIteration *unless* it's the same exception that # was passed to throw(). This prevents a StopIteration diff --git a/lib/sqlalchemy/util/__init__.py b/lib/sqlalchemy/util/__init__.py index c804f96887..6f409c9e29 100644 --- a/lib/sqlalchemy/util/__init__.py +++ b/lib/sqlalchemy/util/__init__.py @@ -49,7 +49,6 @@ from ._collections import WeakPopulateDict as WeakPopulateDict from ._collections import WeakSequence as WeakSequence from .compat import anext_ as anext_ from .compat import arm as arm -from .compat import athrow as athrow from .compat import b as b from .compat import b64decode as b64decode from .compat import b64encode as b64encode diff --git a/lib/sqlalchemy/util/_concurrency_py3k.py b/lib/sqlalchemy/util/_concurrency_py3k.py index 83201dd95c..47da59779f 100644 --- a/lib/sqlalchemy/util/_concurrency_py3k.py +++ b/lib/sqlalchemy/util/_concurrency_py3k.py @@ -138,6 +138,11 @@ def await_fallback(awaitable: Awaitable[_T]) -> _T: :param awaitable: The coroutine to call. + .. deprecated:: 2.0.24 The ``await_fallback()`` function will be removed + in SQLAlchemy 2.1. Use :func:`_util.await_only` instead, running the + function / program / etc. within a top-level greenlet that is set up + using :func:`_util.greenlet_spawn`. + """ # this is called in the context greenlet while running fn diff --git a/lib/sqlalchemy/util/compat.py b/lib/sqlalchemy/util/compat.py index a4464324cd..73cdafea5d 100644 --- a/lib/sqlalchemy/util/compat.py +++ b/lib/sqlalchemy/util/compat.py @@ -19,8 +19,6 @@ import platform import sys import typing from typing import Any -from typing import AsyncGenerator -from typing import Awaitable from typing import Callable from typing import Dict from typing import Iterable @@ -102,24 +100,6 @@ def inspect_getfullargspec(func: Callable[..., Any]) -> FullArgSpec: ) -if py312: - # we are 95% certain this form of athrow works in former Python - # versions, however we are unable to get confirmation; - # see https://github.com/python/cpython/issues/105269 where have - # been unable to get a straight answer so far - def athrow( # noqa - gen: AsyncGenerator[_T_co, Any], typ: Any, value: Any, traceback: Any - ) -> Awaitable[_T_co]: - return gen.athrow(value) - -else: - - def athrow( # noqa - gen: AsyncGenerator[_T_co, Any], typ: Any, value: Any, traceback: Any - ) -> Awaitable[_T_co]: - return gen.athrow(typ, value, traceback) - - if py39: # python stubs don't have a public type for this. not worth # making a protocol diff --git a/test/engine/test_deprecations.py b/test/engine/test_deprecations.py index f6fa21f29d..9041a6af10 100644 --- a/test/engine/test_deprecations.py +++ b/test/engine/test_deprecations.py @@ -500,3 +500,21 @@ class ImplicitReturningFlagTest(fixtures.TestBase): ) # parameter has no effect + + +class AsyncFallbackDeprecationTest(fixtures.TestBase): + __requires__ = ("greenlet",) + + def test_async_fallback_deprecated(self): + with assertions.expect_deprecated( + "The async_fallback dialect argument is deprecated and will be " + "removed in SQLAlchemy 2.1.", + ): + create_engine( + "postgresql+asyncpg://?async_fallback=True", module=mock.Mock() + ) + + def test_async_fallback_false_is_ok(self): + create_engine( + "postgresql+asyncpg://?async_fallback=False", module=mock.Mock() + ) -- 2.47.2