From e566305e3309aa93bc0c4c55099940e3261aa1c7 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Fri, 19 Aug 2022 09:41:01 +0200 Subject: [PATCH 01/12] Add a test for the 'data is gone' case --- tests/test_integration.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_integration.py b/tests/test_integration.py index e9962b32b..982a2824c 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -174,6 +174,12 @@ def test_is_toolbar_request_override_request_urlconf(self): self.request.path = "/__debug__/render_panel/" self.assertTrue(self.toolbar.is_toolbar_request(self.request)) + def test_data_gone(self): + response = self.client.get( + "/__debug__/render_panel/?store_id=GONE&panel_id=RequestPanel" + ) + self.assertIn("Please reload the page and retry.", response.json()["content"]) + @override_settings(DEBUG=True) class DebugToolbarIntegrationTestCase(IntegrationTestCase): From 6a34e007e773d1243e3c7ba0b0ee07e4b45514ba Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 28 Aug 2022 16:15:29 +0200 Subject: [PATCH 02/12] [pre-commit.ci] pre-commit autoupdate (#1665) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/pre-commit/mirrors-prettier: v2.7.1 → v3.0.0-alpha.0](https://github.com/pre-commit/mirrors-prettier/compare/v2.7.1...v3.0.0-alpha.0) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- debug_toolbar/static/debug_toolbar/js/history.js | 12 ++++++------ debug_toolbar/static/debug_toolbar/js/timer.js | 2 +- debug_toolbar/static/debug_toolbar/js/toolbar.js | 16 ++++++++-------- debug_toolbar/static/debug_toolbar/js/utils.js | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 36baad66d..99bc08582 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,7 +38,7 @@ repos: - id: rst-backticks - id: rst-directive-colons - repo: https://github.com/pre-commit/mirrors-prettier - rev: v2.7.1 + rev: v3.0.0-alpha.0 hooks: - id: prettier types_or: [javascript, css] diff --git a/debug_toolbar/static/debug_toolbar/js/history.js b/debug_toolbar/static/debug_toolbar/js/history.js index b30fcabae..5611fde1d 100644 --- a/debug_toolbar/static/debug_toolbar/js/history.js +++ b/debug_toolbar/static/debug_toolbar/js/history.js @@ -25,7 +25,7 @@ function refreshHistory() { const formTarget = djDebug.querySelector(".refreshHistory"); const container = document.getElementById("djdtHistoryRequests"); const oldIds = new Set( - pluckData(container.querySelectorAll("tr[data-store-id]"), "storeId") + pluckData(container.querySelectorAll("tr[data-store-id]"), "storeId"), ); ajaxForm(formTarget) @@ -44,8 +44,8 @@ function refreshHistory() { const allIds = new Set( pluckData( container.querySelectorAll("tr[data-store-id]"), - "storeId" - ) + "storeId", + ), ); const newIds = difference(allIds, oldIds); const lastRequestId = newIds.values().next().value; @@ -58,7 +58,7 @@ function refreshHistory() { .then(function (refreshInfo) { refreshInfo.newIds.forEach(function (newId) { const row = container.querySelector( - `tr[data-store-id="${newId}"]` + `tr[data-store-id="${newId}"]`, ); row.classList.add("flash-new"); }); @@ -74,7 +74,7 @@ function refreshHistory() { function switchHistory(newStoreId) { const formTarget = djDebug.querySelector( - ".switchHistory[data-store-id='" + newStoreId + "']" + ".switchHistory[data-store-id='" + newStoreId + "']", ); const tbody = formTarget.closest("tbody"); @@ -88,7 +88,7 @@ function switchHistory(newStoreId) { if (Object.keys(data).length === 0) { const container = document.getElementById("djdtHistoryRequests"); container.querySelector( - 'button[data-store-id="' + newStoreId + '"]' + 'button[data-store-id="' + newStoreId + '"]', ).innerHTML = "Switch [EXPIRED]"; } replaceToolbarState(newStoreId, data); diff --git a/debug_toolbar/static/debug_toolbar/js/timer.js b/debug_toolbar/static/debug_toolbar/js/timer.js index 70d3fe5a2..9f26bf83c 100644 --- a/debug_toolbar/static/debug_toolbar/js/timer.js +++ b/debug_toolbar/static/debug_toolbar/js/timer.js @@ -33,7 +33,7 @@ function insertBrowserTiming() { ")"; row.querySelector("rect").setAttribute( "width", - getCSSWidth(stat, endStat) + getCSSWidth(stat, endStat), ); } else { // Render a point in time diff --git a/debug_toolbar/static/debug_toolbar/js/toolbar.js b/debug_toolbar/static/debug_toolbar/js/toolbar.js index 1c06be7fa..3d45ffd74 100644 --- a/debug_toolbar/static/debug_toolbar/js/toolbar.js +++ b/debug_toolbar/static/debug_toolbar/js/toolbar.js @@ -31,13 +31,13 @@ const djdt = { this.parentElement.classList.add("djdt-active"); const inner = current.querySelector( - ".djDebugPanelContent .djdt-scroll" + ".djDebugPanelContent .djdt-scroll", ), store_id = djDebug.dataset.storeId; if (store_id && inner.children.length === 0) { const url = new URL( djDebug.dataset.renderPanelUrl, - window.location + window.location, ); url.searchParams.append("store_id", store_id); url.searchParams.append("panel_id", panelId); @@ -49,18 +49,18 @@ const djdt = { djDebug.dispatchEvent( new CustomEvent("djdt.panel.render", { detail: { panelId: panelId }, - }) + }), ); }); } else { djDebug.dispatchEvent( new CustomEvent("djdt.panel.render", { detail: { panelId: panelId }, - }) + }), ); } } - } + }, ); $$.on(djDebug, "click", ".djDebugClose", function () { djdt.hide_one_level(); @@ -76,9 +76,9 @@ const djdt = { { path: "/", expires: 10, - } + }, ); - } + }, ); // Used by the SQL and template panels @@ -219,7 +219,7 @@ const djdt = { // set handle position const handleTop = Math.min( localStorage.getItem("djdt.top") || 0, - window.innerHeight - handle.offsetWidth + window.innerHeight - handle.offsetWidth, ); handle.style.top = handleTop + "px"; }, diff --git a/debug_toolbar/static/debug_toolbar/js/utils.js b/debug_toolbar/static/debug_toolbar/js/utils.js index 72c767fb6..065c1d42e 100644 --- a/debug_toolbar/static/debug_toolbar/js/utils.js +++ b/debug_toolbar/static/debug_toolbar/js/utils.js @@ -77,7 +77,7 @@ function ajax(url, init) { return response.json(); } return Promise.reject( - new Error(response.status + ": " + response.statusText) + new Error(response.status + ": " + response.statusText), ); }) .catch(function (error) { From 6f548ae81352d3b78f0955710dbaffdec000627a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 9 Sep 2022 09:38:09 +0200 Subject: [PATCH 03/12] [pre-commit.ci] pre-commit autoupdate (#1667) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/adamchainz/django-upgrade: 1.8.0 → 1.9.0](https://github.com/adamchainz/django-upgrade/compare/1.8.0...1.9.0) - [github.com/pre-commit/mirrors-eslint: v8.22.0 → v8.23.0](https://github.com/pre-commit/mirrors-eslint/compare/v8.22.0...v8.23.0) - [github.com/psf/black: 22.6.0 → 22.8.0](https://github.com/psf/black/compare/22.6.0...22.8.0) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- tests/urls.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 99bc08582..54dc2baa6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: - id: pyupgrade args: [--py37-plus] - repo: https://github.com/adamchainz/django-upgrade - rev: 1.8.0 + rev: 1.9.0 hooks: - id: django-upgrade args: [--target-version, "3.2"] @@ -43,7 +43,7 @@ repos: - id: prettier types_or: [javascript, css] - repo: https://github.com/pre-commit/mirrors-eslint - rev: v8.22.0 + rev: v8.23.0 hooks: - id: eslint files: \.js?$ @@ -51,7 +51,7 @@ repos: args: - --fix - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 22.8.0 hooks: - id: black language_version: python3 diff --git a/tests/urls.py b/tests/urls.py index c12fc744a..6fc8811b7 100644 --- a/tests/urls.py +++ b/tests/urls.py @@ -9,7 +9,7 @@ re_path( r"^resolving1/(.+)/(.+)/$", views.resolving_view, name="positional-resolving" ), - re_path(r"^resolving2/(?P.+)/(?P.+)/$", views.resolving_view), + path("resolving2///", views.resolving_view), re_path(r"^resolving3/(.+)/$", views.resolving_view, {"arg2": "default"}), re_path(r"^regular/(?P.*)/$", views.regular_view), re_path(r"^template_response/(?P<title>.*)/$", views.template_response_view), From b20ddd332f88cbc3e13aaafb0a27a9c8dc8b7899 Mon Sep 17 00:00:00 2001 From: tschilling <schillingt@better-simple.com> Date: Sun, 11 Sep 2022 13:08:44 -0500 Subject: [PATCH 04/12] Fix JS linting error from pre-commit. prettier v3 changed the default of trailing comma to all which seems to be problematic for ESLint. --- .pre-commit-config.yaml | 2 ++ debug_toolbar/static/debug_toolbar/js/history.js | 12 ++++++------ debug_toolbar/static/debug_toolbar/js/timer.js | 2 +- debug_toolbar/static/debug_toolbar/js/toolbar.js | 16 ++++++++-------- debug_toolbar/static/debug_toolbar/js/utils.js | 2 +- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 54dc2baa6..07de1cd35 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,6 +42,8 @@ repos: hooks: - id: prettier types_or: [javascript, css] + args: + - --trailing-comma=es5 - repo: https://github.com/pre-commit/mirrors-eslint rev: v8.23.0 hooks: diff --git a/debug_toolbar/static/debug_toolbar/js/history.js b/debug_toolbar/static/debug_toolbar/js/history.js index 5611fde1d..b30fcabae 100644 --- a/debug_toolbar/static/debug_toolbar/js/history.js +++ b/debug_toolbar/static/debug_toolbar/js/history.js @@ -25,7 +25,7 @@ function refreshHistory() { const formTarget = djDebug.querySelector(".refreshHistory"); const container = document.getElementById("djdtHistoryRequests"); const oldIds = new Set( - pluckData(container.querySelectorAll("tr[data-store-id]"), "storeId"), + pluckData(container.querySelectorAll("tr[data-store-id]"), "storeId") ); ajaxForm(formTarget) @@ -44,8 +44,8 @@ function refreshHistory() { const allIds = new Set( pluckData( container.querySelectorAll("tr[data-store-id]"), - "storeId", - ), + "storeId" + ) ); const newIds = difference(allIds, oldIds); const lastRequestId = newIds.values().next().value; @@ -58,7 +58,7 @@ function refreshHistory() { .then(function (refreshInfo) { refreshInfo.newIds.forEach(function (newId) { const row = container.querySelector( - `tr[data-store-id="${newId}"]`, + `tr[data-store-id="${newId}"]` ); row.classList.add("flash-new"); }); @@ -74,7 +74,7 @@ function refreshHistory() { function switchHistory(newStoreId) { const formTarget = djDebug.querySelector( - ".switchHistory[data-store-id='" + newStoreId + "']", + ".switchHistory[data-store-id='" + newStoreId + "']" ); const tbody = formTarget.closest("tbody"); @@ -88,7 +88,7 @@ function switchHistory(newStoreId) { if (Object.keys(data).length === 0) { const container = document.getElementById("djdtHistoryRequests"); container.querySelector( - 'button[data-store-id="' + newStoreId + '"]', + 'button[data-store-id="' + newStoreId + '"]' ).innerHTML = "Switch [EXPIRED]"; } replaceToolbarState(newStoreId, data); diff --git a/debug_toolbar/static/debug_toolbar/js/timer.js b/debug_toolbar/static/debug_toolbar/js/timer.js index 9f26bf83c..70d3fe5a2 100644 --- a/debug_toolbar/static/debug_toolbar/js/timer.js +++ b/debug_toolbar/static/debug_toolbar/js/timer.js @@ -33,7 +33,7 @@ function insertBrowserTiming() { ")</td>"; row.querySelector("rect").setAttribute( "width", - getCSSWidth(stat, endStat), + getCSSWidth(stat, endStat) ); } else { // Render a point in time diff --git a/debug_toolbar/static/debug_toolbar/js/toolbar.js b/debug_toolbar/static/debug_toolbar/js/toolbar.js index 3d45ffd74..1c06be7fa 100644 --- a/debug_toolbar/static/debug_toolbar/js/toolbar.js +++ b/debug_toolbar/static/debug_toolbar/js/toolbar.js @@ -31,13 +31,13 @@ const djdt = { this.parentElement.classList.add("djdt-active"); const inner = current.querySelector( - ".djDebugPanelContent .djdt-scroll", + ".djDebugPanelContent .djdt-scroll" ), store_id = djDebug.dataset.storeId; if (store_id && inner.children.length === 0) { const url = new URL( djDebug.dataset.renderPanelUrl, - window.location, + window.location ); url.searchParams.append("store_id", store_id); url.searchParams.append("panel_id", panelId); @@ -49,18 +49,18 @@ const djdt = { djDebug.dispatchEvent( new CustomEvent("djdt.panel.render", { detail: { panelId: panelId }, - }), + }) ); }); } else { djDebug.dispatchEvent( new CustomEvent("djdt.panel.render", { detail: { panelId: panelId }, - }), + }) ); } } - }, + } ); $$.on(djDebug, "click", ".djDebugClose", function () { djdt.hide_one_level(); @@ -76,9 +76,9 @@ const djdt = { { path: "/", expires: 10, - }, + } ); - }, + } ); // Used by the SQL and template panels @@ -219,7 +219,7 @@ const djdt = { // set handle position const handleTop = Math.min( localStorage.getItem("djdt.top") || 0, - window.innerHeight - handle.offsetWidth, + window.innerHeight - handle.offsetWidth ); handle.style.top = handleTop + "px"; }, diff --git a/debug_toolbar/static/debug_toolbar/js/utils.js b/debug_toolbar/static/debug_toolbar/js/utils.js index 065c1d42e..72c767fb6 100644 --- a/debug_toolbar/static/debug_toolbar/js/utils.js +++ b/debug_toolbar/static/debug_toolbar/js/utils.js @@ -77,7 +77,7 @@ function ajax(url, init) { return response.json(); } return Promise.reject( - new Error(response.status + ": " + response.statusText), + new Error(response.status + ": " + response.statusText) ); }) .catch(function (error) { From 5923f384db0e1090e67be07e83400e89fbddcbe2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 12 Sep 2022 18:16:55 +0000 Subject: [PATCH 05/12] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/adamchainz/django-upgrade: 1.9.0 → 1.10.0](https://github.com/adamchainz/django-upgrade/compare/1.9.0...1.10.0) - [github.com/pre-commit/mirrors-eslint: v8.23.0 → v8.23.1](https://github.com/pre-commit/mirrors-eslint/compare/v8.23.0...v8.23.1) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 07de1cd35..f215cff3c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: - id: pyupgrade args: [--py37-plus] - repo: https://github.com/adamchainz/django-upgrade - rev: 1.9.0 + rev: 1.10.0 hooks: - id: django-upgrade args: [--target-version, "3.2"] @@ -45,7 +45,7 @@ repos: args: - --trailing-comma=es5 - repo: https://github.com/pre-commit/mirrors-eslint - rev: v8.23.0 + rev: v8.23.1 hooks: - id: eslint files: \.js?$ From c88a13d62bb42dc87e35af1efc1677a365c8267d Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@feinheit.ch> Date: Fri, 16 Sep 2022 09:56:54 +0200 Subject: [PATCH 06/12] Use system font stack in the toolbar We follow the Django admin's lead, see https://code.djangoproject.com/ticket/33878 --- .../static/debug_toolbar/css/toolbar.css | 41 +++++++++++-------- docs/changes.rst | 2 + 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/debug_toolbar/static/debug_toolbar/css/toolbar.css b/debug_toolbar/static/debug_toolbar/css/toolbar.css index a105bfd11..c70eaf5ed 100644 --- a/debug_toolbar/static/debug_toolbar/css/toolbar.css +++ b/debug_toolbar/static/debug_toolbar/css/toolbar.css @@ -76,7 +76,9 @@ color: #000; vertical-align: baseline; background-color: transparent; - font-family: sans-serif; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, + Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; text-align: left; text-shadow: none; white-space: normal; @@ -237,13 +239,30 @@ font-size: 16px; } +#djDebug pre, #djDebug code { display: block; - font-family: Consolas, Monaco, "Bitstream Vera Sans Mono", "Lucida Console", - monospace; + font-family: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", + "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", + "Fira Mono", "Droid Sans Mono", "Courier New", monospace, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", + "Noto Color Emoji"; + overflow: auto; +} + +#djDebug code { font-size: 12px; white-space: pre; - overflow: auto; +} + +#djDebug pre { + white-space: pre-wrap; + color: #555; + border: 1px solid #ccc; + border-collapse: collapse; + background-color: #fff; + padding: 2px 3px; + margin-bottom: 3px; } #djDebug .djdt-panelContent { @@ -562,19 +581,7 @@ #djDebug .djSQLDetailsDiv { margin-top: 0.8em; } -#djDebug pre { - white-space: pre-wrap; - color: #555; - border: 1px solid #ccc; - border-collapse: collapse; - background-color: #fff; - display: block; - overflow: auto; - padding: 2px 3px; - margin-bottom: 3px; - font-family: Consolas, Monaco, "Bitstream Vera Sans Mono", "Lucida Console", - monospace; -} + #djDebug .djdt-stack span { color: #000; font-weight: bold; diff --git a/docs/changes.rst b/docs/changes.rst index df6be99f2..bd66d7658 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -4,6 +4,8 @@ Change log Pending ------- +* The toolbar's font stack now prefers system UI fonts. + 3.6.0 (2022-08-17) ------------------ From be0a433e9bda4bdca1de01387422a3cf94a7c20b Mon Sep 17 00:00:00 2001 From: Tim Schilling <schillingt@better-simple.com> Date: Fri, 16 Sep 2022 08:58:04 -0500 Subject: [PATCH 07/12] Profiling panel improvements (#1669) * Give users control over including more profiling data. * The profiling panel will now include more user code. By checking that the code lives in the settings.BASE_DIR directory, we know that the code was likely written by the user and thus more important to a developer when debugging code. * Highlight the project function calls in the profiling panel. * Add setting PROFILER_CAPTURE_PROJECT_CODE. This can be used to disable the attempt to include all project code. This is useful if dependencies are installed within the project. * Fix bug with test_cum_time_threshold profiling. * Include dist-packages in profiling panel docs. Co-authored-by: Matthias Kestenholz <mk@feinheit.ch> --- debug_toolbar/panels/profiling.py | 34 ++++++++++++++++--- debug_toolbar/settings.py | 2 ++ .../static/debug_toolbar/css/toolbar.css | 6 ++++ .../debug_toolbar/panels/profiling.html | 2 +- docs/changes.rst | 10 ++++++ docs/configuration.rst | 26 ++++++++++++++ docs/panels.rst | 6 ++++ docs/tips.rst | 2 ++ tests/panels/test_profiling.py | 15 ++++++++ 9 files changed, 98 insertions(+), 5 deletions(-) diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py index 5fd5b3c84..ca32b98c2 100644 --- a/debug_toolbar/panels/profiling.py +++ b/debug_toolbar/panels/profiling.py @@ -3,6 +3,7 @@ from colorsys import hsv_to_rgb from pstats import Stats +from django.conf import settings from django.utils.html import format_html from django.utils.translation import gettext_lazy as _ @@ -32,6 +33,22 @@ def background(self): r, g, b = hsv_to_rgb(*self.hsv) return f"rgb({r * 100:f}%,{g * 100:f}%,{b * 100:f}%)" + def is_project_func(self): + """ + Check if the function is from the project code. + + Project code is identified by the BASE_DIR setting + which is used in Django projects by default. + """ + if hasattr(settings, "BASE_DIR"): + file_name, _, _ = self.func + return ( + str(settings.BASE_DIR) in file_name + and "/site-packages/" not in file_name + and "/dist-packages/" not in file_name + ) + return None + def func_std_string(self): # match what old profile produced func_name = self.func if func_name[:2] == ("~", 0): @@ -123,19 +140,25 @@ class ProfilingPanel(Panel): title = _("Profiling") template = "debug_toolbar/panels/profiling.html" + capture_project_code = dt_settings.get_config()["PROFILER_CAPTURE_PROJECT_CODE"] def process_request(self, request): self.profiler = cProfile.Profile() return self.profiler.runcall(super().process_request, request) - def add_node(self, func_list, func, max_depth, cum_time=0.1): + def add_node(self, func_list, func, max_depth, cum_time): func_list.append(func) func.has_subfuncs = False if func.depth < max_depth: for subfunc in func.subfuncs(): - if subfunc.stats[3] >= cum_time: + # Always include the user's code + if subfunc.stats[3] >= cum_time or ( + self.capture_project_code + and subfunc.is_project_func() + and subfunc.stats[3] > 0 + ): func.has_subfuncs = True - self.add_node(func_list, subfunc, max_depth, cum_time=cum_time) + self.add_node(func_list, subfunc, max_depth, cum_time) def generate_stats(self, request, response): if not hasattr(self, "profiler"): @@ -150,10 +173,13 @@ def generate_stats(self, request, response): if root_func in self.stats.stats: root = FunctionCall(self.stats, root_func, depth=0) func_list = [] + cum_time_threshold = ( + root.stats[3] / dt_settings.get_config()["PROFILER_THRESHOLD_RATIO"] + ) self.add_node( func_list, root, dt_settings.get_config()["PROFILER_MAX_DEPTH"], - root.stats[3] / 8, + cum_time_threshold, ) self.record_stats({"func_list": func_list}) diff --git a/debug_toolbar/settings.py b/debug_toolbar/settings.py index 5bf9bb09f..2bad251c1 100644 --- a/debug_toolbar/settings.py +++ b/debug_toolbar/settings.py @@ -33,7 +33,9 @@ "django.utils.functional", ), "PRETTIFY_SQL": True, + "PROFILER_CAPTURE_PROJECT_CODE": True, "PROFILER_MAX_DEPTH": 10, + "PROFILER_THRESHOLD_RATIO": 8, "SHOW_TEMPLATE_CONTEXT": True, "SKIP_TEMPLATE_PREFIXES": ("django/forms/widgets/", "admin/widgets/"), "SQL_WARNING_THRESHOLD": 500, # milliseconds diff --git a/debug_toolbar/static/debug_toolbar/css/toolbar.css b/debug_toolbar/static/debug_toolbar/css/toolbar.css index c70eaf5ed..0aba24ab9 100644 --- a/debug_toolbar/static/debug_toolbar/css/toolbar.css +++ b/debug_toolbar/static/debug_toolbar/css/toolbar.css @@ -621,6 +621,12 @@ #djDebug .djdt-highlighted { background-color: lightgrey; } +#djDebug tr.djdt-highlighted.djdt-profile-row { + background-color: #ffc; +} +#djDebug tr.djdt-highlighted.djdt-profile-row:nth-child(2n + 1) { + background-color: #dd9; +} @keyframes djdt-flash-new { from { background-color: green; diff --git a/debug_toolbar/templates/debug_toolbar/panels/profiling.html b/debug_toolbar/templates/debug_toolbar/panels/profiling.html index 837698889..4c1c3acd3 100644 --- a/debug_toolbar/templates/debug_toolbar/panels/profiling.html +++ b/debug_toolbar/templates/debug_toolbar/panels/profiling.html @@ -12,7 +12,7 @@ </thead> <tbody> {% for call in func_list %} - <tr class="{% for parent_id in call.parent_ids %} djToggleDetails_{{ parent_id }}{% endfor %}" id="profilingMain_{{ call.id }}"> + <tr class="djdt-profile-row {% if call.is_project_func %}djdt-highlighted {% endif %} {% for parent_id in call.parent_ids %} djToggleDetails_{{ parent_id }}{% endfor %}" id="profilingMain_{{ call.id }}"> <td> <div data-djdt-styles="paddingLeft:{{ call.indent }}px"> {% if call.has_subfuncs %} diff --git a/docs/changes.rst b/docs/changes.rst index bd66d7658..923f18dec 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -4,6 +4,16 @@ Change log Pending ------- +* Added Profiling panel setting ``PROFILER_THRESHOLD_RATIO`` to give users + better control over how many function calls are included. A higher value + will include more data, but increase render time. +* Update Profiling panel to include try to always include user code. This + code is more important to developers than dependency code. +* Highlight the project function calls in the profiling panel. +* Added Profiling panel setting ``PROFILER_CAPTURE_PROJECT_CODE`` to allow + users to disable the inclusion of all project code. This will be useful + to project setups that have dependencies installed under + ``settings.BASE_DIR``. * The toolbar's font stack now prefers system UI fonts. 3.6.0 (2022-08-17) diff --git a/docs/configuration.rst b/docs/configuration.rst index 6f4084ad5..07e0a845c 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -250,6 +250,18 @@ Panel options WHERE "auth_user"."username" = '''test_username''' LIMIT 21 +* ``PROFILER_CAPTURE_PROJECT_CODE`` + + Default: ``True`` + + Panel: profiling + + When enabled this setting will include all project function calls in the + panel. Project code is defined as files in the path defined at + ``settings.BASE_DIR``. If you install dependencies under + ``settings.BASE_DIR`` in a directory other than ``sites-packages`` or + ``dist-packages`` you may need to disable this setting. + * ``PROFILER_MAX_DEPTH`` Default: ``10`` @@ -259,6 +271,20 @@ Panel options This setting affects the depth of function calls in the profiler's analysis. +* ``PROFILER_THRESHOLD_RATIO`` + + Default: ``8`` + + Panel: profiling + + This setting affects the which calls are included in the profile. A higher + value will include more function calls. A lower value will result in a faster + render of the profiling panel, but will exclude data. + + This value is used to determine the threshold of cumulative time to include + the nested functions. The threshold is calculated by the root calls' + cumulative time divided by this ratio. + * ``SHOW_TEMPLATE_CONTEXT`` Default: ``True`` diff --git a/docs/panels.rst b/docs/panels.rst index 8e5558aab..09891f2e5 100644 --- a/docs/panels.rst +++ b/docs/panels.rst @@ -130,6 +130,12 @@ Profiling information for the processing of the request. This panel is included but inactive by default. You can activate it by default with the ``DISABLE_PANELS`` configuration option. +The panel will include all function calls made by your project if you're using +the setting ``settings.BASE_DIR`` to point to your project's root directory. +If a function is in a file within that directory and does not include +``"/site-packages/"`` or ``"/dist-packages/"`` in the path, it will be +included. + Third-party panels ------------------ diff --git a/docs/tips.rst b/docs/tips.rst index e6957b0c6..d5d160fb3 100644 --- a/docs/tips.rst +++ b/docs/tips.rst @@ -77,6 +77,8 @@ by disabling some configuration options that are enabled by default: - ``ENABLE_STACKTRACES`` for the SQL and cache panels, - ``SHOW_TEMPLATE_CONTEXT`` for the template panel. +- ``PROFILER_CAPTURE_PROJECT_CODE`` and ``PROFILER_THRESHOLD_RATIO`` for the + profiling panel. Also, check ``SKIP_TEMPLATE_PREFIXES`` when you're using template-based form widgets. diff --git a/tests/panels/test_profiling.py b/tests/panels/test_profiling.py index ca5c2463b..2169932b2 100644 --- a/tests/panels/test_profiling.py +++ b/tests/panels/test_profiling.py @@ -33,6 +33,21 @@ def test_insert_content(self): # ensure the panel renders correctly. content = self.panel.content self.assertIn("regular_view", content) + self.assertIn("render", content) + self.assertValidHTML(content) + + @override_settings(DEBUG_TOOLBAR_CONFIG={"PROFILER_THRESHOLD_RATIO": 1}) + def test_cum_time_threshold(self): + """ + Test that cumulative time threshold excludes calls + """ + self._get_response = lambda request: regular_view(request, "profiling") + response = self.panel.process_request(self.request) + self.panel.generate_stats(self.request, response) + # ensure the panel renders but doesn't include our function. + content = self.panel.content + self.assertIn("regular_view", content) + self.assertNotIn("render", content) self.assertValidHTML(content) def test_listcomp_escaped(self): From c359e762ec02a444863d604403c91fd6050dff20 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@feinheit.ch> Date: Fri, 16 Sep 2022 16:53:01 +0200 Subject: [PATCH 08/12] Tweak spacings a bit because of the changed fonts --- .../static/debug_toolbar/css/toolbar.css | 15 +++++++++------ docs/changes.rst | 3 ++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/debug_toolbar/static/debug_toolbar/css/toolbar.css b/debug_toolbar/static/debug_toolbar/css/toolbar.css index 0aba24ab9..f87d7a133 100644 --- a/debug_toolbar/static/debug_toolbar/css/toolbar.css +++ b/debug_toolbar/static/debug_toolbar/css/toolbar.css @@ -64,6 +64,7 @@ #djDebug tr, #djDebug th, #djDebug td, +#djDebug summary, #djDebug button { margin: 0; padding: 0; @@ -159,7 +160,7 @@ text-decoration: none; display: block; font-size: 16px; - padding: 10px 10px 5px 25px; + padding: 7px 10px 8px 25px; color: #fff; } #djDebug #djDebugToolbar li > div.djdt-disabled { @@ -178,6 +179,7 @@ #djDebug #djDebugToolbar li.djdt-active:before { content: "▶"; + font-family: sans-serif; position: absolute; left: 0; top: 50%; @@ -388,18 +390,19 @@ position: absolute; top: 4px; right: 15px; - height: 16px; - width: 16px; line-height: 16px; - padding: 5px; border: 6px solid #ddd; border-radius: 50%; background: #fff; color: #ddd; - text-align: center; font-weight: 900; font-size: 20px; - box-sizing: content-box; + height: 36px; + width: 36px; + padding: 0 0 5px; + box-sizing: border-box; + display: grid; + place-items: center; } #djDebug .djdt-panelContent .djDebugClose:hover { diff --git a/docs/changes.rst b/docs/changes.rst index 923f18dec..e819ed66d 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -14,7 +14,8 @@ Pending users to disable the inclusion of all project code. This will be useful to project setups that have dependencies installed under ``settings.BASE_DIR``. -* The toolbar's font stack now prefers system UI fonts. +* The toolbar's font stack now prefers system UI fonts. Tweaked the CSS a bit + to improve spacings. 3.6.0 (2022-08-17) ------------------ From 6bc4ca2b7bbbef450a5735c3affa4bcd9a8e0049 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz <mk@feinheit.ch> Date: Fri, 16 Sep 2022 17:23:57 +0200 Subject: [PATCH 09/12] Make the docs linter happy --- docs/changes.rst | 4 ++-- docs/spelling_wordlist.txt | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/changes.rst b/docs/changes.rst index e819ed66d..1c45177b0 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -14,8 +14,8 @@ Pending users to disable the inclusion of all project code. This will be useful to project setups that have dependencies installed under ``settings.BASE_DIR``. -* The toolbar's font stack now prefers system UI fonts. Tweaked the CSS a bit - to improve spacings. +* The toolbar's font stack now prefers system UI fonts. Tweaked paddings, + margins and alignments a bit in the CSS code. 3.6.0 (2022-08-17) ------------------ diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index ee911963f..5e3a7f64b 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -16,12 +16,14 @@ jQuery jrestclient js Makefile +margins memcache memcached middleware middlewares multi neo +paddings pre profiler psycopg From 5cbf357805c04cd33cfa69fef44c48f7ba810a3d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 19 Sep 2022 18:30:52 +0000 Subject: [PATCH 10/12] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v2.37.3 → v2.38.0](https://github.com/asottile/pyupgrade/compare/v2.37.3...v2.38.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f215cff3c..6e9ac0b64 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: hooks: - id: doc8 - repo: https://github.com/asottile/pyupgrade - rev: v2.37.3 + rev: v2.38.0 hooks: - id: pyupgrade args: [--py37-plus] From 348e582645465b319e4f7cf3b2bd4f3853cebad1 Mon Sep 17 00:00:00 2001 From: Ritik Soni <47344024+ritiksoni00@users.noreply.github.com> Date: Sun, 25 Sep 2022 21:20:05 +0530 Subject: [PATCH 11/12] added functionality to keep unsort the session dict (#1673) * added functionality to keep unsort the session dict * Update tests/panels/test_request.py Co-authored-by: Matthias Kestenholz <mk@feinheit.ch> * Add mention of session sorting change to changes.rst. Co-authored-by: Matthias Kestenholz <mk@feinheit.ch> Co-authored-by: tschilling <schillingt@better-simple.com> --- debug_toolbar/panels/request.py | 19 +++++++++---------- docs/changes.rst | 2 ++ tests/panels/test_request.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/debug_toolbar/panels/request.py b/debug_toolbar/panels/request.py index 966301d97..bfb485ae7 100644 --- a/debug_toolbar/panels/request.py +++ b/debug_toolbar/panels/request.py @@ -59,13 +59,12 @@ def generate_stats(self, request, response): self.record_stats(view_info) if hasattr(request, "session"): - self.record_stats( - { - "session": { - "list": [ - (k, request.session.get(k)) - for k in sorted(request.session.keys()) - ] - } - } - ) + try: + session_list = [ + (k, request.session.get(k)) for k in sorted(request.session.keys()) + ] + except TypeError: + session_list = [ + (k, request.session.get(k)) for k in request.session.keys() + ] + self.record_stats({"session": {"list": session_list}}) diff --git a/docs/changes.rst b/docs/changes.rst index 1c45177b0..e049aa3a5 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -16,6 +16,8 @@ Pending ``settings.BASE_DIR``. * The toolbar's font stack now prefers system UI fonts. Tweaked paddings, margins and alignments a bit in the CSS code. +* Only sort the session dictionary when the keys are all strings. Fixes a + bug that causes the toolbar to crash when non-strings are used as keys. 3.6.0 (2022-08-17) ------------------ diff --git a/tests/panels/test_request.py b/tests/panels/test_request.py index 8087203c3..ea7f1681a 100644 --- a/tests/panels/test_request.py +++ b/tests/panels/test_request.py @@ -104,3 +104,32 @@ def test_namespaced_url(self): self.panel.generate_stats(self.request, response) panel_stats = self.panel.get_stats() self.assertEqual(panel_stats["view_urlname"], "admin:login") + + def test_session_list_sorted_or_not(self): + """ + Verify the session is sorted when all keys are strings. + + See https://github.com/jazzband/django-debug-toolbar/issues/1668 + """ + self.request.session = { + 1: "value", + "data": ["foo", "bar", 1], + (2, 3): "tuple_key", + } + data = { + "list": [(1, "value"), ("data", ["foo", "bar", 1]), ((2, 3), "tuple_key")] + } + response = self.panel.process_request(self.request) + self.panel.generate_stats(self.request, response) + panel_stats = self.panel.get_stats() + self.assertEqual(panel_stats["session"], data) + + self.request.session = { + "b": "b-value", + "a": "a-value", + } + data = {"list": [("a", "a-value"), ("b", "b-value")]} + response = self.panel.process_request(self.request) + self.panel.generate_stats(self.request, response) + panel_stats = self.panel.get_stats() + self.assertEqual(panel_stats["session"], data) From 9f0b938242e90e4950621f14d94e2a989a218ca5 Mon Sep 17 00:00:00 2001 From: tschilling <schillingt@better-simple.com> Date: Sun, 25 Sep 2022 10:53:07 -0500 Subject: [PATCH 12/12] Version 3.7.0 --- README.rst | 2 +- debug_toolbar/__init__.py | 2 +- docs/changes.rst | 3 +++ docs/conf.py | 2 +- setup.cfg | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index c7ea51bd6..d050f5068 100644 --- a/README.rst +++ b/README.rst @@ -44,7 +44,7 @@ Here's a screenshot of the toolbar in action: In addition to the built-in panels, a number of third-party panels are contributed by the community. -The current stable version of the Debug Toolbar is 3.6.0. It works on +The current stable version of the Debug Toolbar is 3.7.0. It works on Django ≥ 3.2.4. Documentation, including installation and configuration instructions, is diff --git a/debug_toolbar/__init__.py b/debug_toolbar/__init__.py index 17f1f9e69..e9ed74ab1 100644 --- a/debug_toolbar/__init__.py +++ b/debug_toolbar/__init__.py @@ -4,7 +4,7 @@ # Do not use pkg_resources to find the version but set it here directly! # see issue #1446 -VERSION = "3.6.0" +VERSION = "3.7.0" # Code that discovers files or modules in INSTALLED_APPS imports this module. urls = "debug_toolbar.urls", APP_NAME diff --git a/docs/changes.rst b/docs/changes.rst index e049aa3a5..720a8c050 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -4,6 +4,9 @@ Change log Pending ------- +3.7.0 (2022-09-25) +------------------ + * Added Profiling panel setting ``PROFILER_THRESHOLD_RATIO`` to give users better control over how many function calls are included. A higher value will include more data, but increase render time. diff --git a/docs/conf.py b/docs/conf.py index 476a055de..97bab48c8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -25,7 +25,7 @@ copyright = copyright.format(datetime.date.today().year) # The full version, including alpha/beta/rc tags -release = "3.6.0" +release = "3.7.0" # -- General configuration --------------------------------------------------- diff --git a/setup.cfg b/setup.cfg index 5daaee0bd..1c3c105d5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = django-debug-toolbar -version = 3.6.0 +version = 3.7.0 description = A configurable set of panels that display various debug information about the current request/response. long_description = file: README.rst long_description_content_type = text/x-rst