Skip to content

Commit f48039e

Browse files
committed
Move the logic to load panels inside the DebugToolbar class.
This has the additional advantage of eliminating a side-effect that happened at import time unnecessarily. It justified refactoring the way we handle settings and defaults.
1 parent c1d50fc commit f48039e

File tree

9 files changed

+78
-69
lines changed

9 files changed

+78
-69
lines changed

debug_toolbar/middleware.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from django.utils.encoding import force_text
1313

1414
from debug_toolbar.toolbar import DebugToolbar
15-
from debug_toolbar.utils.settings import CONFIG
15+
from debug_toolbar.utils import settings as dt_settings
1616

1717
_HTML_TYPES = ('text/html', 'application/xhtml+xml')
1818
# Handles python threading module bug - http://bugs.python.org/issue14308
@@ -52,10 +52,10 @@ class DebugToolbarMiddleware(object):
5252

5353
def __init__(self):
5454
# The method to call to decide to show the toolbar
55-
self.show_toolbar = CONFIG['SHOW_TOOLBAR_CALLBACK'] or show_toolbar
55+
self.show_toolbar = dt_settings.CONFIG['SHOW_TOOLBAR_CALLBACK'] or show_toolbar
5656

5757
# The tag to attach the toolbar to
58-
self.tag = '</%s>' % CONFIG['TAG']
58+
self.tag = '</%s>' % dt_settings.CONFIG['TAG']
5959

6060
def process_request(self, request):
6161
__traceback_hide__ = True # noqa

debug_toolbar/models.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from django.core.urlresolvers import reverse, NoReverseMatch
66
from django.utils.importlib import import_module
77

8-
from debug_toolbar.toolbar import load_panel_classes
98
from debug_toolbar.middleware import DebugToolbarMiddleware
109

1110

@@ -59,7 +58,3 @@ def patch_root_urlconf():
5958
patch_internal_ips()
6059
patch_middleware_classes()
6160
patch_root_urlconf()
62-
63-
64-
if is_toolbar_middleware_installed():
65-
load_panel_classes()

debug_toolbar/panels/cache.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from debug_toolbar.panels import DebugPanel
1717
from debug_toolbar.utils import (tidy_stacktrace, render_stacktrace,
1818
get_template_info, get_stack)
19-
from debug_toolbar.utils.settings import CONFIG
19+
from debug_toolbar.utils import settings as dt_settings
2020

2121

