move supports_async to DatabaseFeatures class.

This commit is contained in:
Flavio Curella 2025-05-05 12:04:45 -05:00
parent 9afa1ece06
commit 2f3dbceaa8
No known key found for this signature in database
GPG key ID: 1AD0556F485696BF
11 changed files with 28 additions and 27 deletions

View file

@ -51,7 +51,7 @@ class new_connection:
async def __aenter__(self): async def __aenter__(self):
conn = connections.create_connection(self.using) conn = connections.create_connection(self.using)
if conn.supports_async is False: if conn.features.supports_async is False:
raise NotSupportedError( raise NotSupportedError(
"The database backend does not support asynchronous execution." "The database backend does not support asynchronous execution."
) )

View file

@ -39,7 +39,6 @@ class BaseDatabaseWrapper:
ops = None ops = None
vendor = "unknown" vendor = "unknown"
display_name = "unknown" display_name = "unknown"
supports_async = False
SchemaEditorClass = None SchemaEditorClass = None
# Classes instantiated in __init__(). # Classes instantiated in __init__().

View file

@ -358,6 +358,9 @@ class BaseDatabaseFeatures:
# Does the backend support negative JSON array indexing? # Does the backend support negative JSON array indexing?
supports_json_negative_indexing = True supports_json_negative_indexing = True
# Asynchronous database operations
supports_async = False
# Does the backend support column collations? # Does the backend support column collations?
supports_collation_on_charfield = True supports_collation_on_charfield = True
supports_collation_on_textfield = True supports_collation_on_textfield = True

View file

@ -94,7 +94,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
vendor = "postgresql" vendor = "postgresql"
display_name = "PostgreSQL" display_name = "PostgreSQL"
_pg_version = None _pg_version = None
supports_async = is_psycopg3
# This dictionary maps Field objects to their associated PostgreSQL column # This dictionary maps Field objects to their associated PostgreSQL column
# types, as strings. Column-type strings can contain format strings; # types, as strings. Column-type strings can contain format strings;

View file

@ -54,6 +54,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
END; END;
$$ LANGUAGE plpgsql;""" $$ LANGUAGE plpgsql;"""
requires_casted_case_in_updates = True requires_casted_case_in_updates = True
supports_async = is_psycopg3
supports_over_clause = True supports_over_clause = True
supports_frame_exclusion = True supports_frame_exclusion = True
only_supports_unbounded_with_preceding_and_following = True only_supports_unbounded_with_preceding_and_following = True

View file

@ -319,7 +319,7 @@ def debug_transaction(connection, sql):
{ {
"sql": "%s" % sql, "sql": "%s" % sql,
"time": "%.3f" % duration, "time": "%.3f" % duration,
"async": connection.supports_async, "async": connection.features.supports_async,
} }
) )
logger.debug( logger.debug(
@ -328,12 +328,12 @@ def debug_transaction(connection, sql):
sql, sql,
None, None,
connection.alias, connection.alias,
connection.supports_async, connection.features.supports_async,
extra={ extra={
"duration": duration, "duration": duration,
"sql": sql, "sql": sql,
"alias": connection.alias, "alias": connection.alias,
"async": connection.supports_async, "async": connection.features.supports_async,
}, },
) )

View file

@ -1,14 +1,12 @@
import unittest
from asgiref.sync import sync_to_async from asgiref.sync import sync_to_async
from django.db import connection, new_connection from django.db import new_connection
from django.test import TransactionTestCase from django.test import TransactionTestCase, skipUnlessDBFeature
from .models import SimpleModel from .models import SimpleModel
@unittest.skipUnless(connection.supports_async is True, "Async DB test") @skipUnlessDBFeature("supports_async")
class AsyncSyncCominglingTest(TransactionTestCase): class AsyncSyncCominglingTest(TransactionTestCase):
available_apps = ["async"] available_apps = ["async"]

View file

