Skip to content

Commit cd4c748

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 cd4c748

File tree

1 file changed

+20
-42
lines changed

1 file changed

+20
-42
lines changed

debug_toolbar/utils.py

Lines changed: 20 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,17 @@
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+
frame_module = frame.f_globals.get("__name__")
28+
if not isinstance(frame_module, str):
29+
return False
30+
return any(
31+
frame_module == excluded_module
32+
or frame_module.startswith(excluded_module + ".")
33+
for excluded_module in excluded_modules
34+
)
4635

4736

4837
def _stack_trace_deprecation_warning():
@@ -65,8 +54,9 @@ def tidy_stacktrace(stack):
6554
_stack_trace_deprecation_warning()
6655

6756
trace = []
57+
excluded_modules = dt_settings.get_config()["HIDE_IN_STACKTRACES"]
6858
for frame, path, line_no, func_name, text in (f[:5] for f in stack):
69-
if omit_path(os.path.realpath(path)):
59+
if _is_excluded_frame(frame, excluded_modules):
7060
continue
7161
text = "".join(text).strip() if text else ""
7262
frame_locals = (
@@ -267,10 +257,8 @@ def _stack_frames(depth=1):
267257

268258

269259
class _StackTraceRecorder:
270-
def __init__(self, excluded_paths):
271-
self.excluded_paths = excluded_paths
260+
def __init__(self):
272261
self.filename_cache = {}
273-
self.is_excluded_cache = {}
274262

275263
def get_source_file(self, frame):
276264
frame_filename = frame.f_code.co_filename
@@ -291,25 +279,14 @@ def get_source_file(self, frame):
291279

292280
return value
293281

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):
282+
def get_stack_trace(self, excluded_modules=None, include_locals=False, depth=1):
306283
trace = []
307284
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):
285+
if _is_excluded_frame(frame, excluded_modules):
311286
continue
312287

288+
filename, is_source = self.get_source_file(frame)
289+
313290
line_no = frame.f_lineno
314291
func_name = frame.f_code.co_name
315292

@@ -334,9 +311,10 @@ def get_stack_trace(depth=1):
334311
if config["ENABLE_STACKTRACES"]:
335312
stack_trace_recorder = getattr(_local_data, "stack_trace_recorder", None)
336313
if stack_trace_recorder is None:
337-
stack_trace_recorder = _StackTraceRecorder(hidden_paths)
314+
stack_trace_recorder = _StackTraceRecorder()
338315
_local_data.stack_trace_recorder = stack_trace_recorder
339316
return stack_trace_recorder.get_stack_trace(
317+
excluded_modules=config["HIDE_IN_STACKTRACES"],
340318
include_locals=config["ENABLE_STACKTRACES_LOCALS"],
341319
depth=depth,
342320
)

0 commit comments

Comments
 (0)