Skip to content

Commit 216215b

Browse files
committed
Replace path-based stack frame exclusion
Prior to this commit, the HIDE_IN_STACKTRACES setting was implemented by importing the modules listed in the setting and recording their file system paths. Then tidy_stacktrace() and _StackRecorder.get_stack_trace() would look up the file system path for each frame's code object and compare that path against the paths for the excluded modules to see if it matched. If so, the frame would be excluded. This was inefficient since it used a file system access, os.path.realpath(), for each frame (although the _StackRecorder implementation included some caching to reduce the cost). It also would not work correctly for namespace packages since they can have multiple file system hierarchies. Replace with a new implementation that instead retrieves the __name__ variable from the frame's f_globals attribute and matches that module name against the list of excluded modules directly.
1 parent bcc3c46 commit 216215b

File tree

1 file changed

+19
-42
lines changed

1 file changed

+19
-42
lines changed

debug_toolbar/utils.py

Lines changed: 19 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33
import os.path
44
import sys
55
import warnings
6-
from importlib import import_module
76
from pprint import pformat
87

98
from asgiref.local import Local
10-
from django.core.exceptions import ImproperlyConfigured
119
from django.template import Node
1210
from django.utils.html import format_html
1311
from django.utils.safestring import mark_safe
@@ -23,26 +21,16 @@
2321
_local_data = Local()
2422

2523

26-
def get_module_path(module_name):
27-
try:
28-
module = import_module(module_name)
29-
except ImportError as e:
30-
raise ImproperlyConfigured(f"Error importing HIDE_IN_STACKTRACES: {e}")
31-
else:
32-
source_path = inspect.getsourcefile(module)
33-
if source_path.endswith("__init__.py"):
34-
source_path = os.path.dirname(source_path)
35-
return os.path.realpath(source_path)
36-
37-
38-
hidden_paths = [
39-
get_module_path(module_name)
40-
for module_name in dt_settings.get_config()["HIDE_IN_STACKTRACES"]
41-
]
42-
43-
44-
def omit_path(path):
45-
return any(path.startswith(hidden_path) for hidden_path in hidden_paths)
24+
def _is_excluded_frame(frame, excluded_modules):
25+
if not excluded_modules:
26+
return False
27+
name = frame.f_globals.get("__name__")
28+
if not isinstance(name, str):
29+
return False
30+
return any(
31+
name == excluded_module or name.startswith(excluded_module + ".")
32+
for excluded_module in excluded_modules
33+
)
4634

4735

4836
def _stack_trace_deprecation_warning():
@@ -65,8 +53,9 @@ def tidy_stacktrace(stack):
6553
_stack_trace_deprecation_warning()
6654

6755
trace = []
56+
excluded_modules = dt_settings.get_config()["HIDE_IN_STACKTRACES"]
6857
for frame, path, line_no, func_name, text in (f[:5] for f in stack):
69-
if omit_path(os.path.realpath(path)):
58+
if _is_excluded_frame(frame, excluded_modules):
7059
continue
7160
text = "".join(text).strip() if text else ""
7261
frame_locals = (
@@ -267,10 +256,8 @@ def _stack_frames(depth=1):
267256

268257

269258
class _StackTraceRecorder:
270-
def __init__(self, excluded_paths):
271-
self.excluded_paths = excluded_paths
259+
def __init__(self):
272260
self.filename_cache = {}
273-
self.is_excluded_cache = {}
274261

275262
def get_source_file(self, frame):
276263
frame_filename = frame.f_code.co_filename
@@ -291,25 +278,14 @@ def get_source_file(self, frame):
291278

292279
return value
293280

294-
def is_excluded_path(self, path):
295-
excluded = self.is_excluded_cache.get(path)
296-
if excluded is None:
297-
resolved_path = os.path.realpath(path)
298-
excluded = any(
299-
resolved_path.startswith(excluded_path)
300-
for excluded_path in self.excluded_paths
301-
)
302-
self.is_excluded_cache[path] = excluded
303-
return excluded
304-
305-
def get_stack_trace(self, include_locals=False, depth=1):
281+
def get_stack_trace(self, excluded_modules=None, include_locals=False, depth=1):
306282
trace = []
307283
for frame in _stack_frames(depth=depth + 1):
308-
filename, is_source = self.get_source_file(frame)
309-
310-
if self.is_excluded_path(filename):
284+
if _is_excluded_frame(frame, excluded_modules):
311285
continue
312286

287+
filename, is_source = self.get_source_file(frame)
288+
313289
line_no = frame.f_lineno
314290
func_name = frame.f_code.co_name
315291

@@ -334,9 +310,10 @@ def get_stack_trace(depth=1):
334310
if config["ENABLE_STACKTRACES"]:
335311
stack_trace_recorder = getattr(_local_data, "stack_trace_recorder", None)
336312
if stack_trace_recorder is None:
337-
stack_trace_recorder = _StackTraceRecorder(hidden_paths)
313+
stack_trace_recorder = _StackTraceRecorder()
338314
_local_data.stack_trace_recorder = stack_trace_recorder
339315
return stack_trace_recorder.get_stack_trace(
316+
excluded_modules=config["HIDE_IN_STACKTRACES"],
340317
include_locals=config["ENABLE_STACKTRACES_LOCALS"],
341318
depth=depth,
342319
)

0 commit comments

Comments
 (0)