Skip to content
Open
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
48ac250
Add .prof File Download Support to Profiling Panel
andoriyaprashant Jun 18, 2025
49f29eb
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 18, 2025
7ec7f25
Merge branch 'main' of https://github.com/django-commons/django-debug…
JohananOppongAmoateng Dec 17, 2025
fe4e305
Refactor profiling panel and add download functionality for .prof files
JohananOppongAmoateng Dec 17, 2025
5db558d
Add profiling data download functionality and related settings
JohananOppongAmoateng Dec 17, 2025
74ddf5e
Add tests for profiling stats generation and download functionality
JohananOppongAmoateng Dec 17, 2025
5bbb211
fix
JohananOppongAmoateng Dec 17, 2025
a285d82
fix
JohananOppongAmoateng Dec 17, 2025
2bd5cfe
fix
JohananOppongAmoateng Dec 17, 2025
e698cde
Merge branch 'main' into download-prof-files
JohananOppongAmoateng Dec 17, 2025
66e2d50
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 17, 2025
3896fe3
Merge branch 'main' of https://github.com/django-commons/django-debug…
JohananOppongAmoateng Feb 7, 2026
09f2ba0
address problems
JohananOppongAmoateng Feb 7, 2026
9829c58
docs
JohananOppongAmoateng Feb 7, 2026
cfc244b
address review concerns
JohananOppongAmoateng Feb 8, 2026
df258a2
Merge branch 'main' into download-prof-files
tim-schilling May 7, 2026
efbd2b9
Clean up PR.
tim-schilling May 7, 2026
9cbdf04
Generate the prof file on the fly.
tim-schilling May 7, 2026
05a505c
Merge branch 'main' into download-prof-files
tim-schilling May 9, 2026
34dde67
Name the profile file based on the request being made.
tim-schilling May 9, 2026
bdb6bf5
Remove the mocks from the profiling panel's integration tests.
tim-schilling May 9, 2026
776e4ba
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 9, 2026
25fa939
Remove unexpected addition of uv.lock.
tim-schilling May 9, 2026
f1c86c2
Switch to a proper FileResponse response.
tim-schilling May 10, 2026
d03fec3
Remove extra change.
tim-schilling May 10, 2026
7235ab8
Convert to a NamedTuple class.
tim-schilling May 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Remove the mocks from the profiling panel's integration tests.
  • Loading branch information
tim-schilling committed May 9, 2026
commit bdb6bf540c93906d384c0180193db3b53c57e40d
102 changes: 36 additions & 66 deletions tests/panels/test_profiling.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import sys
import unittest
from unittest import mock

from django.contrib.auth.models import User
from django.db import IntegrityError, transaction
from django.http import HttpResponse
from django.test import TestCase
from django.test.utils import override_settings
from django.urls import reverse

from debug_toolbar.panels.profiling import ProfilingPanel
from debug_toolbar.store import get_store

from ..base import BaseTestCase, IntegrationTestCase
from ..views import listcomp_view, regular_view
Expand Down Expand Up @@ -112,77 +110,49 @@ def test_view_executed_once(self):
response = self.client.get("/new_user/")
self.assertEqual(User.objects.count(), 1)


@override_settings(DEBUG=True)
class ProfilingDownloadViewTestCase(TestCase):
def test_missing_request_id(self):
url = reverse("djdt:profiling_download")
response = self.client.get(url)
def test_profiling_download_missing_request_id(self):
response = self.client.get("/__debug__/profiling_download/")
self.assertEqual(response.status_code, 400)

def test_toolbar_not_found(self):
url = reverse("djdt:profiling_download")
response = self.client.get(url, {"request_id": "nonexistent-id"})
def test_profiling_download_toolbar_not_found(self):
response = self.client.get(
"/__debug__/profiling_download/", {"request_id": "nonexistent-id"}
)
self.assertEqual(response.status_code, 400)

@mock.patch("debug_toolbar.panels.profiling.DebugToolbar.fetch")
def test_valid_download(self, mock_fetch):
mock_panel = mock.MagicMock()
mock_panel.get_stats.return_value = {
"func_list": [
{
"count": 1,
"primitive_count": 1,
"tottime": 0.001,
"tottime_per_call": 0.001,
"cumtime": 0.005,
"cumtime_per_call": 0.005,
"func_key": "/path/to/file.py:42(view)",
},
{
"count": 5,
"primitive_count": 3,
"tottime": 0.002,
"tottime_per_call": 0.0004,
"cumtime": 0.003,
"cumtime_per_call": 0.001,
"func_key": "/path/to/other.py:10(helper)",
},
]
}
mock_toolbar = mock.MagicMock()
mock_toolbar.get_panel_by_id.return_value = mock_panel
mock_fetch.return_value = mock_toolbar

url = reverse("djdt:profiling_download")
response = self.client.get(url, {"request_id": "test-id"})
self.assertEqual(response.content, b"Request is no longer available.")

def test_profiling_download(self):
# The profiling panel needs to be actively enabled.
self.client.cookies["djdtProfilingPanel"] = "on"
self.client.get("/regular/basic/")
request_ids = list(get_store().request_ids())
request_id = request_ids[-1]
response = self.client.get(
"/__debug__/profiling_download/", {"request_id": request_id}
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response["Content-Type"], "text/plain")
self.assertIn(
'attachment; filename="request-test-id.prof"',
response["Content-Disposition"],
)
self.assertIn(".prof", response["Content-Disposition"])
content = response.content.decode()
self.assertIn(
" ncalls tottime percall cumtime percall filename:lineno(function)",
content,
)
self.assertIn("/path/to/file.py:42(view)", content)
self.assertIn("5/3", content)

@mock.patch("debug_toolbar.panels.profiling.DebugToolbar.fetch")
def test_empty_func_list(self, mock_fetch):
mock_panel = mock.MagicMock()
mock_panel.get_stats.return_value = {"func_list": []}
mock_toolbar = mock.MagicMock()
mock_toolbar.get_panel_by_id.return_value = mock_panel
mock_fetch.return_value = mock_toolbar

url = reverse("djdt:profiling_download")
response = self.client.get(url, {"request_id": "test-id"})
self.assertEqual(response.status_code, 200)
content = response.content.decode()
self.assertIn(
" ncalls tottime percall cumtime percall filename:lineno(function)",
content,

def test_profiling_download_lacks_data(self):
# The profiling panel needs to be actively enabled.
self.client.cookies["djdtProfilingPanel"] = "on"
self.client.get("/regular/basic/")
store = get_store()
request_ids = list(store.request_ids())
request_id = request_ids[-1]
# Clear the Profiling panel's data to treat it as if the profiling
# didn't get generated as expected.
store.save_panel(request_id, ProfilingPanel.panel_id, {})
response = self.client.get(
"/__debug__/profiling_download/", {"request_id": request_id}
)
self.assertEqual(response.status_code, 400)
self.assertEqual(
response.content, b"No profiling data exists for this request."
)
Loading