aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debug_toolbar/panels/__init__.py11
-rw-r--r--debug_toolbar/panels/profiling.py6
-rw-r--r--debug_toolbar/panels/redirects.py5
-rw-r--r--debug_toolbar/panels/request.py8
-rw-r--r--debug_toolbar/panels/sql/panel.py21
-rw-r--r--debug_toolbar/panels/sql/tracking.py10
-rw-r--r--debug_toolbar/panels/sql/views.py8
-rw-r--r--debug_toolbar/panels/templates/panel.py6
-rw-r--r--debug_toolbar/settings.py27
-rw-r--r--debug_toolbar/static/debug_toolbar/js/toolbar.js2
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/sql.html2
-rw-r--r--docs/changes.rst26
-rw-r--r--docs/configuration.rst21
-rw-r--r--docs/panels.rst2
14 files changed, 114 insertions, 41 deletions
diff --git a/debug_toolbar/panels/__init__.py b/debug_toolbar/panels/__init__.py
index 178ea6f..74b0734 100644
--- a/debug_toolbar/panels/__init__.py
+++ b/debug_toolbar/panels/__init__.py
@@ -4,6 +4,9 @@ import warnings
from django.template.loader import render_to_string
+from debug_toolbar import settings as dt_settings
+from debug_toolbar.utils import get_name_from_obj
+
class Panel(object):
"""
@@ -20,7 +23,13 @@ class Panel(object):
@property
def enabled(self):
- return self.toolbar.request.COOKIES.get('djdt' + self.panel_id, 'on') == 'on'
+ # Check to see if settings has a default value for it
+ if get_name_from_obj(self) in dt_settings.CONFIG['DISABLE_PANELS']:
+ default = 'off'
+ else:
+ default = 'on'
+ # The user's cookies should override the default value
+ return self.toolbar.request.COOKIES.get('djdt' + self.panel_id, default) == 'on'
# Titles and content
diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py
index 7399c16..9020799 100644
--- a/debug_toolbar/panels/profiling.py
+++ b/debug_toolbar/panels/profiling.py
@@ -3,6 +3,7 @@ from __future__ import absolute_import, division, unicode_literals
from django.utils.translation import ugettext_lazy as _
from django.utils.safestring import mark_safe
from debug_toolbar.panels import Panel
+from debug_toolbar import settings as dt_settings
import cProfile
from pstats import Stats
@@ -152,6 +153,9 @@ class ProfilingPanel(Panel):
root = FunctionCall(self.stats, self.stats.get_root_func(), depth=0)
func_list = []
- self.add_node(func_list, root, 10, root.stats[3] / 8)
+ self.add_node(func_list,
+ root,
+ dt_settings.CONFIG['PROFILER_MAX_DEPTH'],
+ root.stats[3] / 8)
self.record_stats({'func_list': func_list})
diff --git a/debug_toolbar/panels/redirects.py b/debug_toolbar/panels/redirects.py
index 8bd5aba..757c65c 100644
--- a/debug_toolbar/panels/redirects.py
+++ b/debug_toolbar/panels/redirects.py
@@ -12,11 +12,6 @@ class RedirectsPanel(Panel):
Panel that intercepts redirects and displays a page with debug info.
"""
- @property
- def enabled(self):
- default = 'on' if self.toolbar.config['INTERCEPT_REDIRECTS'] else 'off'
- return self.toolbar.request.COOKIES.get('djdt' + self.panel_id, default) == 'on'
-
has_content = False
nav_title = _("Intercept redirects")
diff --git a/debug_toolbar/panels/request.py b/debug_toolbar/panels/request.py
index b98ef22..b5caa52 100644
--- a/debug_toolbar/panels/request.py
+++ b/debug_toolbar/panels/request.py
@@ -17,6 +17,14 @@ class RequestPanel(Panel):
title = _("Request")
+ @property
+ def nav_subtitle(self):
+ """
+ Show abbreviated name of view function as subtitle
+ """
+ view_func = self.get_stats().get('view_func', '')
+ return view_func.rsplit('.', 1)[-1]
+
def process_response(self, request, response):
self.record_stats({
'get': [(k, request.GET.getlist(k)) for k in sorted(request.GET)],
diff --git a/debug_toolbar/panels/sql/panel.py b/debug_toolbar/panels/sql/panel.py
index f6ce954..5531964 100644
--- a/debug_toolbar/panels/sql/panel.py
+++ b/debug_toolbar/panels/sql/panel.py
@@ -15,8 +15,8 @@ from debug_toolbar.panels.sql.utils import reformat_sql, contrasting_color_gener
from debug_toolbar.panels.sql.tracking import wrap_cursor, unwrap_cursor
-def get_isolation_level_display(engine, level):
- if engine == 'psycopg2':
+def get_isolation_level_display(vendor, level):
+ if vendor == 'postgresql':
import psycopg2.extensions
choices = {
psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT: _("Autocommit"),
@@ -26,12 +26,12 @@ def get_isolation_level_display(engine, level):
psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE: _("Serializable"),
}
else:
- raise ValueError(engine)
+ raise ValueError(vendor)
return choices.get(level)
-def get_transaction_status_display(engine, level):
- if engine == 'psycopg2':
+def get_transaction_status_display(vendor, level):
+ if vendor == 'postgresql':
import psycopg2.extensions
choices = {
psycopg2.extensions.TRANSACTION_STATUS_IDLE: _("Idle"),
@@ -41,7 +41,7 @@ def get_transaction_status_display(engine, level):
psycopg2.extensions.TRANSACTION_STATUS_UNKNOWN: _("Unknown"),
}
else:
- raise ValueError(engine)
+ raise ValueError(vendor)
return choices.get(level)
@@ -67,11 +67,10 @@ class SQLPanel(Panel):
if not conn:
return
- engine = conn.__class__.__module__.split('.', 1)[0]
- if engine == 'psycopg2':
+ if conn.vendor == 'postgresql':
cur_status = conn.get_transaction_status()
else:
- raise ValueError(engine)
+ raise ValueError(conn.vendor)
last_status = self._transaction_status.get(alias)
self._transaction_status[alias] = cur_status
@@ -175,10 +174,10 @@ class SQLPanel(Panel):
query['alias'] = alias
if 'iso_level' in query:
- query['iso_level'] = get_isolation_level_display(query['engine'],
+ query['iso_level'] = get_isolation_level_display(query['vendor'],
query['iso_level'])
if 'trans_status' in query:
- query['trans_status'] = get_transaction_status_display(query['engine'],
+ query['trans_status'] = get_transaction_status_display(query['vendor'],
query['trans_status'])
query['form'] = SQLSelectForm(auto_id=None, initial=copy(query))
diff --git a/debug_toolbar/panels/sql/tracking.py b/debug_toolbar/panels/sql/tracking.py
index 68c77e2..b6a787d 100644
--- a/debug_toolbar/panels/sql/tracking.py
+++ b/debug_toolbar/panels/sql/tracking.py
@@ -131,14 +131,10 @@ class NormalCursorWrapper(object):
alias = getattr(self.db, 'alias', 'default')
conn = self.db.connection
- # HACK: avoid imports
- if conn:
- engine = conn.__class__.__module__.split('.', 1)[0]
- else:
- engine = 'unknown'
+ vendor = getattr(conn, 'vendor', 'unknown')
params = {
- 'engine': engine,
+ 'vendor': vendor,
'alias': alias,
'sql': self.db.ops.last_executed_query(
self.cursor, sql, self._quote_params(params)),
@@ -153,7 +149,7 @@ class NormalCursorWrapper(object):
'template_info': template_info,
}
- if engine == 'psycopg2':
+ if vendor == 'postgresql':
# If an erroneous query was ran on the connection, it might
# be in a state where checking isolation_level raises an
# exception.
diff --git a/debug_toolbar/panels/sql/views.py b/debug_toolbar/panels/sql/views.py
index 05ad74f..d8c94a0 100644
--- a/debug_toolbar/panels/sql/views.py
+++ b/debug_toolbar/panels/sql/views.py
@@ -39,17 +39,15 @@ def sql_explain(request):
if form.is_valid():
sql = form.cleaned_data['raw_sql']
params = form.cleaned_data['params']
+ vendor = form.connection.vendor
cursor = form.cursor
- conn = form.connection
- engine = conn.__class__.__module__.split('.', 1)[0]
-
- if engine == "sqlite3":
+ if vendor == 'sqlite':
# SQLite's EXPLAIN dumps the low-level opcodes generated for a query;
# EXPLAIN QUERY PLAN dumps a more human-readable summary
# See http://www.sqlite.org/lang_explain.html for details
cursor.execute("EXPLAIN QUERY PLAN %s" % (sql,), params)
- elif engine == "psycopg2":
+ elif vendor == 'postgresql':
cursor.execute("EXPLAIN ANALYZE %s" % (sql,), params)
else:
cursor.execute("EXPLAIN %s" % (sql,), params)
diff --git a/debug_toolbar/panels/templates/panel.py b/debug_toolbar/panels/templates/panel.py
index 74f28b0..4ee7772 100644
--- a/debug_toolbar/panels/templates/panel.py
+++ b/debug_toolbar/panels/templates/panel.py
@@ -145,6 +145,12 @@ class TemplatesPanel(Panel):
num_templates = len(self.templates)
return _("Templates (%(num_templates)s rendered)") % {'num_templates': num_templates}
+ @property
+ def nav_subtitle(self):
+ if self.templates:
+ return self.templates[0]['template'].name
+ return ''
+
template = 'debug_toolbar/panels/templates.html'
@classmethod
diff --git a/debug_toolbar/settings.py b/debug_toolbar/settings.py
index 48649fd..5c1cd3d 100644
--- a/debug_toolbar/settings.py
+++ b/debug_toolbar/settings.py
@@ -16,6 +16,7 @@ from django.utils import six
CONFIG_DEFAULTS = {
# Toolbar options
+ 'DISABLE_PANELS': set(['debug_toolbar.panels.redirects.RedirectsPanel']),
'INSERT_BEFORE': '</body>',
'RENDER_PANELS': None,
'RESULTS_STORE_SIZE': 10,
@@ -32,7 +33,7 @@ CONFIG_DEFAULTS = {
'debug_toolbar',
'django',
),
- 'INTERCEPT_REDIRECTS': False,
+ 'PROFILER_MAX_DEPTH': 10,
'SHOW_TEMPLATE_CONTEXT': True,
'SQL_WARNING_THRESHOLD': 500, # milliseconds
}
@@ -125,6 +126,30 @@ else:
PANELS[index] = new_panel
+if 'INTERCEPT_REDIRECTS' in USER_CONFIG:
+ warnings.warn(
+ "INTERCEPT_REDIRECTS is deprecated. Please use the "
+ "DISABLE_PANELS config in the"
+ "DEBUG_TOOLBAR_CONFIG setting.", DeprecationWarning)
+ if USER_CONFIG['INTERCEPT_REDIRECTS']:
+ if 'debug_toolbar.panels.redirects.RedirectsPanel' \
+ in CONFIG['DISABLE_PANELS']:
+ # RedirectsPanel should be enabled
+ try:
+ CONFIG['DISABLE_PANELS'].remove(
+ 'debug_toolbar.panels.redirects.RedirectsPanel'
+ )
+ except KeyError:
+ # We wanted to remove it, but it didn't exist. This is fine
+ pass
+ elif not 'debug_toolbar.panels.redirects.RedirectsPanel' \
+ in CONFIG['DISABLE_PANELS']:
+ # RedirectsPanel should be disabled
+ CONFIG['DISABLE_PANELS'].add(
+ 'debug_toolbar.panels.redirects.RedirectsPanel'
+ )
+
+
PATCH_SETTINGS = getattr(settings, 'DEBUG_TOOLBAR_PATCH_SETTINGS', settings.DEBUG)
diff --git a/debug_toolbar/static/debug_toolbar/js/toolbar.js b/debug_toolbar/static/debug_toolbar/js/toolbar.js
index 126f399..cb40205 100644
--- a/debug_toolbar/static/debug_toolbar/js/toolbar.js
+++ b/debug_toolbar/static/debug_toolbar/js/toolbar.js
@@ -160,8 +160,8 @@
setTimeout(function () {
djdt.handleDragged = false;
}, 10);
+ return false;
}
- return false;
});
$(document).bind('close.djDebug', function() {
// If a sub-panel is open, close that
diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql.html b/debug_toolbar/templates/debug_toolbar/panels/sql.html
index 4d95a80..7dab547 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/sql.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/sql.html
@@ -49,7 +49,7 @@
<button formaction="{% url 'djdt:sql_select' %}" class="remoteCall">Sel</button>
<button formaction="{% url 'djdt:sql_explain' %}" class="remoteCall">Expl</button>
- {% if query.engine == 'mysql' or query.engine == 'MySQLdb' %}
+ {% if query.vendor == 'mysql' %}
<button formaction="{% url 'djdt:sql_profile' %}" class="remoteCall">Prof</button>
{% endif %}
</form>
diff --git a/docs/changes.rst b/docs/changes.rst
index 4c3012a..5020466 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -1,6 +1,32 @@
Change log
==========
+1.1
+---
+
+This is the first version compatible with Django 1.7.
+
+New features
+~~~~~~~~~~~~
+
+* The SQL panel colors queries depending on the stack level.
+* The Profiler panel allows configuring the maximum depth.
+
+Bugfixes
+~~~~~~~~
+
+* Support languages where lowercase and uppercase strings may have different
+ lengths.
+* Allow using cursor as context managers.
+* Make the SQL explain more helpful on SQLite.
+* Various JavaScript improvements.
+
+Deprecated features
+~~~~~~~~~~~~~~~~~~~
+
+* The `INTERCEPT_REDIRECT` setting is superseded by the more generic
+ `DISABLE_PANELS`.
+
1.0
---
diff --git a/docs/configuration.rst b/docs/configuration.rst
index 88226cd..ff4ece7 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -57,6 +57,13 @@ toolbar itself, others are specific to some panels.
Toolbar options
~~~~~~~~~~~~~~~
+* ``DISABLE_PANELS``
+
+ Default: ``set(['debug_toolbar.panels.redirects.RedirectsPanel'])``
+
+ This setting is a set of the full Python paths to each panel that you
+ want disabled (but still displayed) by default.
+
* ``INSERT_BEFORE``
Default: ``'</body>'``
@@ -106,8 +113,8 @@ Toolbar options
This is the dotted path to a function used for determining whether the
toolbar should show or not. The default checks are that ``DEBUG`` must be
set to ``True``, the IP of the request must be in ``INTERNAL_IPS``, and the
- request must no be an AJAX request. You can provide your own function that
- accepts a request in argument and returns ``True`` or ``False``.
+ request must no be an AJAX request. You can provide your own function
+ ``callback(request)`` which returns ``True`` or ``False``.
Panel options
~~~~~~~~~~~~~
@@ -142,13 +149,14 @@ Panel options
Useful for eliminating server-related entries which can result
in enormous DOM structures and toolbar rendering delays.
-* ``INTERCEPT_REDIRECTS``
+* ``PROFILER_MAX_DEPTH``
- Default: ``False``
+ Default: ``10``
- Panel: redirects
+ Panel: profiling
- If set to ``True``, the redirect panel will be active by default.
+ This setting affects the depth of function calls in the profiler's
+ analysis.
* ``SHOW_TEMPLATE_CONTEXT``
@@ -178,6 +186,5 @@ Here's what a slightly customized toolbar configuration might look like::
'RESULTS_STORE_SIZE': 3,
'SHOW_COLLAPSED': True,
# Panel options
- 'INTERCEPT_REDIRECTS': True,
'SQL_WARNING_THRESHOLD': 100, # milliseconds
}
diff --git a/docs/panels.rst b/docs/panels.rst
index ed7abbf..58713b4 100644
--- a/docs/panels.rst
+++ b/docs/panels.rst
@@ -103,7 +103,7 @@ ready.
Since this behavior is annoying when you aren't debugging a redirect, this
panel is included but inactive by default. You can activate it by default with
-the ``INTERCEPT_REDIRECTS`` configuration option.
+the ``DISABLE_PANELS`` configuration option.
Non-default built-in panels