Permalink
Browse files

Adding a signals panel to display list of signals and their providing…

… arguments

and receivers.  Thanks Alex Gaynor!

Signed-off-by: Rob Hudson <rob@cogit8.org>
  • Loading branch information...
1 parent 08b6a97 commit 1956ee540c75f9d4226f0352df5b06aae5c02703 @alex alex committed with robhudson May 28, 2009
View
@@ -15,6 +15,7 @@ Currently, the following panels have been written and are working:
- GET/POST/cookie/session variable display
- Templates and context used, and their template paths
- SQL queries including time to execute and links to EXPLAIN each query
+- List of signals, their args and receivers
- Logging output via Python's built-in logging module
If you have ideas for other panels please let us know.
@@ -50,7 +51,7 @@ Installation
#. Add `debug_toolbar` to your `INSTALLED_APPS` setting so Django can find the
template files associated with the Debug Toolbar.
-
+
Alternatively, add the path to the debug toolbar templates
(``'path/to/debug_toolbar/templates'`` to your ``TEMPLATE_DIRS`` setting.)
@@ -72,6 +73,7 @@ The debug toolbar has two settings that can be set in `settings.py`:
'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
'debug_toolbar.panels.template.TemplateDebugPanel',
'debug_toolbar.panels.sql.SQLDebugPanel',
+ 'debug_toolbar.panels.signals.SignalDebugPanel',
'debug_toolbar.panels.logger.LoggingPanel',
)
@@ -96,6 +98,9 @@ The debug toolbar has two settings that can be set in `settings.py`:
provide your own method for displaying the toolbar which contains your
custom logic. This method should return True or False.
+ * `EXTRA_SIGNALS`: An array of custom signals that might be in your project,
+ defined as the python path to the signal.
+
Example configuration::
def custom_show_toolbar(request):
@@ -104,6 +109,7 @@ The debug toolbar has two settings that can be set in `settings.py`:
DEBUG_TOOLBAR_CONFIG = {
'INTERCEPT_REDIRECTS': False,
'SHOW_TOOLBAR_CALLBACK': custom_show_toolbar,
+ 'EXTRA_SIGNALS': ['myproject.signals.MySignal'],
}
TODOs and BUGS
@@ -0,0 +1,73 @@
+import sys
+
+from django.conf import settings
+from django.core.signals import request_started, request_finished, \
+ got_request_exception
+from django.db.backends.signals import connection_created
+from django.db.models.signals import class_prepared, pre_init, post_init, \
+ pre_save, post_save, pre_delete, post_delete, post_syncdb
+from django.dispatch.dispatcher import WEAKREF_TYPES
+from django.template.loader import render_to_string
+
+from debug_toolbar.panels import DebugPanel
+
+class SignalDebugPanel(DebugPanel):
+ name = "Signals"
+ has_content = True
+
+ SIGNALS = {
+ 'request_started': request_started,
+ 'request_finished': request_finished,
+ 'got_request_exception': got_request_exception,
+ 'connection_created': connection_created,
+ 'class_prepared': class_prepared,
+ 'pre_init': pre_init,
+ 'post_init': post_init,
+ 'pre_save': pre_save,
+ 'post_save': post_save,
+ 'pre_delete': pre_delete,
+ 'post_delete': post_delete,
+ 'post_syncdb': post_syncdb,
+ }
+
+ def title(self):
+ return "Signals"
+
+ def url(self):
+ return ''
+
+ def signals(self):
+ signals = self.SIGNALS.copy()
+ if hasattr(settings, 'DEBUG_TOOLBAR_CONFIG'):
+ extra_signals = settings.DEBUG_TOOLBAR_CONFIG.get('EXTRA_SIGNALS', [])
+ else:
+ extra_signals = []
+ for signal in extra_signals:
+ parts = signal.split('.')
+ path = '.'.join(parts[:-1])
+ __import__(path)
+ signals[parts[-1]] = getattr(sys.modules[path], parts[-1])
+ return signals
+ signals = property(signals)
+
+ def content(self):
+ signals = []
+ keys = self.signals.keys()
+ keys.sort()
+ for name in keys:
+ signal = self.signals[name]
+ receivers = []
+ for (receiverkey, r_senderkey), receiver in signal.receivers:
+ if isinstance(receiver, WEAKREF_TYPES):
+ receiver = receiver()
+ if receiver is None:
+ continue
+ if getattr(receiver, 'im_self', None) is not None:
+ text = "method %s on %s object" % (receiver.__name__, receiver.im_self.__class__.__name__)
+ elif getattr(receiver, 'im_class', None) is not None:
+ text = "method %s on %s" % (receiver.__name__, receiver.im_class.__name__)
+ else:
+ text = "function %s" % receiver.__name__
+ receivers.append(text)
+ signals.append((name, signal, receivers))
+ return render_to_string('debug_toolbar/panels/signals.html', {'signals': signals})
@@ -98,7 +98,7 @@ def content(self):
return render_to_string('debug_toolbar/panels/sql.html', context)
def reformat_sql(sql):
- sql = sql.replace('`,`', '`, `')
+ sql = sql.replace(',', ', ')
sql = sql.replace('SELECT ', 'SELECT\n\t')
sql = sql.replace(' FROM ', '\nFROM\n\t')
sql = sql.replace(' WHERE ', '\nWHERE\n\t')
@@ -0,0 +1,19 @@
+<h3>Signals</h3>
+<table>
+ <thead>
+ <tr>
+ <th>Signal</th>
+ <th>Providing Args</th>
+ <th>Receivers</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for name, signal, receivers in signals %}
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
+ <td>{{ name|escape }}</td>
+ <td>{{ signal.providing_args|join:", " }}</td>
+ <td>{{ receivers|join:", " }}</td>
+ </tr>
+ {% endfor %}
+ </tbody>
+</table>
@@ -21,6 +21,7 @@ def __init__(self, request):
'debug_toolbar.panels.sql.SQLDebugPanel',
'debug_toolbar.panels.template.TemplateDebugPanel',
#'debug_toolbar.panels.cache.CacheDebugPanel',
+ 'debug_toolbar.panels.signals.SignalDebugPanel',
'debug_toolbar.panels.logger.LoggingPanel',
)
self.load_panels()

0 comments on commit 1956ee5

Please sign in to comment.