@ -1,11 +1,11 @@
import unittest from django.db import new_connection
from django.test import SimpleTestCase, skipUnlessDBFeature
from django.db import connection, new_connection
from django.test import SimpleTestCase
@unittest.skipUnless(connection.supports_async is True, "Async DB test") @skipUnlessDBFeature("supports_async")
class AsyncCursorTests(SimpleTestCase): class AsyncCursorTests(SimpleTestCase):
databases = {"default", "other"}
async def test_aexecute(self): async def test_aexecute(self):
async with new_connection() as conn: async with new_connection() as conn:
async with conn.acursor() as cursor: async with conn.acursor() as cursor:

View file

@ -1,11 +1,11 @@
import unittest from django.db import new_connection
from django.test import SimpleTestCase, skipUnlessDBFeature
from django.db import connection, new_connection
from django.test import SimpleTestCase
@unittest.skipUnless(connection.supports_async is True, "Async DB test") @skipUnlessDBFeature("supports_async")
class AsyncDatabaseWrapperTests(SimpleTestCase): class AsyncDatabaseWrapperTests(SimpleTestCase):
databases = {"default", "other"}
async def test_async_cursor(self): async def test_async_cursor(self):
async with new_connection() as conn: async with new_connection() as conn:
async with conn.acursor() as cursor: async with conn.acursor() as cursor:

View file

@ -20,7 +20,7 @@ from django.db.utils import (
ConnectionHandler, ConnectionHandler,
load_backend, load_backend,
) )
from django.test import SimpleTestCase, TestCase from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
from django.utils.connection import ConnectionDoesNotExist from django.utils.connection import ConnectionDoesNotExist
@ -108,6 +108,8 @@ class LoadBackendTests(SimpleTestCase):
class AsyncConnectionTests(SimpleTestCase): class AsyncConnectionTests(SimpleTestCase):
databases = {"default", "other"}
def run_pool(self, coro, count=2): def run_pool(self, coro, count=2):
def fn(): def fn():
asyncio.run(coro()) asyncio.run(coro())
@ -146,7 +148,7 @@ class AsyncConnectionTests(SimpleTestCase):
self.run_pool(coro) self.run_pool(coro)
@unittest.skipUnless(connection.supports_async is True, "Async DB test") @skipUnlessDBFeature("supports_async")
def test_new_connection_threading(self): def test_new_connection_threading(self):
async def coro(): async def coro():
assert async_connections.empty is True assert async_connections.empty is True
@ -156,7 +158,7 @@ class AsyncConnectionTests(SimpleTestCase):
self.run_pool(coro) self.run_pool(coro)
@unittest.skipUnless(connection.supports_async is True, "Async DB test") @skipUnlessDBFeature("supports_async")
async def test_new_connection(self): async def test_new_connection(self):
with self.assertRaises(ConnectionDoesNotExist): with self.assertRaises(ConnectionDoesNotExist):
async_connections.get_connection(DEFAULT_DB_ALIAS) async_connections.get_connection(DEFAULT_DB_ALIAS)
@ -177,7 +179,7 @@ class AsyncConnectionTests(SimpleTestCase):
with self.assertRaises(ConnectionDoesNotExist): with self.assertRaises(ConnectionDoesNotExist):
async_connections.get_connection(DEFAULT_DB_ALIAS) async_connections.get_connection(DEFAULT_DB_ALIAS)
@unittest.skipUnless(connection.supports_async is False, "Sync DB test") @skipUnlessDBFeature("supports_async")
async def test_new_connection_on_sync(self): async def test_new_connection_on_sync(self):
with self.assertRaises(NotSupportedError): with self.assertRaises(NotSupportedError):
async with new_connection(): async with new_connection():

View file

@ -589,8 +589,7 @@ class DurableTests(DurableTestsBase, TestCase):
pass pass
@skipUnlessDBFeature("uses_savepoints") @skipUnlessDBFeature("uses_savepoints", "supports_async")
@skipUnless(connection.supports_async is True, "Async DB test")
class AsyncTransactionTestCase(TransactionTestCase): class AsyncTransactionTestCase(TransactionTestCase):
available_apps = ["transactions"] available_apps = ["transactions"]