Skip to content

Commit e22ea43

Browse files
committed
Create basic memory store for toolbar to reproduce existing functionality.
1 parent 176614a commit e22ea43

File tree

9 files changed

+78
-30
lines changed

9 files changed

+78
-30
lines changed

debug_toolbar/panels/history/panel.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from debug_toolbar.panels import Panel
1212
from debug_toolbar.panels.history import views
1313
from debug_toolbar.panels.history.forms import HistoryStoreForm
14+
from debug_toolbar.store import store
1415

1516

1617
class HistoryPanel(Panel):
@@ -73,7 +74,7 @@ def content(self):
7374
Fetch every store for the toolbar and include it in the template.
7475
"""
7576
stores = OrderedDict()
76-
for id, toolbar in reversed(self.toolbar._store.items()):
77+
for id, toolbar in reversed(store.all()):
7778
stores[id] = {
7879
"toolbar": toolbar,
7980
"form": HistoryStoreForm(initial={"store_id": id}),

debug_toolbar/panels/history/views.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from debug_toolbar.decorators import require_show_toolbar
55
from debug_toolbar.panels.history.forms import HistoryStoreForm
6-
from debug_toolbar.toolbar import DebugToolbar
6+
from debug_toolbar.store import store
77

88

99
@require_show_toolbar
@@ -13,7 +13,7 @@ def history_sidebar(request):
1313

1414
if form.is_valid():
1515
store_id = form.cleaned_data["store_id"]
16-
toolbar = DebugToolbar.fetch(store_id)
16+
toolbar = store.get(store_id)
1717
context = {}
1818
for panel in toolbar.panels:
1919
if not panel.is_historical:
@@ -38,7 +38,7 @@ def history_refresh(request):
3838

3939
if form.is_valid():
4040
requests = []
41-
for id, toolbar in reversed(DebugToolbar._store.items()):
41+
for id, toolbar in reversed(store.all()):
4242
requests.append(
4343
{
4444
"id": id,

debug_toolbar/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"ROOT_TAG_EXTRA_ATTRS": "",
2222
"SHOW_COLLAPSED": False,
2323
"SHOW_TOOLBAR_CALLBACK": "debug_toolbar.middleware.show_toolbar",
24+
"TOOLBAR_STORE_CLASS": "debug_toolbar.store.MemoryStore",
2425
# Panel options
2526
"EXTRA_SIGNALS": [],
2627
"ENABLE_STACKTRACES": True,

debug_toolbar/store.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from collections import OrderedDict
2+
3+
from django.utils.module_loading import import_string
4+
5+
from debug_toolbar import settings as dt_settings
6+
7+
8+
class BaseStore:
9+
config = dt_settings.get_config().copy()
10+
11+
@classmethod
12+
def get(cls, store_id):
13+
raise NotImplementedError
14+
15+
@classmethod
16+
def all(cls):
17+
raise NotImplementedError
18+
19+
@classmethod
20+
def set(cls, store_id, toolbar):
21+
raise NotImplementedError
22+
23+
@classmethod
24+
def delete(cls, store_id):
25+
raise NotImplementedError
26+
27+
28+
class MemoryStore(BaseStore):
29+
_store = OrderedDict()
30+
31+
@classmethod
32+
def get(cls, store_id):
33+
return cls._store.get(store_id)
34+
35+
@classmethod
36+
def all(cls):
37+
return cls._store.items()
38+
39+
@classmethod
40+
def set(cls, store_id, toolbar):
41+
cls._store[store_id] = toolbar
42+
for _ in range(cls.config["RESULTS_CACHE_SIZE"], len(cls._store)):
43+
cls._store.popitem(last=False)
44+
45+
@classmethod
46+
def delete(cls, store_id):
47+
del cls._store[store_id]
48+
49+
50+
store = import_string(dt_settings.get_config()["TOOLBAR_STORE_CLASS"])

debug_toolbar/toolbar.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from django.utils.module_loading import import_string
1414

1515
from debug_toolbar import settings as dt_settings
16+
from debug_toolbar.store import store
1617

1718

1819
class DebugToolbar:
@@ -83,22 +84,12 @@ def should_render_panels(self):
8384
render_panels = self.request.META["wsgi.multiprocess"]
8485
return render_panels
8586

86-
# Handle storing toolbars in memory and fetching them later on
87-
88-
_store = OrderedDict()
89-
9087
def store(self):
9188
# Store already exists.
9289
if self.store_id:
9390
return
9491
self.store_id = uuid.uuid4().hex
95-
self._store[self.store_id] = self
96-
for _ in range(self.config["RESULTS_CACHE_SIZE"], len(self._store)):
97-
self._store.popitem(last=False)
98-
99-
@classmethod
100-
def fetch(cls, store_id):
101-
return cls._store.get(store_id)
92+
store.set(self.store_id, self)
10293

10394
# Manually implement class-level caching of panel classes and url patterns
10495
# because it's more obvious than going through an abstraction.

debug_toolbar/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
from django.utils.translation import gettext as _
44

55
from debug_toolbar.decorators import require_show_toolbar
6-
from debug_toolbar.toolbar import DebugToolbar
6+
from debug_toolbar.store import store
77

88

99
@require_show_toolbar
1010
def render_panel(request):
1111
"""Render the contents of a panel"""
12-
toolbar = DebugToolbar.fetch(request.GET["store_id"])
12+
toolbar = store.get(request.GET["store_id"])
1313
if toolbar is None:
1414
content = _(
1515
"Data for this panel isn't available anymore. "

tests/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from django.http import HttpResponse
33
from django.test import RequestFactory, TestCase
44

5+
from debug_toolbar.store import store
56
from debug_toolbar.toolbar import DebugToolbar
67

78
rf = RequestFactory()
@@ -52,6 +53,6 @@ def setUp(self):
5253
# The HistoryPanel keeps track of previous stores in memory.
5354
# This bleeds into other tests and violates their idempotency.
5455
# Clear the store before each test.
55-
for key in list(DebugToolbar._store.keys()):
56-
del DebugToolbar._store[key]
56+
for key, _ in list(store.all()):
57+
store.delete(key)
5758
super().setUp()

tests/panels/test_history.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from django.urls import resolve, reverse
55

66
from debug_toolbar.panels.history.forms import HistoryStoreForm
7-
from debug_toolbar.toolbar import DebugToolbar
7+
from debug_toolbar.store import store
88

99
from ..base import BaseTestCase, IntegrationTestCase
1010

@@ -68,14 +68,14 @@ def test_urls(self):
6868
class HistoryViewsTestCase(IntegrationTestCase):
6969
def test_history_panel_integration_content(self):
7070
"""Verify the history panel's content renders properly.."""
71-
self.assertEqual(len(DebugToolbar._store), 0)
71+
self.assertEqual(len(store.all()), 0)
7272

