Skip to content

Commit 2fafbb4

Browse files
committed
Merge branch 'main' into serializable
2 parents 7a638c7 + 772db88 commit 2fafbb4

File tree

10 files changed

+66
-63
lines changed

10 files changed

+66
-63
lines changed

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ jobs:
6969
name: python-package-distributions
7070
path: dist/
7171
- name: Sign the dists with Sigstore
72-
uses: sigstore/[email protected].0
72+
uses: sigstore/[email protected].1
7373
with:
7474
inputs: >-
7575
./dist/*.tar.gz

.pre-commit-config.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ repos:
1010
- id: file-contents-sorter
1111
files: docs/spelling_wordlist.txt
1212
- repo: https://github.com/pycqa/doc8
13-
rev: v1.1.2
13+
rev: v2.0.0
1414
hooks:
1515
- id: doc8
1616
- repo: https://github.com/adamchainz/django-upgrade
@@ -29,18 +29,18 @@ repos:
2929
- id: rst-backticks
3030
- id: rst-directive-colons
3131
- repo: https://github.com/biomejs/pre-commit
32-
rev: v2.0.0-beta.4
32+
rev: v2.0.6
3333
hooks:
3434
- id: biome-check
3535
verbose: true
3636
- repo: https://github.com/astral-sh/ruff-pre-commit
37-
rev: 'v0.11.10'
37+
rev: 'v0.12.2'
3838
hooks:
3939
- id: ruff
4040
args: [--fix, --exit-non-zero-on-fix]
4141
- id: ruff-format
4242
- repo: https://github.com/tox-dev/pyproject-fmt
43-
rev: v2.5.1
43+
rev: v2.6.0
4444
hooks:
4545
- id: pyproject-fmt
4646
- repo: https://github.com/abravalheri/validate-pyproject

biome.json

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"$schema": "https://biomejs.dev/schemas/2.0.0-beta.2/schema.json",
2+
"$schema": "https://biomejs.dev/schemas/2.0.6/schema.json",
33
"formatter": {
44
"enabled": true,
55
"useEditorconfig": true
@@ -15,29 +15,8 @@
1515
"enabled": true,
1616
"rules": {
1717
"recommended": true,
18-
"style": {
19-
"useLiteralEnumMembers": "error",
20-
"noCommaOperator": "error",
21-
"useNodejsImportProtocol": "error",
22-
"useAsConstAssertion": "error",
23-
"useNumericLiterals": "error",
24-
"useEnumInitializers": "error",
25-
"useSelfClosingElements": "error",
26-
"useConst": "error",
27-
"useSingleVarDeclarator": "error",
28-
"noUnusedTemplateLiteral": "error",
29-
"useNumberNamespace": "error",
30-
"noInferrableTypes": "error",
31-
"useExponentiationOperator": "error",
32-
"useTemplate": "error",
33-
"noParameterAssign": "error",
34-
"noNonNullAssertion": "error",
35-
"useDefaultParameterLast": "error",
36-
"noArguments": "error",
37-
"useImportType": "error",
38-
"useExportType": "error",
39-
"noUselessElse": "error",
40-
"useShorthandFunctionType": "error"
18+
"correctness": {
19+
"noUndeclaredVariables": "error"
4120
},
4221
"suspicious": {
4322
"noDocumentCookie": "off"
@@ -46,8 +25,7 @@
4625
},
4726
"javascript": {
4827
"formatter": {
49-
"trailingCommas": "es5",
50-
"quoteStyle": "double"
28+
"trailingCommas": "es5"
5129
}
5230
}
5331
}

debug_toolbar/middleware.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@ def show_toolbar(request):
3131
if request.META.get("REMOTE_ADDR") in settings.INTERNAL_IPS:
3232
return True
3333

34+
# No test passed
35+
return False
36+
37+
38+
def show_toolbar_with_docker(request):
39+
"""
40+
Default function to determine whether to show the toolbar on a given page.
41+
"""
42+
if not settings.DEBUG:
43+
return False
44+
45+
# Test: settings
46+
if request.META.get("REMOTE_ADDR") in settings.INTERNAL_IPS:
47+
return True
48+
3449
# Test: Docker
3550
try:
3651
# This is a hack for docker installations. It attempts to look

debug_toolbar/static/debug_toolbar/css/toolbar.css

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/* Variable definitions */
22
:root {
33
/* Font families are the same as in Django admin/css/base.css */
4-
--djdt-font-family-primary: "Segoe UI", system-ui, Roboto, "Helvetica Neue",
5-
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
6-
"Segoe UI Symbol", "Noto Color Emoji";
4+
--djdt-font-family-primary:
5+
"Segoe UI", system-ui, Roboto, "Helvetica Neue", Arial, sans-serif,
6+
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
7+
"Noto Color Emoji";
78
--djdt-font-family-monospace:
89
ui-monospace, Menlo, Monaco, "Cascadia Mono",
910
"Segoe UI Mono", "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace",

docs/changes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Pending
66

77
* Added support for checking if pytest as the test runner when determining
88
if tests are running.
9+
* Added ``show_toolbar_with_docker`` function to check Docker host IP address
10+
when running inside Docker containers.
911
* Defines the ``BaseStore`` interface for request storage mechanisms.
1012
* Added the setting ``TOOLBAR_STORE_CLASS`` to configure the request
1113
storage mechanism. Defaults to ``debug_toolbar.store.MemoryStore``.
@@ -68,6 +70,7 @@ Pending
6870
* Fix for exception-unhandled "forked" Promise chain in rebound window.fetch
6971
* Create a CSP nonce property on the toolbar ``Toolbar().csp_nonce``.
7072

73+
7174
5.0.1 (2025-01-13)
7275
------------------
7376
* Fixing the build and release process. No functional changes.

docs/installation.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,11 @@ option.
152152

153153
.. warning::
154154

155-
If using Docker, the toolbar will attempt to look up your host name
156-
automatically and treat it as an allowable internal IP. If you're not
157-
able to get the toolbar to work with your docker installation, review
158-
the code in ``debug_toolbar.middleware.show_toolbar``.
155+
If using Docker you can use
156+
``debug_toolbar.middleware.show_toolbar_with_docker`` as your
157+
``SHOW_TOOLBAR_CALLBACK`` which attempts to automatically look up the
158+
Docker gateway IP and treat it as an allowable internal IP so that the
159+
toolbar is shown to you.
159160

160161
7. Disable the toolbar when running tests (optional)
161162
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_csp_rendering.py

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
from __future__ import annotations
22

3-
from typing import cast
4-
from xml.etree.ElementTree import Element
5-
63
from django.conf import settings
7-
from django.http.response import HttpResponse
84
from django.test.utils import override_settings
95
from html5lib.constants import E
106
from html5lib.html5parser import HTMLParser
@@ -22,7 +18,7 @@
2218
MIDDLEWARE_CSP_LAST = settings.MIDDLEWARE + ["csp.middleware.CSPMiddleware"]
2319

2420

25-
def get_namespaces(element: Element) -> dict[str, str]:
21+
def get_namespaces(element):
2622
"""
2723
Return the default `xmlns`. See
2824
https://docs.python.org/3/library/xml.etree.elementtree.html#parsing-xml-with-namespaces
@@ -40,9 +36,7 @@ def setUp(self):
4036
super().setUp()
4137
self.parser = HTMLParser()
4238

43-
def _fail_if_missing(
44-
self, root: Element, path: str, namespaces: dict[str, str], nonce: str
45-
):
39+
def _fail_if_missing(self, root, path, namespaces, nonce):
4640
"""
4741
Search elements, fail if a `nonce` attribute is missing on them.
4842
"""
@@ -51,7 +45,7 @@ def _fail_if_missing(
5145
if item.attrib.get("nonce") != nonce:
5246
raise self.failureException(f"{item} has no nonce attribute.")
5347

54-
def _fail_if_found(self, root: Element, path: str, namespaces: dict[str, str]):
48+
def _fail_if_found(self, root, path, namespaces):
5549
"""
5650
Search elements, fail if a `nonce` attribute is found on them.
5751
"""
@@ -60,7 +54,7 @@ def _fail_if_found(self, root: Element, path: str, namespaces: dict[str, str]):
6054
if "nonce" in item.attrib:
6155
raise self.failureException(f"{item} has a nonce attribute.")
6256

63-
def _fail_on_invalid_html(self, content: bytes, parser: HTMLParser):
57+
def _fail_on_invalid_html(self, content, parser):
6458
"""Fail if the passed HTML is invalid."""
6559
if parser.errors:
6660
default_msg = ["Content is invalid HTML:"]
@@ -75,10 +69,10 @@ def test_exists(self):
7569
"""A `nonce` should exist when using the `CSPMiddleware`."""
7670
for middleware in [MIDDLEWARE_CSP_BEFORE, MIDDLEWARE_CSP_LAST]:
7771
with self.settings(MIDDLEWARE=middleware):
78-
response = cast(HttpResponse, self.client.get(path="/csp_view/"))
72+
response = self.client.get(path="/csp_view/")
7973
self.assertEqual(response.status_code, 200)
8074

81-
html_root: Element = self.parser.parse(stream=response.content)
75+
html_root = self.parser.parse(stream=response.content)
8276
self._fail_on_invalid_html(content=response.content, parser=self.parser)
8377
self.assertContains(response, "djDebug")
8478

@@ -98,10 +92,10 @@ def test_does_not_exist_nonce_wasnt_used(self):
9892
"""
9993
for middleware in [MIDDLEWARE_CSP_BEFORE, MIDDLEWARE_CSP_LAST]:
10094
with self.settings(MIDDLEWARE=middleware):
101-
response = cast(HttpResponse, self.client.get(path="/regular/basic/"))
95+
response = self.client.get(path="/regular/basic/")
10296
self.assertEqual(response.status_code, 200)
10397

104-
html_root: Element = self.parser.parse(stream=response.content)
98+
html_root = self.parser.parse(stream=response.content)
10599
self._fail_on_invalid_html(content=response.content, parser=self.parser)
106100
self.assertContains(response, "djDebug")
107101

@@ -119,15 +113,16 @@ def test_does_not_exist_nonce_wasnt_used(self):
119113
def test_redirects_exists(self):
120114
for middleware in [MIDDLEWARE_CSP_BEFORE, MIDDLEWARE_CSP_LAST]:
121115
with self.settings(MIDDLEWARE=middleware):
122-
response = cast(HttpResponse, self.client.get(path="/csp_view/"))
116+
response = self.client.get(path="/csp_view/")
123117
self.assertEqual(response.status_code, 200)
124118

125-
html_root: Element = self.parser.parse(stream=response.content)
119+
html_root = self.parser.parse(stream=response.content)
126120
self._fail_on_invalid_html(content=response.content, parser=self.parser)
127121
self.assertContains(response, "djDebug")
128122

129123
namespaces = get_namespaces(element=html_root)
130-
nonce = response.context["request"].csp_nonce
124+
context = response.context
125+
nonce = str(context["toolbar"].csp_nonce)
131126
self._fail_if_missing(
132127
root=html_root, path=".//link", namespaces=namespaces, nonce=nonce
133128
)
@@ -139,15 +134,15 @@ def test_panel_content_nonce_exists(self):
139134
store = get_store()
140135
for middleware in [MIDDLEWARE_CSP_BEFORE, MIDDLEWARE_CSP_LAST]:
141136
with self.settings(MIDDLEWARE=middleware):
142-
response = cast(HttpResponse, self.client.get(path="/csp_view/"))
137+
response = self.client.get(path="/csp_view/")
143138
self.assertEqual(response.status_code, 200)
144139

145140
request_ids = list(store.request_ids())
146141
toolbar = DebugToolbar.fetch(request_ids[-1])
147142
panels_to_check = ["HistoryPanel", "TimerPanel"]
148143
for panel in panels_to_check:
149144
content = toolbar.get_panel_by_id(panel).content
150-
html_root: Element = self.parser.parse(stream=content)
145+
html_root = self.parser.parse(stream=content)
151146
namespaces = get_namespaces(element=html_root)
152147
nonce = str(toolbar.csp_nonce)
153148
self._fail_if_missing(
@@ -165,10 +160,10 @@ def test_panel_content_nonce_exists(self):
165160

166161
def test_missing(self):
167162
"""A `nonce` should not exist when not using the `CSPMiddleware`."""
168-
response = cast(HttpResponse, self.client.get(path="/regular/basic/"))
163+
response = self.client.get(path="/regular/basic/")
169164
self.assertEqual(response.status_code, 200)
170165

171-
html_root: Element = self.parser.parse(stream=response.content)
166+
html_root = self.parser.parse(stream=response.content)
172167
self._fail_on_invalid_html(content=response.content, parser=self.parser)
173168
self.assertContains(response, "djDebug")
174169

tests/test_integration.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
from django.test.utils import override_settings
1616

1717
from debug_toolbar.forms import SignedDataForm
18-
from debug_toolbar.middleware import DebugToolbarMiddleware, show_toolbar
18+
from debug_toolbar.middleware import (
19+
DebugToolbarMiddleware,
20+
show_toolbar,
21+
show_toolbar_with_docker,
22+
)
1923
from debug_toolbar.panels import Panel
2024
from debug_toolbar.panels.cache import CachePanel
2125
from debug_toolbar.panels.history import HistoryPanel
@@ -79,7 +83,8 @@ def test_show_toolbar_docker(self, mocked_gethostbyname):
7983
with self.settings(INTERNAL_IPS=[]):
8084
# Is true because REMOTE_ADDR is 127.0.0.1 and the 255
8185
# is shifted to be 1.
82-
self.assertTrue(show_toolbar(self.request))
86+
self.assertFalse(show_toolbar(self.request))
87+
self.assertTrue(show_toolbar_with_docker(self.request))
8388
mocked_gethostbyname.assert_called_once_with("host.docker.internal")
8489

8590
def test_not_iterating_over_INTERNAL_IPS(self):

tests/test_integration_async.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
from django.test.utils import override_settings
1212

1313
from debug_toolbar.forms import SignedDataForm
14-
from debug_toolbar.middleware import DebugToolbarMiddleware, show_toolbar
14+
from debug_toolbar.middleware import (
15+
DebugToolbarMiddleware,
16+
show_toolbar,
17+
show_toolbar_with_docker,
18+
)
1519
from debug_toolbar.panels import Panel
1620
from debug_toolbar.panels.history import HistoryPanel
1721
from debug_toolbar.panels.sql import SQLPanel
@@ -63,7 +67,8 @@ async def test_show_toolbar_docker(self, mocked_gethostbyname):
6367
with self.settings(INTERNAL_IPS=[]):
6468
# Is true because REMOTE_ADDR is 127.0.0.1 and the 255
6569
# is shifted to be 1.
66-
self.assertTrue(show_toolbar(self.request))
70+
self.assertFalse(show_toolbar(self.request))
71+
self.assertTrue(show_toolbar_with_docker(self.request))
6772
mocked_gethostbyname.assert_called_once_with("host.docker.internal")
6873

6974
async def test_not_iterating_over_INTERNAL_IPS(self):

0 commit comments

Comments
 (0)