#34451: Incorrect handling of ImproperlyConfigured Exception in views in ASGI
context
--------------------------------+--------------------------------------
Reporter: Michael Galler | Owner: nobody
Type: Bug | Status: new
Component: Uncategorized | Version: 4.1
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+--------------------------------------
Description changed by Mariusz Felisiak:
Old description:
> start with
>
> {{{
> django-admin startproject myproject
> }}}
>
>
> views.py
> {{{
>
> from django.views.generic import FormView
>
> class TestView(FormView):
>
> async def post(self, request, *args, **kwargs):
> return 'Foobar'
> }}}
>
> urls.py
> {{{
> from django.contrib import admin
> from django.urls import path
>
> from myproject.views import TestView
>
> urlpatterns = [
> path('admin/', admin.site.urls),
> path('test/', TestView.as_view()),
> ]
> }}}
>
> This should raise
> django.core.exceptions.ImproperlyConfigured: TestView HTTP handlers must
> either be all sync or all async.
>
> Running the devserver via manage.py results in
>
> {{{
> C:\code\myproject\venv\Scripts\python.exe C:\code\myproject\manage.py
> runserver 8000
> Performing system checks...
>
> Watching for file changes with StatReloader
> Exception in thread django-main-thread:
> Traceback (most recent call last):
> File "C:\Program Files\Python311\Lib\threading.py", line 1038, in
> _bootstrap_inner
> self.run()
> File "C:\Program Files\Python311\Lib\threading.py", line 975, in run
> self._target(*self._args, **self._kwargs)
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\autoreload.py", line 64, in wrapper
> fn(*args, **kwargs)
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\management\commands\runserver.py", line 134, in
> inner_run
> self.check(display_num_errors=True)
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\management\base.py", line 475, in check
> all_issues = checks.run_checks(
> ^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\checks\registry.py", line 88, in run_checks
> new_errors = check(app_configs=app_configs, databases=databases)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\checks\urls.py", line 14, in check_url_config
> return check_resolver(resolver)
> ^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\checks\urls.py", line 24, in check_resolver
> return check_method()
> ^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 494, in check
> for pattern in self.url_patterns:
> ^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 57, in __get__
> res = instance.__dict__[self.name] = self.func(instance)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 715, in url_patterns
> patterns = getattr(self.urlconf_module, "urlpatterns",
> self.urlconf_module)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 57, in __get__
> res = instance.__dict__[self.name] = self.func(instance)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 708, in urlconf_module
> return import_module(self.urlconf_name)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\Program Files\Python311\Lib\importlib\__init__.py", line 126,
> in import_module
> return _bootstrap._gcd_import(name[level:], package, level)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
> File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
> File "<frozen importlib._bootstrap>", line 1149, in
> _find_and_load_unlocked
> File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
> File "<frozen importlib._bootstrap_external>", line 940, in exec_module
> File "<frozen importlib._bootstrap>", line 241, in
> _call_with_frames_removed
> File "C:\code\myproject\myproject\urls.py", line 8, in <module>
> path('test/', TestView.as_view()),
> ^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\views\generic\base.py", line 119, in as_view
> if cls.view_is_async:
> ^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 71, in __get__
> return self.fget(cls)
> ^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\views\generic\base.py", line 73, in view_is_async
> raise ImproperlyConfigured(
> django.core.exceptions.ImproperlyConfigured: TestView HTTP handlers must
> either be all sync or all async.
>
> }}}
>
> Now the same thing with hypercorn will result in some sort of recursion
> that I do not understand.
> Uvicorn behaves the same way.
>
> {{{
> (venv) λ hypercorn myproject.asgi:application
> [2023-03-31 11:54:00 +0200] [16000] [WARNING] ASGI Framework Lifespan
> error, continuing without Lifespan support
> [2023-03-31 11:54:00 +0200] [16000] [INFO] Running on
> http://127.0.0.1:8000 (CTRL + C to quit)
> [2023-03-31 11:54:08 +0200] [16000] [ERROR] Error in ASGI Framework
> Traceback (most recent call last):
> File "C:\code\myproject\venv\Lib\site-packages\asgiref\sync.py", line
> 486, in thread_handler
> raise exc_info[1]
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\handlers\exception.py", line 43, in inner
> response = await get_response(request)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\handlers\base.py", line 235, in _get_response_async
> callback, callback_args, callback_kwargs =
> self.resolve_request(request)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\handlers\base.py", line 313, in resolve_request
> resolver_match = resolver.resolve(request.path_info)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 663, in resolve
> for pattern in self.url_patterns:
> ^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 57, in __get__
> res = instance.__dict__[self.name] = self.func(instance)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 715, in url_patterns
> patterns = getattr(self.urlconf_module, "urlpatterns",
> self.urlconf_module)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 57, in __get__
> res = instance.__dict__[self.name] = self.func(instance)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 708, in urlconf_module
> return import_module(self.urlconf_name)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\Program Files\Python311\Lib\importlib\__init__.py", line 126,
> in import_module
> return _bootstrap._gcd_import(name[level:], package, level)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
> File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
> File "<frozen importlib._bootstrap>", line 1149, in
> _find_and_load_unlocked
> File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
> File "<frozen importlib._bootstrap_external>", line 940, in exec_module
> File "<frozen importlib._bootstrap>", line 241, in
> _call_with_frames_removed
> File "C:\code\myproject\myproject\urls.py", line 8, in <module>
> path('test/', TestView.as_view()),
> ^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\views\generic\base.py", line 119, in as_view
> if cls.view_is_async:
> ^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 71, in __get__
> return self.fget(cls)
> ^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\views\generic\base.py", line 73, in view_is_async
> raise ImproperlyConfigured(
> django.core.exceptions.ImproperlyConfigured: TestView HTTP handlers must
> either be all sync or all async.
>
> During handling of the above exception, another exception occurred:
>
> ... (the same frame over and over again)
> }}}
>
> ==
> #############################################################################################
>
> In my personal project this leads to a strange problem with django-ninja
>
> api.py
> {{{
> from ninja import NinjaAPI
>
> api = NinjaAPI()
> }}}
>
> urls.py
> {{{
> from django.contrib import admin
> from django.urls import path
>
> from myproject.api import api
> from myproject.views import TestView
>
> urlpatterns = [
> path('admin/', admin.site.urls),
> path("api/", api.urls),
> path('test/', TestView.as_view()),
> ]
> }}}
>
> manage.py devserver:
>
> {{{
> C:\code\myproject\venv\Scripts\python.exe C:\code\myproject\manage.py
> runserver 8000
> Watching for file changes with StatReloader
> Performing system checks...
>
> Exception in thread django-main-thread:
> Traceback (most recent call last):
> File "C:\Program Files\Python311\Lib\threading.py", line 1038, in
> _bootstrap_inner
> self.run()
> File "C:\Program Files\Python311\Lib\threading.py", line 975, in run
> self._target(*self._args, **self._kwargs)
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\autoreload.py", line 64, in wrapper
> fn(*args, **kwargs)
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\management\commands\runserver.py", line 134, in
> inner_run
> self.check(display_num_errors=True)
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\management\base.py", line 475, in check
> all_issues = checks.run_checks(
> ^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\checks\registry.py", line 88, in run_checks
> new_errors = check(app_configs=app_configs, databases=databases)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\checks\urls.py", line 14, in check_url_config
> return check_resolver(resolver)
> ^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\checks\urls.py", line 24, in check_resolver
> return check_method()
> ^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 494, in check
> for pattern in self.url_patterns:
> ^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 57, in __get__
> res = instance.__dict__[self.name] = self.func(instance)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 715, in url_patterns
> patterns = getattr(self.urlconf_module, "urlpatterns",
> self.urlconf_module)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 57, in __get__
> res = instance.__dict__[self.name] = self.func(instance)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 708, in urlconf_module
> return import_module(self.urlconf_name)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\Program Files\Python311\Lib\importlib\__init__.py", line 126,
> in import_module
> return _bootstrap._gcd_import(name[level:], package, level)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
> File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
> File "<frozen importlib._bootstrap>", line 1149, in
> _find_and_load_unlocked
> File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
> File "<frozen importlib._bootstrap_external>", line 940, in exec_module
> File "<frozen importlib._bootstrap>", line 241, in
> _call_with_frames_removed
> File "C:\code\myproject\myproject\urls.py", line 10, in <module>
> path('test/', TestView.as_view()),
> ^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\views\generic\base.py", line 119, in as_view
> if cls.view_is_async:
> ^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 71, in __get__
> return self.fget(cls)
> ^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\views\generic\base.py", line 73, in view_is_async
> raise ImproperlyConfigured(
> django.core.exceptions.ImproperlyConfigured: TestView HTTP handlers must
> either be all sync or all async.
>
> }}}
>
> With hypercorn:
>
> {{{
> (venv) λ hypercorn myproject.asgi:application
> [2023-03-31 12:03:33 +0200] [20028] [WARNING] ASGI Framework Lifespan
> error, continuing without Lifespan support
> [2023-03-31 12:03:33 +0200] [20028] [INFO] Running on
> http://127.0.0.1:8000 (CTRL + C to quit)
> [2023-03-31 12:03:40 +0200] [20028] [ERROR] Error in ASGI Framework
> Traceback (most recent call last):
> File "C:\code\myproject\venv\Lib\site-packages\asgiref\sync.py", line
> 486, in thread_handler
> raise exc_info[1]
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\handlers\exception.py", line 43, in inner
> response = await get_response(request)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\handlers\base.py", line 235, in _get_response_async
> callback, callback_args, callback_kwargs =
> self.resolve_request(request)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\handlers\base.py", line 313, in resolve_request
> resolver_match = resolver.resolve(request.path_info)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 663, in resolve
> for pattern in self.url_patterns:
> ^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 57, in __get__
> res = instance.__dict__[self.name] = self.func(instance)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 715, in url_patterns
> patterns = getattr(self.urlconf_module, "urlpatterns",
> self.urlconf_module)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 57, in __get__
> res = instance.__dict__[self.name] = self.func(instance)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 708, in urlconf_module
> return import_module(self.urlconf_name)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\Program Files\Python311\Lib\importlib\__init__.py", line 126,
> in import_module
> return _bootstrap._gcd_import(name[level:], package, level)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
> File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
> File "<frozen importlib._bootstrap>", line 1149, in
> _find_and_load_unlocked
> File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
> File "<frozen importlib._bootstrap_external>", line 940, in exec_module
> File "<frozen importlib._bootstrap>", line 241, in
> _call_with_frames_removed
> File "C:\code\myproject\myproject\urls.py", line 10, in <module>
> path('test/', TestView.as_view()),
> ^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\views\generic\base.py", line 119, in as_view
> if cls.view_is_async:
> ^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 71, in __get__
> return self.fget(cls)
> ^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\views\generic\base.py", line 73, in view_is_async
> raise ImproperlyConfigured(
> django.core.exceptions.ImproperlyConfigured: TestView HTTP handlers must
> either be all sync or all async.
>
> During handling of the above exception, another exception occurred:
>
> Traceback (most recent call last):
> File "C:\code\myproject\venv\Lib\site-packages\asgiref\sync.py", line
> 486, in thread_handler
> raise exc_info[1]
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\handlers\exception.py", line 43, in inner
> response = await get_response(request)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\deprecation.py", line 152, in __acall__
> response = response or await self.get_response(request)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\handlers\exception.py", line 45, in inner
> response = await sync_to_async(
> ^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-packages\asgiref\sync.py", line
> 448, in __call__
> ret = await asyncio.wait_for(future, timeout=None)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\Program Files\Python311\Lib\asyncio\tasks.py", line 442, in
> wait_for
> return await fut
> ^^^^^^^^^
> File "C:\Program Files\Python311\Lib\concurrent\futures\thread.py",
> line 58, in run
> result = self.fn(*self.args, **self.kwargs)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-packages\asgiref\sync.py", line
> 488, in thread_handler
> return func(*args, **kwargs)
> ^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\handlers\exception.py", line 141, in
> response_for_exception
> response = handle_uncaught_exception(
> ^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\core\handlers\exception.py", line 182, in
> handle_uncaught_exception
> return debug.technical_500_response(request, *exc_info)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-packages\django\views\debug.py",
> line 66, in technical_500_response
> html = reporter.get_traceback_html()
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-packages\django\views\debug.py",
> line 396, in get_traceback_html
> c = Context(self.get_traceback_data(), use_l10n=False)
> ^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-packages\django\views\debug.py",
> line 381, in get_traceback_data
> c["raising_view_name"] = get_caller(self.request)
> ^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-packages\django\views\debug.py",
> line 99, in get_caller
> resolver_match = resolve(request.path)
> ^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-packages\django\urls\base.py",
> line 24, in resolve
> return get_resolver(urlconf).resolve(path)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 663, in resolve
> for pattern in self.url_patterns:
> ^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 57, in __get__
> res = instance.__dict__[self.name] = self.func(instance)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 715, in url_patterns
> patterns = getattr(self.urlconf_module, "urlpatterns",
> self.urlconf_module)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\utils\functional.py", line 57, in __get__
> res = instance.__dict__[self.name] = self.func(instance)
> ^^^^^^^^^^^^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-
> packages\django\urls\resolvers.py", line 708, in urlconf_module
> return import_module(self.urlconf_name)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "C:\Program Files\Python311\Lib\importlib\__init__.py", line 126,
> in import_module
> return _bootstrap._gcd_import(name[level:], package, level)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
> File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
> File "<frozen importlib._bootstrap>", line 1149, in
> _find_and_load_unlocked
> File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
> File "<frozen importlib._bootstrap_external>", line 940, in exec_module
> File "<frozen importlib._bootstrap>", line 241, in
> _call_with_frames_removed
> File "C:\code\myproject\myproject\urls.py", line 9, in <module>
> path("api/", api.urls),
> ^^^^^^^^
> File "C:\code\myproject\venv\Lib\site-packages\ninja\main.py", line
> 379, in urls
> self._validate()
> File "C:\code\myproject\venv\Lib\site-packages\ninja\main.py", line
> 494, in _validate
> raise ConfigError(msg.strip())
> ninja.errors.ConfigError: Looks like you created multiple NinjaAPIs or
> TestClients
> To let ninja distinguish them you need to set either unique version or
> urls_namespace
> - NinjaAPI(..., version='2.0.0')
> - NinjaAPI(..., urls_namespace='otherapi')
> Already registered: ['api-1.0.0']
>
> During handling of the above exception, another exception occurred:
>
> ... (the same frame over and over again)
> }}}
New description:
start with
{{{
django-admin startproject myproject
}}}
views.py
{{{
from django.views.generic import FormView
class TestView(FormView):
async def post(self, request, *args, **kwargs):
return 'Foobar'
}}}
urls.py
{{{
from django.contrib import admin
from django.urls import path
from myproject.views import TestView
urlpatterns = [
path('admin/', admin.site.urls),
path('test/', TestView.as_view()),
]
}}}
This should raise
django.core.exceptions.ImproperlyConfigured: TestView HTTP handlers must
either be all sync or all async.
Running the devserver via manage.py results in
{{{
C:\code\myproject\venv\Scripts\python.exe C:\code\myproject\manage.py
runserver 8000
Performing system checks...
Watching for file changes with StatReloader
Exception in thread django-main-thread:
Traceback (most recent call last):
File "C:\Program Files\Python311\Lib\threading.py", line 1038, in
_bootstrap_inner
self.run()
File "C:\Program Files\Python311\Lib\threading.py", line 975, in run
self._target(*self._args, **self._kwargs)
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\autoreload.py", line 64, in wrapper
fn(*args, **kwargs)
File "C:\code\myproject\venv\Lib\site-
packages\django\core\management\commands\runserver.py", line 134, in
inner_run
self.check(display_num_errors=True)
File "C:\code\myproject\venv\Lib\site-
packages\django\core\management\base.py", line 475, in check
all_issues = checks.run_checks(
^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\checks\registry.py", line 88, in run_checks
new_errors = check(app_configs=app_configs, databases=databases)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\checks\urls.py", line 14, in check_url_config
return check_resolver(resolver)
^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\checks\urls.py", line 24, in check_resolver
return check_method()
^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 494, in check
for pattern in self.url_patterns:
^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 57, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 715, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns",
self.urlconf_module)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 57, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 708, in urlconf_module
return import_module(self.urlconf_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\importlib\__init__.py", line 126,
in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
File "<frozen importlib._bootstrap>", line 1149, in
_find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in
_call_with_frames_removed
File "C:\code\myproject\myproject\urls.py", line 8, in <module>
path('test/', TestView.as_view()),
^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\views\generic\base.py", line 119, in as_view
if cls.view_is_async:
^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 71, in __get__
return self.fget(cls)
^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\views\generic\base.py", line 73, in view_is_async
raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: TestView HTTP handlers must
either be all sync or all async.
}}}
Now the same thing with hypercorn will result in some sort of recursion
that I do not understand.
Uvicorn behaves the same way.
{{{
(venv) λ hypercorn myproject.asgi:application
[2023-03-31 11:54:00 +0200] [16000] [WARNING] ASGI Framework Lifespan
error, continuing without Lifespan support
[2023-03-31 11:54:00 +0200] [16000] [INFO] Running on
http://127.0.0.1:8000 (CTRL + C to quit)
[2023-03-31 11:54:08 +0200] [16000] [ERROR] Error in ASGI Framework
Traceback (most recent call last):
File "C:\code\myproject\venv\Lib\site-packages\asgiref\sync.py", line
486, in thread_handler
raise exc_info[1]
File "C:\code\myproject\venv\Lib\site-
packages\django\core\handlers\exception.py", line 43, in inner
response = await get_response(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\handlers\base.py", line 235, in _get_response_async
callback, callback_args, callback_kwargs =
self.resolve_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\handlers\base.py", line 313, in resolve_request
resolver_match = resolver.resolve(request.path_info)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 663, in resolve
for pattern in self.url_patterns:
^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 57, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 715, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns",
self.urlconf_module)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 57, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 708, in urlconf_module
return import_module(self.urlconf_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\importlib\__init__.py", line 126,
in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
File "<frozen importlib._bootstrap>", line 1149, in
_find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in
_call_with_frames_removed
File "C:\code\myproject\myproject\urls.py", line 8, in <module>
path('test/', TestView.as_view()),
^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\views\generic\base.py", line 119, in as_view
if cls.view_is_async:
^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 71, in __get__
return self.fget(cls)
^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\views\generic\base.py", line 73, in view_is_async
raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: TestView HTTP handlers must
either be all sync or all async.
During handling of the above exception, another exception occurred:
... (the same frame over and over again)
}}}
-----
In my personal project this leads to a strange problem with django-ninja
api.py
{{{
from ninja import NinjaAPI
api = NinjaAPI()
}}}
urls.py
{{{
from django.contrib import admin
from django.urls import path
from myproject.api import api
from myproject.views import TestView
urlpatterns = [
path('admin/', admin.site.urls),
path("api/", api.urls),
path('test/', TestView.as_view()),
]
}}}
manage.py devserver:
{{{
C:\code\myproject\venv\Scripts\python.exe C:\code\myproject\manage.py
runserver 8000
Watching for file changes with StatReloader
Performing system checks...
Exception in thread django-main-thread:
Traceback (most recent call last):
File "C:\Program Files\Python311\Lib\threading.py", line 1038, in
_bootstrap_inner
self.run()
File "C:\Program Files\Python311\Lib\threading.py", line 975, in run
self._target(*self._args, **self._kwargs)
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\autoreload.py", line 64, in wrapper
fn(*args, **kwargs)
File "C:\code\myproject\venv\Lib\site-
packages\django\core\management\commands\runserver.py", line 134, in
inner_run
self.check(display_num_errors=True)
File "C:\code\myproject\venv\Lib\site-
packages\django\core\management\base.py", line 475, in check
all_issues = checks.run_checks(
^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\checks\registry.py", line 88, in run_checks
new_errors = check(app_configs=app_configs, databases=databases)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\checks\urls.py", line 14, in check_url_config
return check_resolver(resolver)
^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\checks\urls.py", line 24, in check_resolver
return check_method()
^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 494, in check
for pattern in self.url_patterns:
^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 57, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 715, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns",
self.urlconf_module)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 57, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 708, in urlconf_module
return import_module(self.urlconf_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\importlib\__init__.py", line 126,
in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
File "<frozen importlib._bootstrap>", line 1149, in
_find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in
_call_with_frames_removed
File "C:\code\myproject\myproject\urls.py", line 10, in <module>
path('test/', TestView.as_view()),
^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\views\generic\base.py", line 119, in as_view
if cls.view_is_async:
^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 71, in __get__
return self.fget(cls)
^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\views\generic\base.py", line 73, in view_is_async
raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: TestView HTTP handlers must
either be all sync or all async.
}}}
With hypercorn:
{{{
(venv) λ hypercorn myproject.asgi:application
[2023-03-31 12:03:33 +0200] [20028] [WARNING] ASGI Framework Lifespan
error, continuing without Lifespan support
[2023-03-31 12:03:33 +0200] [20028] [INFO] Running on
http://127.0.0.1:8000 (CTRL + C to quit)
[2023-03-31 12:03:40 +0200] [20028] [ERROR] Error in ASGI Framework
Traceback (most recent call last):
File "C:\code\myproject\venv\Lib\site-packages\asgiref\sync.py", line
486, in thread_handler
raise exc_info[1]
File "C:\code\myproject\venv\Lib\site-
packages\django\core\handlers\exception.py", line 43, in inner
response = await get_response(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\handlers\base.py", line 235, in _get_response_async
callback, callback_args, callback_kwargs =
self.resolve_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\handlers\base.py", line 313, in resolve_request
resolver_match = resolver.resolve(request.path_info)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 663, in resolve
for pattern in self.url_patterns:
^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 57, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 715, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns",
self.urlconf_module)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 57, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 708, in urlconf_module
return import_module(self.urlconf_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\importlib\__init__.py", line 126,
in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
File "<frozen importlib._bootstrap>", line 1149, in
_find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in
_call_with_frames_removed
File "C:\code\myproject\myproject\urls.py", line 10, in <module>
path('test/', TestView.as_view()),
^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\views\generic\base.py", line 119, in as_view
if cls.view_is_async:
^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 71, in __get__
return self.fget(cls)
^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\views\generic\base.py", line 73, in view_is_async
raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: TestView HTTP handlers must
either be all sync or all async.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\code\myproject\venv\Lib\site-packages\asgiref\sync.py", line
486, in thread_handler
raise exc_info[1]
File "C:\code\myproject\venv\Lib\site-
packages\django\core\handlers\exception.py", line 43, in inner
response = await get_response(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\deprecation.py", line 152, in __acall__
response = response or await self.get_response(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\handlers\exception.py", line 45, in inner
response = await sync_to_async(
^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-packages\asgiref\sync.py", line
448, in __call__
ret = await asyncio.wait_for(future, timeout=None)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\asyncio\tasks.py", line 442, in
wait_for
return await fut
^^^^^^^^^
File "C:\Program Files\Python311\Lib\concurrent\futures\thread.py", line
58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-packages\asgiref\sync.py", line
488, in thread_handler
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\handlers\exception.py", line 141, in
response_for_exception
response = handle_uncaught_exception(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\core\handlers\exception.py", line 182, in
handle_uncaught_exception
return debug.technical_500_response(request, *exc_info)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-packages\django\views\debug.py",
line 66, in technical_500_response
html = reporter.get_traceback_html()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-packages\django\views\debug.py",
line 396, in get_traceback_html
c = Context(self.get_traceback_data(), use_l10n=False)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-packages\django\views\debug.py",
line 381, in get_traceback_data
c["raising_view_name"] = get_caller(self.request)
^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-packages\django\views\debug.py",
line 99, in get_caller
resolver_match = resolve(request.path)
^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-packages\django\urls\base.py",
line 24, in resolve
return get_resolver(urlconf).resolve(path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 663, in resolve
for pattern in self.url_patterns:
^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 57, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 715, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns",
self.urlconf_module)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\utils\functional.py", line 57, in __get__
res = instance.__dict__[self.name] = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "C:\code\myproject\venv\Lib\site-
packages\django\urls\resolvers.py", line 708, in urlconf_module
return import_module(self.urlconf_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python311\Lib\importlib\__init__.py", line 126,
in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
File "<frozen importlib._bootstrap>", line 1149, in
_find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in
_call_with_frames_removed
File "C:\code\myproject\myproject\urls.py", line 9, in <module>
path("api/", api.urls),
^^^^^^^^
File "C:\code\myproject\venv\Lib\site-packages\ninja\main.py", line 379,
in urls
self._validate()
File "C:\code\myproject\venv\Lib\site-packages\ninja\main.py", line 494,
in _validate
raise ConfigError(msg.strip())
ninja.errors.ConfigError: Looks like you created multiple NinjaAPIs or
TestClients
To let ninja distinguish them you need to set either unique version or
urls_namespace
- NinjaAPI(..., version='2.0.0')
- NinjaAPI(..., urls_namespace='otherapi')
Already registered: ['api-1.0.0']
During handling of the above exception, another exception occurred:
... (the same frame over and over again)
}}}
--
--
Ticket URL: <https://code.djangoproject.com/ticket/34451#comment:2>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/0107018737496893-7be812d1-8ac6-44cb-9f59-7494d8a5e0b8-000000%40eu-central-1.amazonses.com.