Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Switch to Store.request_ids and remove serialization force_str.
If the serialization logic begins throwing exceptions we can consider
subclassing the encoder class and using force_str on the object itself.
  • Loading branch information
tim-schilling committed Jun 17, 2023
commit 99f4473c3eb36fb5882a5dbde84cd4a5a90d3da8
47 changes: 20 additions & 27 deletions debug_toolbar/store.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
import contextlib
import json
from collections import defaultdict, deque
from typing import Any, Dict, Iterable

from django.core.serializers.json import DjangoJSONEncoder
from django.utils.encoding import force_str
from django.utils.module_loading import import_string

from debug_toolbar import settings as dt_settings


class DebugToolbarJSONEncoder(DjangoJSONEncoder):
def default(self, o: Any) -> Any:
try:
return super().default(o)
except TypeError:
return force_str(o)


def serialize(data: Any) -> str:
return json.dumps(data, cls=DebugToolbarJSONEncoder)
# If this starts throwing an exceptions, consider
# Subclassing DjangoJSONEncoder and using force_str to
# make it JSON serializable.
return json.dumps(data, cls=DjangoJSONEncoder)


def deserialize(data: str) -> Any:
Expand All @@ -29,8 +24,8 @@ class BaseStore:
_config = dt_settings.get_config().copy()

@classmethod
def ids(cls) -> Iterable:
"""The stored ids"""
def request_ids(cls) -> Iterable:
"""The stored request ids"""
raise NotImplementedError

@classmethod
Expand Down Expand Up @@ -68,43 +63,41 @@ class MemoryStore(BaseStore):
# ids is the collection of storage ids that have been used.
# Use a dequeue to support O(1) appends and pops
# from either direction.
_ids: deque = deque()
_request_ids: deque = deque()
_request_store: Dict[str, Dict] = defaultdict(dict)

@classmethod
def ids(cls) -> Iterable:
"""The stored ids"""
return cls._ids
def request_ids(cls) -> Iterable:
"""The stored request ids"""
return cls._request_ids

@classmethod
def exists(cls, request_id: str) -> bool:
"""Does the given request_id exist in the request store"""
return request_id in cls._ids
return request_id in cls._request_ids

@classmethod
def set(cls, request_id: str):
"""Set a request_id in the request store"""
if request_id not in cls._ids:
cls._ids.append(request_id)
for _ in range(len(cls._ids) - cls._config["RESULTS_CACHE_SIZE"]):
removed_id = cls._ids.popleft()
if request_id not in cls._request_ids:
cls._request_ids.append(request_id)
for _ in range(len(cls._request_ids) - cls._config["RESULTS_CACHE_SIZE"]):
removed_id = cls._request_ids.popleft()
cls._request_store.pop(removed_id, None)

@classmethod
def clear(cls):
"""Remove all requests from the request store"""
cls._ids.clear()
cls._request_ids.clear()
cls._request_store.clear()

@classmethod
def delete(cls, request_id: str):
"""Delete the stored request for the given request_id"""
cls._request_store.pop(request_id, None)
try:
cls._ids.remove(request_id)
except ValueError:
# The request_id doesn't exist in the collection of ids.
pass
# Suppress when request_id doesn't exist in the collection of ids.
with contextlib.suppress(ValueError):
cls._request_ids.remove(request_id)

@classmethod
def save_panel(cls, request_id: str, panel_id: str, data: Any = None):
Expand Down
26 changes: 7 additions & 19 deletions tests/test_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,6 @@ def test_serialize(self):
'{"hello": {"foo": "bar"}}',
)

def test_serialize_force_str(self):
class Foo:
spam = "bar"

def __str__(self):
return f"Foo spam={self.spam}"

self.assertEqual(
store.serialize({"hello": Foo()}),
'{"hello": "Foo spam=bar"}',
)

def test_deserialize(self):
self.assertEqual(
store.deserialize('{"hello": {"foo": "bar"}}'),
Expand All @@ -38,7 +26,7 @@ def test_methods_are_not_implemented(self):
]
self.assertEqual(len(methods), 7)
with self.assertRaises(NotImplementedError):
store.BaseStore.ids()
store.BaseStore.request_ids()
with self.assertRaises(NotImplementedError):
store.BaseStore.exists("")
with self.assertRaises(NotImplementedError):
Expand All @@ -64,7 +52,7 @@ def tearDown(self) -> None:
def test_ids(self):
self.store.set("foo")
self.store.set("bar")
self.assertEqual(list(self.store.ids()), ["foo", "bar"])
self.assertEqual(list(self.store.request_ids()), ["foo", "bar"])

def test_exists(self):
self.assertFalse(self.store.exists("missing"))
Expand All @@ -73,14 +61,14 @@ def test_exists(self):

def test_set(self):
self.store.set("foo")
self.assertEqual(list(self.store.ids()), ["foo"])
self.assertEqual(list(self.store.request_ids()), ["foo"])

def test_set_max_size(self):
existing = self.store._config["RESULTS_CACHE_SIZE"]
self.store._config["RESULTS_CACHE_SIZE"] = 1
self.store.save_panel("foo", "foo.panel", "foo.value")
self.store.save_panel("bar", "bar.panel", {"a": 1})
self.assertEqual(list(self.store.ids()), ["bar"])
self.assertEqual(list(self.store.request_ids()), ["bar"])
self.assertEqual(self.store.panel("foo", "foo.panel"), {})
self.assertEqual(self.store.panel("bar", "bar.panel"), {"a": 1})
# Restore the existing config setting since this config is shared.
Expand All @@ -89,20 +77,20 @@ def test_set_max_size(self):
def test_clear(self):
self.store.save_panel("bar", "bar.panel", {"a": 1})
self.store.clear()
self.assertEqual(list(self.store.ids()), [])
self.assertEqual(list(self.store.request_ids()), [])
self.assertEqual(self.store.panel("bar", "bar.panel"), {})

def test_delete(self):
self.store.save_panel("bar", "bar.panel", {"a": 1})
self.store.delete("bar")
self.assertEqual(list(self.store.ids()), [])
self.assertEqual(list(self.store.request_ids()), [])
self.assertEqual(self.store.panel("bar", "bar.panel"), {})
# Make sure it doesn't error
self.store.delete("bar")

def test_save_panel(self):
self.store.save_panel("bar", "bar.panel", {"a": 1})
self.assertEqual(list(self.store.ids()), ["bar"])
self.assertEqual(list(self.store.request_ids()), ["bar"])
self.assertEqual(self.store.panel("bar", "bar.panel"), {"a": 1})

def test_panel(self):
Expand Down