2222
cache_called = Signal(providing_args=[
@@ -29,7 +29,7 @@ def wrapped(self, *args, **kwargs):
2929
value = method(self, *args, **kwargs)
3030
t = time.time() - t
3131

32-
if CONFIG['ENABLE_STACKTRACES']:
32+
if dt_settings.CONFIG['ENABLE_STACKTRACES']:
3333
stacktrace = tidy_stacktrace(reversed(get_stack()))
3434
else:
3535
stacktrace = []

debug_toolbar/panels/signals.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
connection_created = None
1717

1818
from debug_toolbar.panels import DebugPanel
19-
from debug_toolbar.utils.settings import CONFIG
19+
from debug_toolbar.utils import settings as dt_settings
2020

2121

2222
class SignalDebugPanel(DebugPanel):
@@ -63,7 +63,7 @@ def title(self):
6363
@property
6464
def signals(self):
6565
signals = self.SIGNALS.copy()
66-
for signal in CONFIG['EXTRA_SIGNALS']:
66+
for signal in dt_settings.CONFIG['EXTRA_SIGNALS']:
6767
mod_path, signal_name = signal.rsplit('.', 1)
6868
signals_mod = import_module(mod_path)
6969
signals[signal_name] = getattr(signals_mod, signal_name)

debug_toolbar/panels/template.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from debug_toolbar.panels import DebugPanel
1717
from debug_toolbar.utils.tracking.db import recording, SQLQueryTriggered
18-
from debug_toolbar.utils.settings import CONFIG
18+
from debug_toolbar.utils import settings as dt_settings
1919

2020
# Code taken and adapted from Simon Willison and Django Snippets:
2121
# http://www.djangosnippets.org/snippets/766/
@@ -140,7 +140,7 @@ def process_response(self, request, response):
140140
template.origin_name = 'No origin'
141141
info['template'] = template
142142
# Clean up context for better readability
143-
if CONFIG['SHOW_TEMPLATE_CONTEXT']:
143+
if dt_settings.CONFIG['SHOW_TEMPLATE_CONTEXT']:
144144
context_list = template_data.get('context', [])
145145
info['context'] = '\n'.join(context_list)
146146
template_context.append(info)

debug_toolbar/toolbar.py

Lines changed: 35 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
from __future__ import unicode_literals
66

77
from django.conf import settings
8+
from django.core.exceptions import ImproperlyConfigured
89
from django.template.loader import render_to_string
910
from django.utils.datastructures import SortedDict
1011
from django.utils.importlib import import_module
1112

12-
from debug_toolbar.utils.settings import CONFIG
13+
from debug_toolbar.utils import settings as dt_settings
1314

1415

1516
class DebugToolbar(object):
@@ -19,7 +20,7 @@ def __init__(self, request):
1920
self._panels = SortedDict()
2021
base_url = self.request.META.get('SCRIPT_NAME', '')
2122
self.config = {}
22-
self.config.update(CONFIG)
23+
self.config.update(dt_settings.CONFIG)
2324
self.template_context = {
2425
'BASE_URL': base_url, # for backwards compatibility
2526
'STATIC_URL': settings.STATIC_URL,
@@ -40,8 +41,7 @@ def load_panels(self):
4041
"""
4142
Populate debug panels
4243
"""
43-
global panel_classes
44-
for panel_class in panel_classes:
44+
for panel_class in self.get_panel_classes():
4545
panel_instance = panel_class(self, context=self.template_context)
4646
self._panels[panel_class] = panel_instance
4747

@@ -65,7 +65,7 @@ def store(self):
6565
cls = type(self)
6666
cls._counter += 1
6767
cls._storage[cls._counter] = self
68-
for _ in range(len(cls._storage) - CONFIG['RESULTS_CACHE_SIZE']):
68+
for _ in range(len(cls._storage) - dt_settings.CONFIG['RESULTS_CACHE_SIZE']):
6969
# When we drop support for Python 2.6 and switch to
7070
# collections.OrderedDict, use popitem(last=False).
7171
del cls._storage[cls._storage.keyOrder[0]]
@@ -75,45 +75,35 @@ def store(self):
7575
def fetch(cls, storage_id):
7676
return cls._storage.get(storage_id)
7777

78+
# Manually implement class-level caching of the list of panels because
79+
# it's more obvious than going through an abstraction.
7880

81+
_panel_classes = None
7982

80-
panel_classes = []
81-
82-
83-
def load_panel_classes():
84-
from django.conf import settings
85-
from django.core.exceptions import ImproperlyConfigured
86-
87-
# Check if settings has a DEBUG_TOOLBAR_PANELS, otherwise use default
88-
panels = getattr(settings, 'DEBUG_TOOLBAR_PANELS', (
89-
'debug_toolbar.panels.version.VersionDebugPanel',
90-
'debug_toolbar.panels.timer.TimerDebugPanel',
91-
'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
92-
'debug_toolbar.panels.headers.HeaderDebugPanel',
93-
'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
94-
'debug_toolbar.panels.sql.SQLDebugPanel',
95-
'debug_toolbar.panels.template.TemplateDebugPanel',
96-
'debug_toolbar.panels.cache.CacheDebugPanel',
97-
'debug_toolbar.panels.signals.SignalDebugPanel',
98-
'debug_toolbar.panels.logger.LoggingPanel',
99-
))
100-
for panel_path in panels:
101-
try:
102-
dot = panel_path.rindex('.')
103-
except ValueError:
104-
raise ImproperlyConfigured(
105-
"%s isn't a debug panel module" % panel_path)
106-
panel_module, panel_classname = panel_path[:dot], panel_path[dot + 1:]
107-
try:
108-
mod = import_module(panel_module)
109-
except ImportError as e:
110-
raise ImproperlyConfigured(
111-
'Error importing debug panel %s: "%s"' %
112-
(panel_module, e))
113-
try:
114-
panel_class = getattr(mod, panel_classname)
115-
except AttributeError:
116-
raise ImproperlyConfigured(
117-
'Toolbar Panel module "%s" does not define a "%s" class' %
118-
(panel_module, panel_classname))
119-
panel_classes.append(panel_class)
83+
@classmethod
84+
def get_panel_classes(cls):
85+
if cls._panel_classes is None:
86+
# Load panels in a temporary variable for thread safety.
87+
panel_classes = []
88+
for panel_path in dt_settings.PANELS:
89+
# This logic could be replaced with import_by_path in Django 1.6.
90+
try:
91+
panel_module, panel_classname = panel_path.rsplit('.', 1)
92+
except ValueError:
93+
raise ImproperlyConfigured(
94+
"%s isn't a debug panel module" % panel_path)
95+
try:
96+
mod = import_module(panel_module)
97+
except ImportError as e:
98+
raise ImproperlyConfigured(
99+
'Error importing debug panel %s: "%s"' %
100+
(panel_module, e))
101+
try:
102+
panel_class = getattr(mod, panel_classname)
103+
except AttributeError:
104+
raise ImproperlyConfigured(
105+
'Toolbar Panel module "%s" does not define a "%s" class' %
106+
(panel_module, panel_classname))
107+
panel_classes.append(panel_class)
108+
cls._panel_classes = panel_classes
109+
return cls._panel_classes

debug_toolbar/utils/settings.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
from django.utils import six
55

66

7+
# Always import this module as follows:
8+
# from debug_toolbar.utils import settings [as dt_settings]
9+
10+
# Don't import directly CONFIG or PANELs, or you will miss changes performed
11+
# with override_settings in tests.
12+
13+
714
CONFIG_DEFAULTS = {
815
'INTERCEPT_REDIRECTS': False,
916
'SHOW_TOOLBAR_CALLBACK': None,
@@ -27,3 +34,20 @@
2734
CONFIG = {}
2835
CONFIG.update(CONFIG_DEFAULTS)
2936
CONFIG.update(getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}))
37+
38+
39+
PANELS_DEFAULTS = (
40+
'debug_toolbar.panels.version.VersionDebugPanel',
41+
'debug_toolbar.panels.timer.TimerDebugPanel',
42+
'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
43+
'debug_toolbar.panels.headers.HeaderDebugPanel',
44+
'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
45+
'debug_toolbar.panels.sql.SQLDebugPanel',
46+
'debug_toolbar.panels.template.TemplateDebugPanel',
47+
'debug_toolbar.panels.cache.CacheDebugPanel',
48+
'debug_toolbar.panels.signals.SignalDebugPanel',
49+
'debug_toolbar.panels.logger.LoggingPanel',
50+
)
51+
52+
53+
PANELS = getattr(settings, 'DEBUG_TOOLBAR_PANELS', PANELS_DEFAULTS)

debug_toolbar/utils/tracking/db.py

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

1313
from debug_toolbar.utils import tidy_stacktrace, get_template_info, get_stack
14-
from debug_toolbar.utils.settings import CONFIG
14+
from debug_toolbar.utils import settings as dt_settings
1515

1616

1717
class SQLQueryTriggered(Exception):
@@ -92,7 +92,7 @@ def execute(self, sql, params=()):
9292
finally:
9393
stop_time = time()
9494
duration = (stop_time - start_time) * 1000
95-
if CONFIG['ENABLE_STACKTRACES']:
95+
if dt_settings.CONFIG['ENABLE_STACKTRACES']:
9696
stacktrace = tidy_stacktrace(reversed(get_stack()))
9797
else:
9898
stacktrace = []
@@ -135,7 +135,7 @@ def execute(self, sql, params=()):
135135
'stacktrace': stacktrace,
136136
'start_time': start_time,
137137
'stop_time': stop_time,
138-
'is_slow': duration > CONFIG['SQL_WARNING_THRESHOLD'],
138+
'is_slow': duration > dt_settings.CONFIG['SQL_WARNING_THRESHOLD'],
139139
'is_select': sql.lower().strip().startswith('select'),
140140
'template_info': template_info,
141141
}

tests/__init__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Refresh the debug toolbar's configuration when overriding settings.
22

3-
from debug_toolbar.utils.settings import CONFIG, CONFIG_DEFAULTS
4-
from debug_toolbar.toolbar import load_panel_classes, panel_classes # noqa
3+
from debug_toolbar.toolbar import DebugToolbar
4+
from debug_toolbar.utils import settings as dt_settings
55

66
from django.dispatch import receiver
77
from django.test.signals import setting_changed
@@ -10,13 +10,13 @@
1010
@receiver(setting_changed)
1111
def update_toolbar_config(**kwargs):
1212
if kwargs['setting'] == 'DEBUG_TOOLBAR_CONFIG':
13-
CONFIG.update(CONFIG_DEFAULTS)
14-
CONFIG.update(kwargs['value'] or {})
13+
dt_settings.CONFIG = {}
14+
dt_settings.CONFIG.update(dt_settings.CONFIG_DEFAULTS)
15+
dt_settings.CONFIG.update(kwargs['value'] or {})
1516

1617

1718
@receiver(setting_changed)
1819
def update_toolbar_panels(**kwargs):
1920
if kwargs['setting'] == 'DEBUG_TOOLBAR_PANELS':
20-
global panel_classes
21-
panel_classes = [] # noqa
22-
load_panel_classes()
21+
dt_settings.PANELS = kwargs['value'] or dt_settings.PANELS_DEFAULTS
22+
DebugToolbar._panel_classes = None

0 commit comments

Comments
 (0)