Skip to content

Commit

Permalink
Async compatible redirect panel (#1976)
Browse files Browse the repository at this point in the history
* make redirect panel async capable by using aprocess_request patterm

* added async compability test for redirect panel

* remove redundant call for super process_request
  • Loading branch information
salty-ivy committed Aug 6, 2024
1 parent 89568d5 commit 405f9f2
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 4 deletions.
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)

0 comments on commit 405f9f2

Please sign in to comment.