diff --git a/django/contrib/auth/decorators.py b/django/contrib/auth/decorators.py index 4d62aec93a03..3407555852e1 100644 --- a/django/contrib/auth/decorators.py +++ b/django/contrib/auth/decorators.py @@ -1,7 +1,8 @@ from functools import wraps +from inspect import iscoroutinefunction from urllib.parse import urlsplit -from asgiref.sync import async_to_sync, iscoroutinefunction, sync_to_async +from asgiref.sync import async_to_sync, sync_to_async from django.conf import settings from django.contrib.auth import REDIRECT_FIELD_NAME diff --git a/django/contrib/auth/middleware.py b/django/contrib/auth/middleware.py index bd8a1c108084..a28e1705a378 100644 --- a/django/contrib/auth/middleware.py +++ b/django/contrib/auth/middleware.py @@ -1,8 +1,7 @@ from functools import partial +from inspect import iscoroutinefunction, markcoroutinefunction from urllib.parse import urlsplit -from asgiref.sync import iscoroutinefunction, markcoroutinefunction - from django.conf import settings from django.contrib import auth from django.contrib.auth import REDIRECT_FIELD_NAME, load_backend diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py index af3e0c3a504e..d65a5edcb6a6 100644 --- a/django/core/handlers/base.py +++ b/django/core/handlers/base.py @@ -1,8 +1,9 @@ import asyncio import logging import types +from inspect import iscoroutinefunction -from asgiref.sync import async_to_sync, iscoroutinefunction, sync_to_async +from asgiref.sync import async_to_sync, sync_to_async from django.conf import settings from django.core.exceptions import ImproperlyConfigured, MiddlewareNotUsed diff --git a/django/core/handlers/exception.py b/django/core/handlers/exception.py index 1243734705e8..4adc9d7c6af2 100644 --- a/django/core/handlers/exception.py +++ b/django/core/handlers/exception.py @@ -1,8 +1,9 @@ import logging import sys from functools import wraps +from inspect import iscoroutinefunction -from asgiref.sync import iscoroutinefunction, sync_to_async +from asgiref.sync import sync_to_async from django.conf import settings from django.core import signals diff --git a/django/core/paginator.py b/django/core/paginator.py index aabc2f85321b..d1842d6adb67 100644 --- a/django/core/paginator.py +++ b/django/core/paginator.py @@ -3,7 +3,7 @@ import warnings from math import ceil -from asgiref.sync import iscoroutinefunction, sync_to_async +from asgiref.sync import sync_to_async from django.utils.deprecation import RemovedInDjango70Warning from django.utils.functional import cached_property @@ -266,7 +266,7 @@ async def acount(self): return self._cache_acount c = getattr(self.object_list, "acount", None) if ( - iscoroutinefunction(c) + inspect.iscoroutinefunction(c) and not inspect.isbuiltin(c) and method_has_no_args(c) ): diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py index 21d77bd88429..d4a6eff2bcf1 100644 --- a/django/dispatch/dispatcher.py +++ b/django/dispatch/dispatcher.py @@ -3,8 +3,9 @@ import logging import threading import weakref +from inspect import iscoroutinefunction -from asgiref.sync import async_to_sync, iscoroutinefunction, sync_to_async +from asgiref.sync import async_to_sync, sync_to_async from django.utils.inspect import func_accepts_kwargs diff --git a/django/test/testcases.py b/django/test/testcases.py index c56fa52806ea..5f83612fe532 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -11,6 +11,7 @@ from copy import copy, deepcopy from difflib import get_close_matches from functools import wraps +from inspect import iscoroutinefunction from unittest import mock from unittest.suite import _DebugResult from unittest.util import safe_repr @@ -25,7 +26,7 @@ ) from urllib.request import url2pathname -from asgiref.sync import async_to_sync, iscoroutinefunction +from asgiref.sync import async_to_sync from django.apps import apps from django.conf import settings diff --git a/django/test/utils.py b/django/test/utils.py index 3661010463d5..ec888b358882 100644 --- a/django/test/utils.py +++ b/django/test/utils.py @@ -8,14 +8,13 @@ import warnings from contextlib import contextmanager from functools import wraps +from inspect import iscoroutinefunction from io import StringIO from itertools import chain from types import SimpleNamespace from unittest import TestCase, skipIf, skipUnless from xml.dom.minidom import Node, parseString -from asgiref.sync import iscoroutinefunction - from django.apps import apps from django.apps.registry import Apps from django.conf import UserSettingsHolder, settings diff --git a/django/utils/decorators.py b/django/utils/decorators.py index 83586dfc2cc9..7e4d724b462e 100644 --- a/django/utils/decorators.py +++ b/django/utils/decorators.py @@ -1,8 +1,7 @@ "Functions that help with dynamically creating decorators for views." from functools import partial, update_wrapper, wraps - -from asgiref.sync import iscoroutinefunction, markcoroutinefunction +from inspect import iscoroutinefunction, markcoroutinefunction class classonlymethod(classmethod): diff --git a/django/utils/deprecation.py b/django/utils/deprecation.py index b10fb58c6545..6b017cd91731 100644 --- a/django/utils/deprecation.py +++ b/django/utils/deprecation.py @@ -3,8 +3,9 @@ import os import warnings from collections import Counter +from inspect import iscoroutinefunction, markcoroutinefunction -from asgiref.sync import iscoroutinefunction, markcoroutinefunction, sync_to_async +from asgiref.sync import sync_to_async import django diff --git a/django/views/decorators/cache.py b/django/views/decorators/cache.py index aa1679baff1c..f08d30846c2b 100644 --- a/django/views/decorators/cache.py +++ b/django/views/decorators/cache.py @@ -1,6 +1,5 @@ from functools import wraps - -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction from django.middleware.cache import CacheMiddleware from django.utils.cache import add_never_cache_headers, patch_cache_control diff --git a/django/views/decorators/clickjacking.py b/django/views/decorators/clickjacking.py index c20fa59d2a29..105f0ed11a62 100644 --- a/django/views/decorators/clickjacking.py +++ b/django/views/decorators/clickjacking.py @@ -1,6 +1,5 @@ from functools import wraps - -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction def xframe_options_deny(view_func): diff --git a/django/views/decorators/common.py b/django/views/decorators/common.py index d09b0bfee47d..d4e9a1888e51 100644 --- a/django/views/decorators/common.py +++ b/django/views/decorators/common.py @@ -1,6 +1,5 @@ from functools import wraps - -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction def no_append_slash(view_func): diff --git a/django/views/decorators/csp.py b/django/views/decorators/csp.py index 9033d9cdf0ee..1c537fe1f2c5 100644 --- a/django/views/decorators/csp.py +++ b/django/views/decorators/csp.py @@ -1,6 +1,5 @@ from functools import wraps - -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction def _make_csp_decorator(config_attr_name, config_attr_value): diff --git a/django/views/decorators/csrf.py b/django/views/decorators/csrf.py index 64c478b42ef4..9f13114580c3 100644 --- a/django/views/decorators/csrf.py +++ b/django/views/decorators/csrf.py @@ -1,6 +1,5 @@ from functools import wraps - -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction from django.middleware.csrf import CsrfViewMiddleware, get_token from django.utils.decorators import decorator_from_middleware diff --git a/django/views/decorators/debug.py b/django/views/decorators/debug.py index 506aaeb64d2b..38ccef4c92ce 100644 --- a/django/views/decorators/debug.py +++ b/django/views/decorators/debug.py @@ -1,7 +1,6 @@ import inspect from functools import wraps - -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction from django.http import HttpRequest diff --git a/django/views/decorators/http.py b/django/views/decorators/http.py index 408039937cbd..3bafa880b652 100644 --- a/django/views/decorators/http.py +++ b/django/views/decorators/http.py @@ -4,8 +4,7 @@ import datetime from functools import wraps - -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction from django.http import HttpResponseNotAllowed from django.middleware.http import ConditionalGetMiddleware diff --git a/django/views/decorators/vary.py b/django/views/decorators/vary.py index 9beab8b4db84..b4c467a8807a 100644 --- a/django/views/decorators/vary.py +++ b/django/views/decorators/vary.py @@ -1,6 +1,5 @@ from functools import wraps - -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction from django.utils.cache import patch_vary_headers diff --git a/django/views/generic/base.py b/django/views/generic/base.py index a961dfddee55..649d871cf738 100644 --- a/django/views/generic/base.py +++ b/django/views/generic/base.py @@ -1,8 +1,7 @@ import logging +from inspect import iscoroutinefunction, markcoroutinefunction from urllib.parse import urlparse -from asgiref.sync import iscoroutinefunction, markcoroutinefunction - from django.core.exceptions import ImproperlyConfigured from django.http import ( HttpResponse, diff --git a/docs/topics/async.txt b/docs/topics/async.txt index 5cf9fd46242a..2607381ad274 100644 --- a/docs/topics/async.txt +++ b/docs/topics/async.txt @@ -28,9 +28,9 @@ class-based view, this means declaring the HTTP method handlers, such as .. note:: - Django uses ``asgiref.sync.iscoroutinefunction`` to test if your view is + Django uses ``inspect.iscoroutinefunction`` to test if your view is asynchronous or not. If you implement your own method of returning a - coroutine, ensure you use ``asgiref.sync.markcoroutinefunction`` so this + coroutine, ensure you use ``inspect.markcoroutinefunction`` so this function returns ``True``. Under a WSGI server, async views will run in their own, one-off event loop. diff --git a/docs/topics/http/middleware.txt b/docs/topics/http/middleware.txt index 1c3b3c2a26cd..8bca89f56de6 100644 --- a/docs/topics/http/middleware.txt +++ b/docs/topics/http/middleware.txt @@ -318,7 +318,7 @@ If your middleware has both ``sync_capable = True`` and ``async_capable = True``, then Django will pass it the request without converting it. In this case, you can work out if your middleware will receive async requests by checking if the ``get_response`` object you are passed is a -coroutine function, using ``asgiref.sync.iscoroutinefunction``. +coroutine function, using ``inspect.iscoroutinefunction``. The ``django.utils.decorators`` module contains :func:`~django.utils.decorators.sync_only_middleware`, @@ -337,7 +337,7 @@ at an additional performance penalty. Here's an example of how to create a middleware function that supports both:: - from asgiref.sync import iscoroutinefunction + from inspect import iscoroutinefunction from django.utils.decorators import sync_and_async_middleware @@ -373,7 +373,7 @@ Here's an example of how to create a middleware function that supports both:: When using an asynchronous class-based middleware, you must ensure that instances are correctly marked as coroutine functions:: - from asgiref.sync import iscoroutinefunction, markcoroutinefunction + from inspect import iscoroutinefunction, markcoroutinefunction class AsyncMiddleware: diff --git a/tests/admin_changelist/tests.py b/tests/admin_changelist/tests.py index e0772a3e6d4a..330859bcf438 100644 --- a/tests/admin_changelist/tests.py +++ b/tests/admin_changelist/tests.py @@ -914,6 +914,7 @@ def test_exact_lookup_with_more_lenient_formfield(self): cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, [obj]) + @skipUnlessDBFeature("supports_primitives_in_json_field") def test_exact_lookup_validates_each_field_independently(self): """ Each field validates the search term independently without leaking diff --git a/tests/async/tests.py b/tests/async/tests.py index 6ca5c989b06c..43051c369a4b 100644 --- a/tests/async/tests.py +++ b/tests/async/tests.py @@ -1,8 +1,9 @@ import asyncio import os +from inspect import iscoroutinefunction from unittest import mock -from asgiref.sync import async_to_sync, iscoroutinefunction +from asgiref.sync import async_to_sync from django.core.cache import DEFAULT_CACHE_ALIAS, caches from django.core.exceptions import ImproperlyConfigured, SynchronousOnlyOperation diff --git a/tests/auth_tests/test_decorators.py b/tests/auth_tests/test_decorators.py index 2c3f93d2abf8..08f6186e34eb 100644 --- a/tests/auth_tests/test_decorators.py +++ b/tests/auth_tests/test_decorators.py @@ -1,4 +1,4 @@ -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction from django.conf import settings from django.contrib.auth import models diff --git a/tests/decorators/test_cache.py b/tests/decorators/test_cache.py index 513ff7e7114e..1aca6967e0b6 100644 --- a/tests/decorators/test_cache.py +++ b/tests/decorators/test_cache.py @@ -1,7 +1,6 @@ +from inspect import iscoroutinefunction from unittest import mock -from asgiref.sync import iscoroutinefunction - from django.http import HttpRequest, HttpResponse from django.test import SimpleTestCase from django.utils.decorators import method_decorator diff --git a/tests/decorators/test_clickjacking.py b/tests/decorators/test_clickjacking.py index fe4c551648d9..b585b00451ac 100644 --- a/tests/decorators/test_clickjacking.py +++ b/tests/decorators/test_clickjacking.py @@ -1,4 +1,4 @@ -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction from django.http import HttpRequest, HttpResponse from django.middleware.clickjacking import XFrameOptionsMiddleware diff --git a/tests/decorators/test_common.py b/tests/decorators/test_common.py index a2661ef30a13..53ec5c07bcd1 100644 --- a/tests/decorators/test_common.py +++ b/tests/decorators/test_common.py @@ -1,4 +1,4 @@ -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction from django.http import HttpRequest, HttpResponse from django.test import SimpleTestCase diff --git a/tests/decorators/test_csp.py b/tests/decorators/test_csp.py index 2def6b0f79cb..46e573cfa1b6 100644 --- a/tests/decorators/test_csp.py +++ b/tests/decorators/test_csp.py @@ -1,7 +1,6 @@ +from inspect import iscoroutinefunction from itertools import product -from asgiref.sync import iscoroutinefunction - from django.http import HttpRequest, HttpResponse from django.test import SimpleTestCase from django.utils.csp import CSP diff --git a/tests/decorators/test_csrf.py b/tests/decorators/test_csrf.py index c1934448643f..eb01339cf950 100644 --- a/tests/decorators/test_csrf.py +++ b/tests/decorators/test_csrf.py @@ -1,4 +1,4 @@ -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction from django.conf import settings from django.http import HttpRequest, HttpResponse diff --git a/tests/decorators/test_gzip.py b/tests/decorators/test_gzip.py index 87eff0fe7772..2d64c171f70e 100644 --- a/tests/decorators/test_gzip.py +++ b/tests/decorators/test_gzip.py @@ -1,4 +1,4 @@ -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction from django.http import HttpRequest, HttpResponse from django.test import SimpleTestCase diff --git a/tests/decorators/test_http.py b/tests/decorators/test_http.py index 4b1b81588e21..b0bb4c1e00fb 100644 --- a/tests/decorators/test_http.py +++ b/tests/decorators/test_http.py @@ -1,6 +1,5 @@ import datetime - -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction from django.http import HttpRequest, HttpResponse, HttpResponseNotAllowed from django.test import SimpleTestCase diff --git a/tests/decorators/test_vary.py b/tests/decorators/test_vary.py index ccab18a6609b..cf5f36b97dc6 100644 --- a/tests/decorators/test_vary.py +++ b/tests/decorators/test_vary.py @@ -1,4 +1,4 @@ -from asgiref.sync import iscoroutinefunction +from inspect import iscoroutinefunction from django.http import HttpRequest, HttpResponse from django.test import SimpleTestCase diff --git a/tests/decorators/tests.py b/tests/decorators/tests.py index fce64a8834aa..0c5213f0abbe 100644 --- a/tests/decorators/tests.py +++ b/tests/decorators/tests.py @@ -1,9 +1,8 @@ import asyncio from functools import update_wrapper, wraps +from inspect import iscoroutinefunction from unittest import TestCase -from asgiref.sync import iscoroutinefunction - from django.contrib.admin.views.decorators import staff_member_required from django.contrib.auth.decorators import ( login_required, diff --git a/tests/middleware_exceptions/middleware.py b/tests/middleware_exceptions/middleware.py index f50aa61327e6..9d4c87099fb6 100644 --- a/tests/middleware_exceptions/middleware.py +++ b/tests/middleware_exceptions/middleware.py @@ -1,4 +1,4 @@ -from asgiref.sync import iscoroutinefunction, markcoroutinefunction +from inspect import iscoroutinefunction, markcoroutinefunction from django.http import Http404, HttpResponse from django.template import engines diff --git a/tests/schema/tests.py b/tests/schema/tests.py index cbc5f57eb91f..024e68f2b36d 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -3805,8 +3805,14 @@ def test_func_unique_constraint_nondeterministic(self): with self.assertRaises(DatabaseError): editor.add_constraint(Author, constraint) - @skipUnlessDBFeature("supports_nulls_distinct_unique_constraints") + @skipUnlessDBFeature( + "supports_expression_indexes", "supports_nulls_distinct_unique_constraints" + ) def test_unique_constraint_index_nulls_distinct(self): + """ + For a UniqueConstraint with expressions, the backend executes: + CREATE UNIQUE INDEX ... + """ with connection.schema_editor() as editor: editor.create_model(Author) nulls_distinct = UniqueConstraint( @@ -3831,6 +3837,10 @@ def test_unique_constraint_index_nulls_distinct(self): @skipUnlessDBFeature("supports_nulls_distinct_unique_constraints") def test_unique_constraint_nulls_distinct(self): + """ + For UniqueConstraint(fields=...), the backend executes: + ALTER TABLE "schema_author" ADD CONSTRAINT ... + """ with connection.schema_editor() as editor: editor.create_model(Author) constraint = UniqueConstraint( diff --git a/tests/signals/tests.py b/tests/signals/tests.py index 907612459af6..e304424eb8af 100644 --- a/tests/signals/tests.py +++ b/tests/signals/tests.py @@ -1,8 +1,7 @@ import contextvars +from inspect import markcoroutinefunction from unittest import mock -from asgiref.sync import markcoroutinefunction - from django import dispatch from django.apps.registry import Apps from django.db import models