7373
data = {"foo": "bar"}
7474
self.client.get("/json_view/", data, content_type="application/json")
7575

7676
# Check the history panel's stats to verify the toolbar rendered properly.
77-
self.assertEqual(len(DebugToolbar._store), 1)
78-
toolbar = list(DebugToolbar._store.values())[0]
77+
self.assertEqual(len(store.all()), 1)
78+
toolbar = list(store.all())[0][1]
7979
content = toolbar.get_panel_by_id("HistoryPanel").content
8080
self.assertIn("bar", content)
8181

@@ -90,10 +90,10 @@ def test_history_sidebar_invalid(self):
9090
response = self.client.get(reverse("djdt:history_sidebar"), data=data)
9191
self.assertEqual(response.status_code, 400)
9292

93-
@patch("debug_toolbar.panels.history.views.DebugToolbar.fetch")
94-
def test_history_sidebar_hash(self, fetch):
93+
@patch("debug_toolbar.panels.history.views.store")
94+
def test_history_sidebar_hash(self, store):
9595
"""Validate the hashing mechanism."""
96-
fetch.return_value.panels = []
96+
store.get.return_value.panels = []
9797
data = {
9898
"store_id": "foo",
9999
"hash": "3280d66a3cca10098a44907c5a1fd255265eed31",
@@ -105,7 +105,7 @@ def test_history_sidebar_hash(self, fetch):
105105
def test_history_sidebar(self):
106106
"""Validate the history sidebar view."""
107107
self.client.get("/json_view/")
108-
store_id = list(DebugToolbar._store.keys())[0]
108+
store_id = list(store.all())[0][0]
109109
data = {
110110
"store_id": store_id,
111111
"hash": HistoryStoreForm.make_hash({"store_id": store_id}),

tests/test_integration.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from debug_toolbar.middleware import DebugToolbarMiddleware, show_toolbar
1616
from debug_toolbar.panels import Panel
17+
from debug_toolbar.store import store
1718
from debug_toolbar.toolbar import DebugToolbar
1819

1920
from .base import BaseTestCase, IntegrationTestCase
@@ -156,15 +157,15 @@ def get_response(request):
156157

157158
def test_middleware_render_toolbar_json(self):
158159
"""Verify the toolbar is rendered and data is stored for a json request."""
159-
self.assertEqual(len(DebugToolbar._store), 0)
160+
self.assertEqual(len(store.all()), 0)
160161

161162
data = {"foo": "bar"}
162163
response = self.client.get("/json_view/", data, content_type="application/json")
163164
self.assertEqual(response.status_code, 200)
164165
self.assertEqual(response.content.decode("utf-8"), '{"foo": "bar"}')
165166
# Check the history panel's stats to verify the toolbar rendered properly.
166-
self.assertEqual(len(DebugToolbar._store), 1)
167-
toolbar = list(DebugToolbar._store.values())[0]
167+
self.assertEqual(len(store.all()), 1)
168+
toolbar = list(store.all())[0][1]
168169
self.assertEqual(
169170
toolbar.get_panel_by_id("HistoryPanel").get_stats()["data"],
170171
{"foo": ["bar"]},
@@ -427,6 +428,8 @@ def test_rerender_on_history_switch(self):
427428

428429
@override_settings(DEBUG_TOOLBAR_CONFIG={"RESULTS_CACHE_SIZE": 0})
429430
def test_expired_store(self):
431+
original_value = store.config["RESULTS_CACHE_SIZE"]
432+
store.config["RESULTS_CACHE_SIZE"] = 0
430433
self.get("/regular/basic/")
431434
version_panel = self.selenium.find_element_by_id("VersionsPanel")
432435

@@ -438,6 +441,7 @@ def test_expired_store(self):
438441
lambda selenium: version_panel.find_element_by_tag_name("p")
439442
)
440443
self.assertIn("Data for this panel isn't available anymore.", error.text)
444+
store.config["RESULTS_CACHE_SIZE"] = original_value
441445

442446
@override_settings(
443447
TEMPLATES=[

0 commit comments

Comments
 (0)