Skip to content

Async compatible redirect panel #1976

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Aug 6, 2024
25 changes: 22 additions & 3 deletions debug_toolbar/panels/redirects.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from inspect import iscoroutine

from django.template.response import SimpleTemplateResponse
from django.utils.translation import gettext_lazy as _

Expand All @@ -9,13 +11,15 @@ class RedirectsPanel(Panel):
Panel that intercepts redirects and displays a page with debug info.
"""

is_async = False
is_async = True
has_content = False

nav_title = _("Intercept redirects")

def process_request(self, request):
response = super().process_request(request)
def _process_response(self, response):
"""
Common response processing logic.
"""
if 300 <= response.status_code < 400:
redirect_to = response.get("Location")
if redirect_to:
Expand All @@ -33,3 +37,18 @@ def process_request(self, request):
response.cookies = cookies
response.render()
return response

async def aprocess_request(self, request, response_coroutine):
"""
Async version of process_request. used for accessing the response
by awaiting it when running in ASGI.
"""

response = await response_coroutine
return self._process_response(response)

def process_request(self, request):
response = super().process_request(request)
if iscoroutine(response):
return self.aprocess_request(request, response)
return self._process_response(response)
2 changes: 1 addition & 1 deletion docs/architecture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Problematic Parts
- Support for async and multi-threading: ``debug_toolbar.middleware.DebugToolbarMiddleware``
is now async compatible and can process async requests. However certain
panels such as ``SQLPanel``, ``TimerPanel``, ``StaticFilesPanel``,
``RequestPanel``, ``RedirectsPanel`` and ``ProfilingPanel`` aren't fully
``RequestPanel`` and ``ProfilingPanel`` aren't fully
compatible and currently being worked on. For now, these panels
are disabled by default when running in async environment.
follow the progress of this issue in `Async compatible toolbar project <https://github.com/orgs/jazzband/projects/9>`_.
1 change: 1 addition & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Pending
* Fixed internal toolbar requests being instrumented if the Django setting
``FORCE_SCRIPT_NAME`` was set.
* Increase opacity of show Debug Toolbar handle to improve accessibility.
* Changed the ``RedirectsPanel`` to be async compatible.

4.4.6 (2024-07-10)
------------------
Expand Down
15 changes: 15 additions & 0 deletions tests/panels/test_redirects.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from django.conf import settings
from django.http import HttpResponse
from django.test import AsyncRequestFactory

from ..base import BaseTestCase

Expand Down Expand Up @@ -70,3 +71,17 @@ def test_insert_content(self):
self.assertIsNotNone(response)
response = self.panel.generate_stats(self.request, redirect)
self.assertIsNone(response)

async def test_async_compatibility(self):
redirect = HttpResponse(status=302)

async def get_response(request):
return redirect

await_response = await get_response(self.request)
self._get_response = get_response

self.request = AsyncRequestFactory().get("/")
response = await self.panel.process_request(self.request)
self.assertIsInstance(response, HttpResponse)
self.assertTrue(response is await_response)