├── debug_toolbar ├── models.py ├── toolbar │ ├── __init__.py │ └── loader.py ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ └── debugsqlshell.py ├── tests │ ├── templates │ │ └── 404.html │ ├── __init__.py │ ├── views.py │ ├── urls.py │ └── tests.py ├── utils │ ├── compat │ │ ├── __init__.py │ │ └── db.py │ ├── sqlparse │ │ ├── __init__.py │ │ ├── engine │ │ │ ├── __init__.py │ │ │ ├── filter.py │ │ │ └── grouping.py │ │ ├── tokens.py │ │ └── formatter.py │ ├── __init__.py │ └── tracking │ │ ├── __init__.py │ │ └── db.py ├── __init__.py ├── locale │ ├── de │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── en │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── es │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── fr │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── he │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ └── ru │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── media │ └── debug_toolbar │ │ ├── img │ │ ├── back.png │ │ ├── close.png │ │ ├── dot.gif │ │ ├── back_hover.png │ │ ├── indicator.png │ │ ├── panel_bg.png │ │ ├── close_hover.png │ │ └── djdt_vertical.png │ │ ├── Makefile │ │ └── js │ │ ├── jquery.cookie.js │ │ └── toolbar.js ├── templates │ └── debug_toolbar │ │ ├── panels │ │ ├── headers.html │ │ ├── versions.html │ │ ├── settings_vars.html │ │ ├── template_source.html │ │ ├── timer.html │ │ ├── signals.html │ │ ├── logger.html │ │ ├── sql_explain.html │ │ ├── sql_select.html │ │ ├── sql_profile.html │ │ ├── profiling.html │ │ ├── cache.html │ │ ├── templates.html │ │ ├── request_vars.html │ │ └── sql.html │ │ ├── redirect.html │ │ └── base.html ├── urls.py ├── panels │ ├── settings_vars.py │ ├── __init__.py │ ├── headers.py │ ├── request_vars.py │ ├── version.py │ ├── signals.py │ ├── timer.py │ ├── cache.py │ ├── logger.py │ ├── template.py │ ├── profiling.py │ └── sql.py ├── runtests.py ├── middleware.py └── views.py ├── example ├── __init__.py ├── example.db ├── templates │ ├── index.html │ ├── mootools │ │ └── index.html │ ├── prototype │ │ └── index.html │ ├── jquery │ │ └── index.html │ └── admin │ │ └── login.html ├── manage.py ├── urls.py └── settings.py ├── setup.cfg ├── .gitignore ├── MANIFEST.in ├── AUTHORS ├── setup.py ├── NEWS ├── LICENSE └── README.rst /debug_toolbar/models.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /debug_toolbar/toolbar/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /debug_toolbar/management/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /debug_toolbar/tests/templates/404.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /debug_toolbar/utils/compat/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /debug_toolbar/management/commands/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /debug_toolbar/tests/__init__.py: -------------------------------------------------------------------------------- 1 | from tests import * -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [egg_info] 2 | tag_svn_revision = false 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.DS_Store 3 | *~ 4 | django_debug_toolbar.egg-info -------------------------------------------------------------------------------- /debug_toolbar/__init__.py: -------------------------------------------------------------------------------- 1 | VERSION = (0, 8, 5) 2 | __version__ = '.'.join(map(str, VERSION)) 3 | -------------------------------------------------------------------------------- /example/example.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/example/example.db -------------------------------------------------------------------------------- /debug_toolbar/locale/de/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/locale/de/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /debug_toolbar/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /debug_toolbar/locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /debug_toolbar/locale/fr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/locale/fr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /debug_toolbar/locale/he/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/locale/he/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /debug_toolbar/locale/ru/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/locale/ru/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/media/debug_toolbar/img/back.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/media/debug_toolbar/img/close.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/dot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/media/debug_toolbar/img/dot.gif -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS 2 | include LICENSE 3 | include README.rst 4 | recursive-include debug_toolbar/media * 5 | recursive-include debug_toolbar/templates * 6 | -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/back_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/media/debug_toolbar/img/back_hover.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/media/debug_toolbar/img/indicator.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/panel_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/media/debug_toolbar/img/panel_bg.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/close_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/media/debug_toolbar/img/close_hover.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/djdt_vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcramer/django-debug-toolbar/HEAD/debug_toolbar/media/debug_toolbar/img/djdt_vertical.png -------------------------------------------------------------------------------- /debug_toolbar/tests/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.http import HttpResponse 3 | 4 | def execute_sql(request): 5 | list(User.objects.all()) 6 | 7 | return HttpResponse() -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/Makefile: -------------------------------------------------------------------------------- 1 | # Make file to compress and join all JS files 2 | all: compress_js compress_css 3 | 4 | compress_js: 5 | java -jar ~/bin/yuicompressor.jar js/jquery.js > js/toolbar.min.js 6 | java -jar ~/bin/yuicompressor.jar js/toolbar.js >> js/toolbar.min.js 7 | 8 | compress_css: 9 | java -jar ~/bin/yuicompressor.jar --type css css/toolbar.css > css/toolbar.min.css 10 | -------------------------------------------------------------------------------- /debug_toolbar/utils/compat/db.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | try: 3 | from django.db import connections 4 | dbconf = settings.DATABASES 5 | except ImportError: 6 | # Compat with < Django 1.2 7 | from django.db import connection 8 | connections = {'default': connection} 9 | dbconf = { 10 | 'default': { 11 | 'ENGINE': settings.DATABASE_ENGINE, 12 | } 13 | } -------------------------------------------------------------------------------- /debug_toolbar/tests/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | URLpatterns for the debug toolbar. 3 | 4 | These should not be loaded explicitly; the debug toolbar middleware will patch 5 | this into the urlconf for the request. 6 | """ 7 | from django.conf.urls.defaults import * 8 | from django.contrib import admin 9 | 10 | admin.autodiscover() 11 | 12 | urlpatterns = patterns('', 13 | url(r'^execute_sql/$', 'debug_toolbar.tests.views.execute_sql'), 14 | ) 15 | -------------------------------------------------------------------------------- /example/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 || {% trans "Key" %} | 6 |{% trans "Value" %} | 7 |
|---|---|
| {{ key|escape }} | 13 |{{ value|escape }} | 14 |
| {% trans "Package" %} | 7 |{% trans "Version" %} | 8 |
|---|---|
| {{ package }} | 14 |{{ version }} | 15 |
| {% trans "Setting" %} | 6 |{% trans "Value" %} | 7 |
|---|---|
| {{ var.0 }} | 13 |{{ var.1|pprint }} |
14 |
{{ template_name }}{{ source }}
10 | {% else %}
11 | {{ source }}
12 | {% endif %}
13 | | {% trans "Resource" %} | 10 |{% trans "Value" %} | 11 |
|---|---|
| {{ key|escape }} | 17 |{{ value|escape }} | 18 |
| {% trans "Signal" %} | 6 |{% trans 'Providing Args' %} | 7 |{% trans 'Receivers' %} | 8 |
|---|---|---|
| {{ name|escape }} | 14 |{{ signal.providing_args|join:", " }} | 15 |{{ receivers|join:", " }} | 16 |
If you see this, MooTools is working.
18 | 19 | 20 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/redirect.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | 5 | 6 |{% trans 'Location' %}: {{ redirect_to }}
8 |
9 | {% trans "The Django Debug Toolbar has intercepted a redirect to the above URL for debug viewing purposes. You can click the above link to continue with the redirect as normal. If you'd like to disable this feature, set the DEBUG_TOOLBAR_CONFIG dictionary's key INTERCEPT_REDIRECTS to False." %}
10 |
If you see this, Prototype is working.
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /example/templates/jquery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |If you see this, jQuery is working.
20 | 21 | 22 | -------------------------------------------------------------------------------- /example/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls.defaults import * 3 | from django.contrib import admin 4 | from django.views.generic.simple import direct_to_template 5 | 6 | admin.autodiscover() 7 | 8 | urlpatterns = patterns('', 9 | (r'^$', direct_to_template, {'template': 'index.html'}), 10 | (r'^jquery/index/$', direct_to_template, {'template': 'jquery/index.html'}), 11 | (r'^mootools/index/$', direct_to_template, {'template': 'mootools/index.html'}), 12 | (r'^prototype/index/$', direct_to_template, {'template': 'prototype/index.html'}), 13 | (r'^admin/', include(admin.site.urls)), 14 | ) 15 | 16 | if settings.DEBUG: 17 | urlpatterns += patterns('', 18 | (r'^media/(.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}) 19 | ) 20 | 21 | -------------------------------------------------------------------------------- /debug_toolbar/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | URLpatterns for the debug toolbar. 3 | 4 | These should not be loaded explicitly; the debug toolbar middleware will patch 5 | this into the urlconf for the request. 6 | """ 7 | from django.conf.urls.defaults import * 8 | from django.conf import settings 9 | 10 | _PREFIX = '__debug__' 11 | 12 | urlpatterns = patterns('', 13 | url(r'^%s/m/(.*)$' % _PREFIX, 'debug_toolbar.views.debug_media'), 14 | url(r'^%s/sql_select/$' % _PREFIX, 'debug_toolbar.views.sql_select', name='sql_select'), 15 | url(r'^%s/sql_explain/$' % _PREFIX, 'debug_toolbar.views.sql_explain', name='sql_explain'), 16 | url(r'^%s/sql_profile/$' % _PREFIX, 'debug_toolbar.views.sql_profile', name='sql_profile'), 17 | url(r'^%s/template_source/$' % _PREFIX, 'debug_toolbar.views.template_source', name='template_source'), 18 | ) 19 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/logger.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% if records %} 3 || {% trans "Level" %} | 7 |{% trans "Time" %} | 8 |{% trans "Channel" %} | 9 |{% trans "Message" %} | 10 |{% trans "Location" %} | 11 |
|---|---|---|---|---|
| {{ record.level }} | 17 |{{ record.time|date:"h:i:s m/d/Y" }} | 18 |{{ record.channel|default:"-" }} | 19 |{{ record.message }} | 20 |{{ record.file }}:{{ record.line }} | 21 |
{% trans "No messages logged" %}.
27 | {% endif %} 28 | 29 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/sql_explain.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 || {{ h|upper }} | 19 | {% endfor %} 20 |
|---|
| {{ column|escape }} | 27 | {% endfor %} 28 |
%s') % settings.SETTINGS_MODULE
20 |
21 | def url(self):
22 | return ''
23 |
24 | def content(self):
25 | context = self.context.copy()
26 | context.update({
27 | 'settings': get_safe_settings(),
28 | })
29 | return render_to_string('debug_toolbar/panels/settings_vars.html', context)
30 |
--------------------------------------------------------------------------------
/debug_toolbar/templates/debug_toolbar/panels/sql_select.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 | | {{ h|upper }} | 20 | {% endfor %} 21 |
|---|
| {{ column|escape }} | 28 | {% endfor %} 29 |
{% trans "Empty set" %}
35 | {% endif %} 36 || {{ h|upper }} | 20 | {% endfor %} 21 |
|---|
| {{ column|escape }} | 28 | {% endfor %} 29 |
{{ error_message }}
15 | {% endif %} 16 || {% trans "Call" %} | 7 |{% trans "TotTime" %} | 8 |{% trans "Per" %} | 9 |{% trans "CumTime" %} | 10 |{% trans "Per" %} | 11 |{% trans "Count" %} | 12 |
|---|---|---|---|---|---|
|
19 |
20 | {% if call.has_subfuncs %}
21 | -
22 | {% else %}
23 |
24 | {% endif %}
25 | {{ call.func_std_string }}
26 |
27 | |
28 | {{ call.tottime|floatformat:3 }} | 29 |{{ call.tottime_per_call|floatformat:3 }} | 30 |{{ call.cumtime|floatformat:3 }} | 31 |{{ call.cumtime_per_call|floatformat:3 }} | 32 |{{ call.count }} | 33 |
| {% trans "Total Calls" %} | 15 |{{ cache_calls }} | 16 |{% trans "Total Time" %} | 17 |{{ cache_time }}ms | 18 |{% trans "Hits" %} | 19 |{{ cache.hits }} | 20 |{% trans "Misses" %} | 21 |{{ cache.misses }} | 22 |
|---|---|---|---|---|---|---|---|
| gets | 25 |{{ cache.gets }} | 26 |sets | 27 |{{ cache.sets }} | 28 |deletes | 29 |{{ cache.deletes }} | 30 |get_many | 31 |{{ cache.get_many }} | 32 |
| {% trans "Time" %} (ms) | 40 |{% trans "Type" %} | 41 |{% trans "Parameters" %} | 42 |{% trans "Function" %} | 43 |
|---|---|---|---|
| {{ query.0|floatformat:"4" }} | 49 |{{ query.1|escape }} | 50 |{{ query.2|escape }} | 51 |{{ query.3.2|escape }}: {{ query.3.3.0|escape }} | 52 |
None
11 | {% endif %} 12 | 13 |{% trans 'None' %}
29 | {% endif %} 30 | 31 |{% trans 'None' %}
44 | {% endif %} 45 | -------------------------------------------------------------------------------- /example/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | PROJECT_PATH = os.path.realpath(os.path.dirname(__file__)) 3 | 4 | ADMIN_MEDIA_PREFIX = '/admin_media/' 5 | DATABASE_ENGINE = 'sqlite3' 6 | DATABASE_NAME = 'example.db' 7 | DEBUG = True 8 | INSTALLED_APPS = ( 9 | 'django.contrib.auth', 10 | 'django.contrib.admin', 11 | 'django.contrib.contenttypes', 12 | 'django.contrib.sessions', 13 | 'django.contrib.sites', 14 | 'debug_toolbar', 15 | ) 16 | INTERNAL_IPS = ('127.0.0.1',) 17 | MEDIA_ROOT = os.path.join(PROJECT_PATH, 'media') 18 | MEDIA_URL = '/media' 19 | MIDDLEWARE_CLASSES = ( 20 | 'django.middleware.common.CommonMiddleware', 21 | 'django.contrib.sessions.middleware.SessionMiddleware', 22 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 23 | 'debug_toolbar.middleware.DebugToolbarMiddleware', 24 | ) 25 | ROOT_URLCONF = 'example.urls' 26 | SECRET_KEY = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcd' 27 | SITE_ID = 1 28 | TEMPLATE_CONTEXT_PROCESSORS = ( 29 | 'django.core.context_processors.auth', 30 | 'django.core.context_processors.media', 31 | 'django.core.context_processors.request', 32 | ) 33 | TEMPLATE_DEBUG = DEBUG 34 | TEMPLATE_DIRS = (os.path.join(PROJECT_PATH, 'templates')) 35 | DEBUG_TOOLBAR_PANELS = ( 36 | 'debug_toolbar.panels.version.VersionDebugPanel', 37 | 'debug_toolbar.panels.timer.TimerDebugPanel', 38 | 'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel', 39 | 'debug_toolbar.panels.headers.HeaderDebugPanel', 40 | 'debug_toolbar.panels.profiling.ProfilingDebugPanel', 41 | 'debug_toolbar.panels.request_vars.RequestVarsDebugPanel', 42 | 'debug_toolbar.panels.sql.SQLDebugPanel', 43 | 'debug_toolbar.panels.template.TemplateDebugPanel', 44 | #'debug_toolbar.panels.cache.CacheDebugPanel', 45 | 'debug_toolbar.panels.signals.SignalDebugPanel', 46 | 'debug_toolbar.panels.logger.LoggingPanel', 47 | ) -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/base.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 6 | 7 | 55 | -------------------------------------------------------------------------------- /debug_toolbar/panels/version.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import django 4 | from django.conf import settings 5 | from django.template.loader import render_to_string 6 | from django.utils.translation import ugettext_lazy as _ 7 | 8 | import debug_toolbar 9 | from debug_toolbar.panels import DebugPanel 10 | 11 | 12 | class VersionDebugPanel(DebugPanel): 13 | """ 14 | Panel that displays the Django version. 15 | """ 16 | name = 'Version' 17 | has_content = True 18 | 19 | def nav_title(self): 20 | return _('Versions') 21 | 22 | def nav_subtitle(self): 23 | return 'Django %s' % django.get_version() 24 | 25 | def url(self): 26 | return '' 27 | 28 | def title(self): 29 | return _('Versions') 30 | 31 | def content(self): 32 | versions = {} 33 | for app in settings.INSTALLED_APPS + ['django']: 34 | name = app.split('.')[-1].replace('_', ' ').capitalize() 35 | __import__(app) 36 | app = sys.modules[app] 37 | if hasattr(app, 'get_version'): 38 | get_version = app.get_version 39 | if callable(get_version): 40 | version = get_version() 41 | else: 42 | version = get_version 43 | elif hasattr(app, 'VERSION'): 44 | version = app.VERSION 45 | elif hasattr(app, '__version__'): 46 | version = app.__version__ 47 | else: 48 | continue 49 | if isinstance(version, (list, tuple)): 50 | version = '.'.join(str(o) for o in version) 51 | versions[name] = version 52 | 53 | context = self.context.copy() 54 | context.update({ 55 | 'versions': versions, 56 | 'paths': sys.path, 57 | }) 58 | 59 | return render_to_string('debug_toolbar/panels/versions.html', context) 60 | -------------------------------------------------------------------------------- /debug_toolbar/utils/__init__.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import django 3 | import SocketServer 4 | 5 | from django.conf import settings 6 | from django.views.debug import linebreak_iter 7 | 8 | # Figure out some paths 9 | django_path = os.path.realpath(os.path.dirname(django.__file__)) 10 | socketserver_path = os.path.realpath(os.path.dirname(SocketServer.__file__)) 11 | 12 | def ms_from_timedelta(td): 13 | """ 14 | Given a timedelta object, returns a float representing milliseconds 15 | """ 16 | return (td.seconds * 1000) + (td.microseconds / 1000.0) 17 | 18 | def tidy_stacktrace(strace): 19 | """ 20 | Clean up stacktrace and remove all entries that: 21 | 1. Are part of Django (except contrib apps) 22 | 2. Are part of SocketServer (used by Django's dev server) 23 | 3. Are the last entry (which is part of our stacktracing code) 24 | """ 25 | trace = [] 26 | for s in strace[:-1]: 27 | s_path = os.path.realpath(s[0]) 28 | if getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}).get('HIDE_DJANGO_SQL', True) \ 29 | and django_path in s_path and not 'django/contrib' in s_path: 30 | continue 31 | if socketserver_path in s_path: 32 | continue 33 | trace.append((s[0], s[1], s[2], s[3])) 34 | return trace 35 | 36 | def get_template_info(source, context_lines=3): 37 | line = 0 38 | upto = 0 39 | source_lines = [] 40 | before = during = after = "" 41 | 42 | origin, (start, end) = source 43 | template_source = origin.reload() 44 | 45 | for num, next in enumerate(linebreak_iter(template_source)): 46 | if start >= upto and end <= next: 47 | line = num 48 | before = template_source[upto:start] 49 | during = template_source[start:end] 50 | after = template_source[end:next] 51 | source_lines.append((num, template_source[upto:next])) 52 | upto = next 53 | 54 | top = max(1, line - context_lines) 55 | bottom = min(len(source_lines), line + 1 + context_lines) 56 | 57 | context = [] 58 | for num, content in source_lines[top:bottom]: 59 | context.append({ 60 | 'num': num, 61 | 'content': content, 62 | 'highlight': (num == line), 63 | }) 64 | 65 | return { 66 | 'name': origin.name, 67 | 'context': context, 68 | } -------------------------------------------------------------------------------- /debug_toolbar/utils/sqlparse/engine/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2008 Andi Albrecht, albrecht.andi@gmail.com 2 | # 3 | # This module is part of python-sqlparse and is released under 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php. 5 | 6 | """filter""" 7 | 8 | import re 9 | 10 | from debug_toolbar.utils.sqlparse import lexer, SQLParseError 11 | from debug_toolbar.utils.sqlparse.engine import grouping 12 | from debug_toolbar.utils.sqlparse.engine.filter import StatementFilter 13 | 14 | # XXX remove this when cleanup is complete 15 | Filter = object 16 | 17 | 18 | class FilterStack(object): 19 | 20 | def __init__(self): 21 | self.preprocess = [] 22 | self.stmtprocess = [] 23 | self.postprocess = [] 24 | self.split_statements = False 25 | self._grouping = False 26 | 27 | def _flatten(self, stream): 28 | for token in stream: 29 | if token.is_group(): 30 | for t in self._flatten(token.tokens): 31 | yield t 32 | else: 33 | yield token 34 | 35 | def enable_grouping(self): 36 | self._grouping = True 37 | 38 | def full_analyze(self): 39 | self.enable_grouping() 40 | 41 | def run(self, sql): 42 | stream = lexer.tokenize(sql) 43 | # Process token stream 44 | if self.preprocess: 45 | for filter_ in self.preprocess: 46 | stream = filter_.process(self, stream) 47 | 48 | if (self.stmtprocess or self.postprocess or self.split_statements 49 | or self._grouping): 50 | splitter = StatementFilter() 51 | stream = splitter.process(self, stream) 52 | 53 | if self._grouping: 54 | def _group(stream): 55 | for stmt in stream: 56 | grouping.group(stmt) 57 | yield stmt 58 | stream = _group(stream) 59 | 60 | if self.stmtprocess: 61 | def _run(stream): 62 | ret = [] 63 | for stmt in stream: 64 | for filter_ in self.stmtprocess: 65 | filter_.process(self, stmt) 66 | ret.append(stmt) 67 | return ret 68 | stream = _run(stream) 69 | 70 | if self.postprocess: 71 | def _run(stream): 72 | for stmt in stream: 73 | stmt.tokens = list(self._flatten(stmt.tokens)) 74 | for filter_ in self.postprocess: 75 | stmt = filter_.process(self, stmt) 76 | yield stmt 77 | stream = _run(stream) 78 | 79 | return stream 80 | 81 | -------------------------------------------------------------------------------- /debug_toolbar/utils/tracking/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import time 3 | import types 4 | 5 | def post_dispatch(func): 6 | def wrapped(callback): 7 | register_hook(func, 'after', callback) 8 | return callback 9 | return wrapped 10 | 11 | def pre_dispatch(func): 12 | def wrapped(callback): 13 | register_hook(func, 'before', callback) 14 | return callback 15 | return wrapped 16 | 17 | def replace_call(func): 18 | def inner(callback): 19 | def wrapped(*args, **kwargs): 20 | return callback(func, *args, **kwargs) 21 | 22 | actual = getattr(func, '__wrapped__', func) 23 | wrapped.__wrapped__ = actual 24 | wrapped.__doc__ = getattr(actual, '__doc__', None) 25 | wrapped.__name__ = actual.__name__ 26 | 27 | _replace_function(func, wrapped) 28 | return wrapped 29 | return inner 30 | 31 | def fire_hook(hook, sender, **kwargs): 32 | try: 33 | for callback in callbacks[hook].get(id(sender), []): 34 | callback(sender=sender, **kwargs) 35 | except Exception, e: 36 | # Log the exception, dont mess w/ the underlying function 37 | logging.exception(e) 38 | 39 | def _replace_function(func, wrapped): 40 | if isinstance(func, types.FunctionType): 41 | if func.__module__ == '__builtin__': 42 | # oh shit 43 | __builtins__[func] = wrapped 44 | else: 45 | module = __import__(func.__module__, {}, {}, [func.__module__], 0) 46 | setattr(module, func.__name__, wrapped) 47 | elif getattr(func, 'im_self', None): 48 | # TODO: classmethods 49 | raise NotImplementedError 50 | elif hasattr(func, 'im_class'): 51 | # for unbound methods 52 | setattr(func.im_class, func.__name__, wrapped) 53 | else: 54 | raise NotImplementedError 55 | 56 | callbacks = { 57 | 'before': {}, 58 | 'after': {}, 59 | } 60 | 61 | def register_hook(func, hook, callback): 62 | """ 63 | def myhook(sender, args, kwargs): 64 | print func, "executed 65 | print "args:", args 66 | print "kwargs:", kwargs 67 | register_hook(BaseDatabaseWrapper.cursor, 'before', myhook) 68 | """ 69 | 70 | assert hook in ('before', 'after') 71 | 72 | def wrapped(*args, **kwargs): 73 | start = time.time() 74 | fire_hook('before', sender=wrapped.__wrapped__, args=args, kwargs=kwargs, 75 | start=start) 76 | result = wrapped.__wrapped__(*args, **kwargs) 77 | stop = time.time() 78 | fire_hook('after', sender=wrapped.__wrapped__, args=args, kwargs=kwargs, 79 | result=result, start=start, stop=stop) 80 | actual = getattr(func, '__wrapped__', func) 81 | wrapped.__wrapped__ = actual 82 | wrapped.__doc__ = getattr(actual, '__doc__', None) 83 | wrapped.__name__ = actual.__name__ 84 | 85 | id_ = id(actual) 86 | if id_ not in callbacks[hook]: 87 | callbacks[hook][id_] = [] 88 | callbacks[hook][id_].append(callback) 89 | 90 | _replace_function(func, wrapped) -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/request_vars.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 || {% trans 'View Function' %} | 8 |{% trans 'args' %} | 9 |{% trans 'kwargs' %} | 10 |
|---|---|---|
| {{ view_func }} | 15 |{{ view_args|default:"None" }} | 16 |17 | {% if view_kwargs.items %} 18 | {% for k, v in view_kwargs.items %} 19 | {{ k }}={{ v }}{% if not forloop.last %}, {% endif %} 20 | {% endfor %} 21 | {% else %} 22 | None 23 | {% endif %} 24 | | 25 |
| {% trans "Variable" %} | 39 |{% trans "Value" %} | 40 |
|---|---|
| {{ key|escape }} | 46 |{{ value|escape }} | 47 |
{% trans "No COOKIE data" %}
53 | {% endif %} 54 | 55 || {% trans "Variable" %} | 65 |{% trans "Value" %} | 66 |
|---|---|
| {{ key|escape }} | 72 |{{ value|escape }} | 73 |
{% trans "No SESSION data" %}
79 | {% endif %} 80 | 81 || {% trans "Variable" %} | 87 |{% trans "Value" %} | 88 |
|---|---|
| {{ key|escape }} | 94 |{{ value|join:", "|escape }} | 95 |
{% trans "No GET data" %}
101 | {% endif %} 102 | 103 || {% trans "Variable" %} | 109 |{% trans "Value" %} | 110 |
|---|---|
| {{ key|escape }} | 116 |{{ value|join:", "|escape }} | 117 |
{% trans "No POST data" %}
123 | {% endif %} 124 | -------------------------------------------------------------------------------- /debug_toolbar/utils/sqlparse/engine/filter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from debug_toolbar.utils.sqlparse import tokens as T 4 | from debug_toolbar.utils.sqlparse.engine.grouping import Statement, Token 5 | 6 | 7 | class TokenFilter(object): 8 | 9 | def __init__(self, **options): 10 | self.options = options 11 | 12 | def process(self, stack, stream): 13 | """Process token stream.""" 14 | raise NotImplementedError 15 | 16 | 17 | class StatementFilter(TokenFilter): 18 | 19 | def __init__(self): 20 | TokenFilter.__init__(self) 21 | self._in_declare = False 22 | self._in_dbldollar = False 23 | self._is_create = False 24 | 25 | def _reset(self): 26 | self._in_declare = False 27 | self._in_dbldollar = False 28 | self._is_create = False 29 | 30 | def _change_splitlevel(self, ttype, value): 31 | # PostgreSQL 32 | if (ttype == T.Name.Builtin 33 | and value.startswith('$') and value.endswith('$')): 34 | if self._in_dbldollar: 35 | self._in_dbldollar = False 36 | return -1 37 | else: 38 | self._in_dbldollar = True 39 | return 1 40 | elif self._in_dbldollar: 41 | return 0 42 | 43 | # ANSI 44 | if ttype is not T.Keyword: 45 | return 0 46 | 47 | unified = value.upper() 48 | 49 | if unified == 'DECLARE': 50 | self._in_declare = True 51 | return 1 52 | 53 | if unified == 'BEGIN': 54 | if self._in_declare: 55 | return 0 56 | return 0 57 | 58 | if unified == 'END': 59 | # Should this respect a preceeding BEGIN? 60 | # In CASE ... WHEN ... END this results in a split level -1. 61 | return -1 62 | 63 | if ttype is T.Keyword.DDL and unified.startswith('CREATE'): 64 | self._is_create = True 65 | 66 | if unified in ('IF', 'FOR') and self._is_create: 67 | return 1 68 | 69 | # Default 70 | return 0 71 | 72 | def process(self, stack, stream): 73 | splitlevel = 0 74 | stmt = None 75 | consume_ws = False 76 | stmt_tokens = [] 77 | for ttype, value in stream: 78 | # Before appending the token 79 | if (consume_ws and ttype is not T.Whitespace 80 | and ttype is not T.Comment.Single): 81 | consume_ws = False 82 | stmt.tokens = stmt_tokens 83 | yield stmt 84 | self._reset() 85 | stmt = None 86 | splitlevel = 0 87 | if stmt is None: 88 | stmt = Statement() 89 | stmt_tokens = [] 90 | splitlevel += self._change_splitlevel(ttype, value) 91 | # Append the token 92 | stmt_tokens.append(Token(ttype, value)) 93 | # After appending the token 94 | if (splitlevel <= 0 and ttype is T.Punctuation 95 | and value == ';'): 96 | consume_ws = True 97 | if stmt is not None: 98 | stmt.tokens = stmt_tokens 99 | yield stmt 100 | -------------------------------------------------------------------------------- /debug_toolbar/panels/signals.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from django.conf import settings 4 | from django.core.signals import request_started, request_finished, \ 5 | got_request_exception 6 | from django.db.models.signals import class_prepared, pre_init, post_init, \ 7 | pre_save, post_save, pre_delete, post_delete, post_syncdb 8 | from django.dispatch.dispatcher import WEAKREF_TYPES 9 | from django.template.loader import render_to_string 10 | from django.utils.translation import ugettext_lazy as _ 11 | 12 | try: 13 | from django.db.backends.signals import connection_created 14 | except ImportError: 15 | connection_created = None 16 | 17 | from debug_toolbar.panels import DebugPanel 18 | 19 | class SignalDebugPanel(DebugPanel): 20 | name = "Signals" 21 | has_content = True 22 | 23 | SIGNALS = { 24 | 'request_started': request_started, 25 | 'request_finished': request_finished, 26 | 'got_request_exception': got_request_exception, 27 | 'connection_created': connection_created, 28 | 'class_prepared': class_prepared, 29 | 'pre_init': pre_init, 30 | 'post_init': post_init, 31 | 'pre_save': pre_save, 32 | 'post_save': post_save, 33 | 'pre_delete': pre_delete, 34 | 'post_delete': post_delete, 35 | 'post_syncdb': post_syncdb, 36 | } 37 | 38 | def nav_title(self): 39 | return _("Signals") 40 | 41 | def title(self): 42 | return _("Signals") 43 | 44 | def url(self): 45 | return '' 46 | 47 | def signals(self): 48 | signals = self.SIGNALS.copy() 49 | if hasattr(settings, 'DEBUG_TOOLBAR_CONFIG'): 50 | extra_signals = settings.DEBUG_TOOLBAR_CONFIG.get('EXTRA_SIGNALS', []) 51 | else: 52 | extra_signals = [] 53 | for signal in extra_signals: 54 | parts = signal.split('.') 55 | path = '.'.join(parts[:-1]) 56 | __import__(path) 57 | signals[parts[-1]] = getattr(sys.modules[path], parts[-1]) 58 | return signals 59 | signals = property(signals) 60 | 61 | def content(self): 62 | signals = [] 63 | keys = self.signals.keys() 64 | keys.sort() 65 | for name in keys: 66 | signal = self.signals[name] 67 | if signal is None: 68 | continue 69 | receivers = [] 70 | for (receiverkey, r_senderkey), receiver in signal.receivers: 71 | if isinstance(receiver, WEAKREF_TYPES): 72 | receiver = receiver() 73 | if receiver is None: 74 | continue 75 | if getattr(receiver, 'im_self', None) is not None: 76 | text = "method %s on %s object" % (receiver.__name__, receiver.im_self.__class__.__name__) 77 | elif getattr(receiver, 'im_class', None) is not None: 78 | text = "method %s on %s" % (receiver.__name__, receiver.im_class.__name__) 79 | else: 80 | text = "function %s" % receiver.__name__ 81 | receivers.append(text) 82 | signals.append((name, signal, receivers)) 83 | 84 | context = self.context.copy() 85 | context.update({'signals': signals}) 86 | 87 | return render_to_string('debug_toolbar/panels/signals.html', context) 88 | -------------------------------------------------------------------------------- /debug_toolbar/management/commands/debugsqlshell.py: -------------------------------------------------------------------------------- 1 | import os 2 | from optparse import make_option 3 | 4 | from django.core.management.base import NoArgsCommand 5 | from django.db.backends import util 6 | 7 | from debug_toolbar.utils import sqlparse 8 | 9 | class PrintQueryWrapper(util.CursorDebugWrapper): 10 | def execute(self, sql, params=()): 11 | try: 12 | return self.cursor.execute(sql, params) 13 | finally: 14 | raw_sql = self.db.ops.last_executed_query(self.cursor, sql, params) 15 | print sqlparse.format(raw_sql, reindent=True) 16 | print 17 | 18 | util.CursorDebugWrapper = PrintQueryWrapper 19 | 20 | # The rest is copy/paste from django/core/management/commands/shell.py 21 | 22 | class Command(NoArgsCommand): 23 | option_list = NoArgsCommand.option_list + ( 24 | make_option('--plain', action='store_true', dest='plain', 25 | help='Tells Django to use plain Python, not IPython.'), 26 | ) 27 | help = "Runs a Python interactive interpreter. Tries to use IPython, if it's available." 28 | 29 | requires_model_validation = False 30 | 31 | def handle_noargs(self, **options): 32 | # XXX: (Temporary) workaround for ticket #1796: force early loading of all 33 | # models from installed apps. 34 | from django.db.models.loading import get_models 35 | loaded_models = get_models() 36 | 37 | use_plain = options.get('plain', False) 38 | 39 | try: 40 | if use_plain: 41 | # Don't bother loading IPython, because the user wants plain Python. 42 | raise ImportError 43 | import IPython 44 | # Explicitly pass an empty list as arguments, because otherwise IPython 45 | # would use sys.argv from this script. 46 | shell = IPython.Shell.IPShell(argv=[]) 47 | shell.mainloop() 48 | except ImportError: 49 | import code 50 | # Set up a dictionary to serve as the environment for the shell, so 51 | # that tab completion works on objects that are imported at runtime. 52 | # See ticket 5082. 53 | imported_objects = {} 54 | try: # Try activating rlcompleter, because it's handy. 55 | import readline 56 | except ImportError: 57 | pass 58 | else: 59 | # We don't have to wrap the following import in a 'try', because 60 | # we already know 'readline' was imported successfully. 61 | import rlcompleter 62 | readline.set_completer(rlcompleter.Completer(imported_objects).complete) 63 | readline.parse_and_bind("tab:complete") 64 | 65 | # We want to honor both $PYTHONSTARTUP and .pythonrc.py, so follow system 66 | # conventions and get $PYTHONSTARTUP first then import user. 67 | if not use_plain: 68 | pythonrc = os.environ.get("PYTHONSTARTUP") 69 | if pythonrc and os.path.isfile(pythonrc): 70 | try: 71 | execfile(pythonrc) 72 | except NameError: 73 | pass 74 | # This will import .pythonrc.py as a side-effect 75 | import user 76 | code.interact(local=imported_objects) 77 | -------------------------------------------------------------------------------- /debug_toolbar/panels/timer.py: -------------------------------------------------------------------------------- 1 | try: 2 | import resource 3 | except ImportError: 4 | pass # Will fail on Win32 systems 5 | import time 6 | from django.template.loader import render_to_string 7 | from django.utils.translation import ugettext_lazy as _ 8 | from debug_toolbar.panels import DebugPanel 9 | 10 | class TimerDebugPanel(DebugPanel): 11 | """ 12 | Panel that displays the time a response took in milliseconds. 13 | """ 14 | name = 'Timer' 15 | try: # if resource module not available, don't show content panel 16 | resource 17 | except NameError: 18 | has_content = False 19 | has_resource = False 20 | else: 21 | has_content = True 22 | has_resource = True 23 | 24 | def process_request(self, request): 25 | self._start_time = time.time() 26 | if self.has_resource: 27 | self._start_rusage = resource.getrusage(resource.RUSAGE_SELF) 28 | 29 | def process_response(self, request, response): 30 | self.total_time = (time.time() - self._start_time) * 1000 31 | if self.has_resource: 32 | self._end_rusage = resource.getrusage(resource.RUSAGE_SELF) 33 | 34 | def nav_title(self): 35 | return _('Time') 36 | 37 | def nav_subtitle(self): 38 | # TODO l10n 39 | if self.has_resource: 40 | utime = self._end_rusage.ru_utime - self._start_rusage.ru_utime 41 | stime = self._end_rusage.ru_stime - self._start_rusage.ru_stime 42 | return 'CPU: %0.2fms (%0.2fms)' % ((utime + stime) * 1000.0, self.total_time) 43 | else: 44 | return 'TOTAL: %0.2fms' % (self.total_time) 45 | 46 | def title(self): 47 | return _('Resource Usage') 48 | 49 | def url(self): 50 | return '' 51 | 52 | def _elapsed_ru(self, name): 53 | return getattr(self._end_rusage, name) - getattr(self._start_rusage, name) 54 | 55 | def content(self): 56 | 57 | utime = 1000 * self._elapsed_ru('ru_utime') 58 | stime = 1000 * self._elapsed_ru('ru_stime') 59 | vcsw = self._elapsed_ru('ru_nvcsw') 60 | ivcsw = self._elapsed_ru('ru_nivcsw') 61 | minflt = self._elapsed_ru('ru_minflt') 62 | majflt = self._elapsed_ru('ru_majflt') 63 | 64 | # these are documented as not meaningful under Linux. If you're running BSD 65 | # feel free to enable them, and add any others that I hadn't gotten to before 66 | # I noticed that I was getting nothing but zeroes and that the docs agreed. :-( 67 | # 68 | # blkin = self._elapsed_ru('ru_inblock') 69 | # blkout = self._elapsed_ru('ru_oublock') 70 | # swap = self._elapsed_ru('ru_nswap') 71 | # rss = self._end_rusage.ru_maxrss 72 | # srss = self._end_rusage.ru_ixrss 73 | # urss = self._end_rusage.ru_idrss 74 | # usrss = self._end_rusage.ru_isrss 75 | 76 | # TODO l10n on values 77 | rows = ( 78 | (_('User CPU time'), '%0.3f msec' % utime), 79 | (_('System CPU time'), '%0.3f msec' % stime), 80 | (_('Total CPU time'), '%0.3f msec' % (utime + stime)), 81 | (_('Elapsed time'), '%0.3f msec' % self.total_time), 82 | (_('Context switches'), '%d voluntary, %d involuntary' % (vcsw, ivcsw)), 83 | # ('Memory use', '%d max RSS, %d shared, %d unshared' % (rss, srss, urss + usrss)), 84 | # ('Page faults', '%d no i/o, %d requiring i/o' % (minflt, majflt)), 85 | # ('Disk operations', '%d in, %d out, %d swapout' % (blkin, blkout, swap)), 86 | ) 87 | 88 | context = self.context.copy() 89 | context.update({ 90 | 'rows': rows, 91 | }) 92 | 93 | return render_to_string('debug_toolbar/panels/timer.html', context) 94 | -------------------------------------------------------------------------------- /debug_toolbar/panels/cache.py: -------------------------------------------------------------------------------- 1 | import time 2 | import inspect 3 | 4 | from django.core import cache 5 | from django.core.cache.backends.base import BaseCache 6 | from django.template.loader import render_to_string 7 | from django.utils.translation import ugettext_lazy as _ 8 | from debug_toolbar.panels import DebugPanel 9 | 10 | class CacheStatTracker(BaseCache): 11 | """A small class used to track cache calls.""" 12 | def __init__(self, cache): 13 | self.cache = cache 14 | self.reset() 15 | 16 | def reset(self): 17 | self.calls = [] 18 | self.hits = 0 19 | self.misses = 0 20 | self.sets = 0 21 | self.gets = 0 22 | self.get_many = 0 23 | self.deletes = 0 24 | self.total_time = 0 25 | 26 | def _get_func_info(self): 27 | stack = inspect.stack()[2] 28 | return (stack[1], stack[2], stack[3], stack[4]) 29 | 30 | def get(self, key, default=None): 31 | t = time.time() 32 | value = self.cache.get(key, default) 33 | this_time = time.time() - t 34 | self.total_time += this_time * 1000 35 | if value is None: 36 | self.misses += 1 37 | else: 38 | self.hits += 1 39 | self.gets += 1 40 | self.calls.append((this_time, 'get', (key,), self._get_func_info())) 41 | return value 42 | 43 | def set(self, key, value, timeout=None): 44 | t = time.time() 45 | self.cache.set(key, value, timeout) 46 | this_time = time.time() - t 47 | self.total_time += this_time * 1000 48 | self.sets += 1 49 | self.calls.append((this_time, 'set', (key, value, timeout), self._get_func_info())) 50 | 51 | def delete(self, key): 52 | t = time.time() 53 | self.cache.delete(key) 54 | this_time = time.time() - t 55 | self.total_time += this_time * 1000 56 | self.deletes += 1 57 | self.calls.append((this_time, 'delete', (key,), self._get_func_info())) 58 | 59 | def get_many(self, keys): 60 | t = time.time() 61 | results = self.cache.get_many(keys) 62 | this_time = time.time() - t 63 | self.total_time += this_time * 1000 64 | self.get_many += 1 65 | for key, value in results.iteritems(): 66 | if value is None: 67 | self.misses += 1 68 | else: 69 | self.hits += 1 70 | self.calls.append((this_time, 'get_many', (keys,), self._get_func_info())) 71 | 72 | class CacheDebugPanel(DebugPanel): 73 | """ 74 | Panel that displays the cache statistics. 75 | """ 76 | name = 'Cache' 77 | has_content = True 78 | 79 | def __init__(self, *args, **kwargs): 80 | super(self.__class__, self).__init__(*args, **kwargs) 81 | # This is hackish but to prevent threading issues is somewhat needed 82 | if isinstance(cache.cache, CacheStatTracker): 83 | cache.cache.reset() 84 | self.cache = cache.cache 85 | else: 86 | self.cache = CacheStatTracker(cache.cache) 87 | cache.cache = self.cache 88 | 89 | def nav_title(self): 90 | return _('Cache: %.2fms') % self.cache.total_time 91 | 92 | def title(self): 93 | return _('Cache Usage') 94 | 95 | def url(self): 96 | return '' 97 | 98 | def content(self): 99 | context = self.context.copy() 100 | context.update({ 101 | 'cache_calls': len(self.cache.calls), 102 | 'cache_time': self.cache.total_time, 103 | 'cache': self.cache, 104 | }) 105 | return render_to_string('debug_toolbar/panels/cache.html', context) 106 | -------------------------------------------------------------------------------- /debug_toolbar/utils/sqlparse/tokens.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2008 Andi Albrecht, albrecht.andi@gmail.com 2 | # 3 | # This module is part of python-sqlparse and is released under 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php. 5 | 6 | # The Token implementation is based on pygment's token system written 7 | # by Georg Brandl. 8 | # http://pygments.org/ 9 | 10 | """Tokens""" 11 | 12 | try: 13 | set 14 | except NameError: 15 | from sets import Set as set 16 | 17 | 18 | class _TokenType(tuple): 19 | parent = None 20 | 21 | def split(self): 22 | buf = [] 23 | node = self 24 | while node is not None: 25 | buf.append(node) 26 | node = node.parent 27 | buf.reverse() 28 | return buf 29 | 30 | def __init__(self, *args): 31 | # no need to call super.__init__ 32 | self.subtypes = set() 33 | 34 | def __contains__(self, val): 35 | return self is val or ( 36 | type(val) is self.__class__ and 37 | val[:len(self)] == self 38 | ) 39 | 40 | def __getattr__(self, val): 41 | if not val or not val[0].isupper(): 42 | return tuple.__getattribute__(self, val) 43 | new = _TokenType(self + (val,)) 44 | setattr(self, val, new) 45 | self.subtypes.add(new) 46 | new.parent = self 47 | return new 48 | 49 | def __hash__(self): 50 | return hash(tuple(self)) 51 | 52 | def __repr__(self): 53 | return 'Token' + (self and '.' or '') + '.'.join(self) 54 | 55 | 56 | Token = _TokenType() 57 | 58 | # Special token types 59 | Text = Token.Text 60 | Whitespace = Text.Whitespace 61 | Newline = Whitespace.Newline 62 | Error = Token.Error 63 | # Text that doesn't belong to this lexer (e.g. HTML in PHP) 64 | Other = Token.Other 65 | 66 | # Common token types for source code 67 | Keyword = Token.Keyword 68 | Name = Token.Name 69 | Literal = Token.Literal 70 | String = Literal.String 71 | Number = Literal.Number 72 | Punctuation = Token.Punctuation 73 | Operator = Token.Operator 74 | Wildcard = Token.Wildcard 75 | Comment = Token.Comment 76 | Assignment = Token.Assignement 77 | 78 | # Generic types for non-source code 79 | Generic = Token.Generic 80 | 81 | # String and some others are not direct childs of Token. 82 | # alias them: 83 | Token.Token = Token 84 | Token.String = String 85 | Token.Number = Number 86 | 87 | # SQL specific tokens 88 | DML = Keyword.DML 89 | DDL = Keyword.DDL 90 | Command = Keyword.Command 91 | 92 | Group = Token.Group 93 | Group.Parenthesis = Token.Group.Parenthesis 94 | Group.Comment = Token.Group.Comment 95 | Group.Where = Token.Group.Where 96 | 97 | 98 | def is_token_subtype(ttype, other): 99 | """ 100 | Return True if ``ttype`` is a subtype of ``other``. 101 | 102 | exists for backwards compatibility. use ``ttype in other`` now. 103 | """ 104 | return ttype in other 105 | 106 | 107 | def string_to_tokentype(s): 108 | """ 109 | Convert a string into a token type:: 110 | 111 | >>> string_to_token('String.Double') 112 | Token.Literal.String.Double 113 | >>> string_to_token('Token.Literal.Number') 114 | Token.Literal.Number 115 | >>> string_to_token('') 116 | Token 117 | 118 | Tokens that are already tokens are returned unchanged: 119 | 120 | >>> string_to_token(String) 121 | Token.Literal.String 122 | """ 123 | if isinstance(s, _TokenType): 124 | return s 125 | if not s: 126 | return Token 127 | node = Token 128 | for item in s.split('.'): 129 | node = getattr(node, item) 130 | return node 131 | 132 | -------------------------------------------------------------------------------- /debug_toolbar/toolbar/loader.py: -------------------------------------------------------------------------------- 1 | """ 2 | The main DebugToolbar class that loads and renders the Toolbar. 3 | """ 4 | import os.path, os 5 | 6 | from django.conf import settings 7 | from django.template.loader import render_to_string 8 | from django.utils.datastructures import SortedDict 9 | from django.utils.safestring import mark_safe 10 | 11 | class DebugToolbar(object): 12 | 13 | def __init__(self, request): 14 | self.request = request 15 | self._panels = SortedDict() 16 | base_url = self.request.META.get('SCRIPT_NAME', '') 17 | self.config = { 18 | 'INTERCEPT_REDIRECTS': True, 19 | 'MEDIA_URL': u'%s/__debug__/m/' % base_url 20 | } 21 | # Check if settings has a DEBUG_TOOLBAR_CONFIG and updated config 22 | self.config.update(getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {})) 23 | self.template_context = { 24 | 'BASE_URL': base_url, # for backwards compatibility 25 | 'DEBUG_TOOLBAR_MEDIA_URL': self.config.get('MEDIA_URL'), 26 | } 27 | # Override this tuple by copying to settings.py as `DEBUG_TOOLBAR_PANELS` 28 | self.default_panels = ( 29 | 'debug_toolbar.panels.version.VersionDebugPanel', 30 | 'debug_toolbar.panels.timer.TimerDebugPanel', 31 | 'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel', 32 | 'debug_toolbar.panels.headers.HeaderDebugPanel', 33 | 'debug_toolbar.panels.request_vars.RequestVarsDebugPanel', 34 | 'debug_toolbar.panels.sql.SQLDebugPanel', 35 | 'debug_toolbar.panels.template.TemplateDebugPanel', 36 | #'debug_toolbar.panels.cache.CacheDebugPanel', 37 | 'debug_toolbar.panels.signals.SignalDebugPanel', 38 | 'debug_toolbar.panels.logger.LoggingPanel', 39 | ) 40 | self.load_panels() 41 | 42 | def _get_panels(self): 43 | return self._panels.values() 44 | panels = property(_get_panels) 45 | 46 | def get_panel(self, cls): 47 | return self._panels[cls] 48 | 49 | def load_panels(self): 50 | """ 51 | Populate debug panels 52 | """ 53 | from django.conf import settings 54 | from django.core import exceptions 55 | 56 | # Check if settings has a DEBUG_TOOLBAR_PANELS, otherwise use default 57 | if hasattr(settings, 'DEBUG_TOOLBAR_PANELS'): 58 | self.default_panels = settings.DEBUG_TOOLBAR_PANELS 59 | 60 | for panel_path in self.default_panels: 61 | try: 62 | dot = panel_path.rindex('.') 63 | except ValueError: 64 | raise exceptions.ImproperlyConfigured, '%s isn\'t a debug panel module' % panel_path 65 | panel_module, panel_classname = panel_path[:dot], panel_path[dot+1:] 66 | try: 67 | mod = __import__(panel_module, {}, {}, ['']) 68 | except ImportError, e: 69 | raise exceptions.ImproperlyConfigured, 'Error importing debug panel %s: "%s"' % (panel_module, e) 70 | try: 71 | panel_class = getattr(mod, panel_classname) 72 | except AttributeError: 73 | raise exceptions.ImproperlyConfigured, 'Toolbar Panel module "%s" does not define a "%s" class' % (panel_module, panel_classname) 74 | 75 | try: 76 | panel_instance = panel_class(context=self.template_context) 77 | except: 78 | raise # Bubble up problem loading panel 79 | 80 | self._panels[panel_class] = panel_instance 81 | 82 | def render_toolbar(self): 83 | """ 84 | Renders the overall Toolbar with panels inside. 85 | """ 86 | media_path = os.path.join(os.path.dirname(__file__), os.pardir, 'media', 'debug_toolbar') 87 | 88 | context = self.template_context.copy() 89 | context.update({ 90 | 'panels': self.panels, 91 | 'js': mark_safe(open(os.path.join(media_path, 'js', 'toolbar.min.js'), 'r').read()), 92 | 'css': mark_safe(open(os.path.join(media_path, 'css', 'toolbar.min.css'), 'r').read()), 93 | }) 94 | 95 | return render_to_string('debug_toolbar/base.html', context) 96 | -------------------------------------------------------------------------------- /debug_toolbar/utils/tracking/db.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import traceback 3 | 4 | from datetime import datetime 5 | 6 | from django.conf import settings 7 | from django.template import Node 8 | from django.utils import simplejson 9 | from django.utils.encoding import force_unicode 10 | from django.utils.hashcompat import sha_constructor 11 | 12 | from debug_toolbar.utils import ms_from_timedelta, tidy_stacktrace, get_template_info 13 | from debug_toolbar.utils.compat.db import connections 14 | # TODO:This should be set in the toolbar loader as a default and panels should 15 | # get a copy of the toolbar object with access to its config dictionary 16 | SQL_WARNING_THRESHOLD = getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}) \ 17 | .get('SQL_WARNING_THRESHOLD', 500) 18 | 19 | class CursorWrapper(object): 20 | """ 21 | Wraps a cursor and logs queries. 22 | """ 23 | 24 | def __init__(self, cursor, db, logger): 25 | self.cursor = cursor 26 | # Instance of a BaseDatabaseWrapper subclass 27 | self.db = db 28 | # logger must implement a ``record`` method 29 | self.logger = logger 30 | 31 | def execute(self, sql, params=()): 32 | start = datetime.now() 33 | try: 34 | return self.cursor.execute(sql, params) 35 | finally: 36 | stop = datetime.now() 37 | duration = ms_from_timedelta(stop - start) 38 | stacktrace = tidy_stacktrace(traceback.extract_stack()) 39 | _params = '' 40 | try: 41 | _params = simplejson.dumps([force_unicode(x, strings_only=True) for x in params]) 42 | except TypeError: 43 | pass # object not JSON serializable 44 | 45 | template_info = None 46 | cur_frame = sys._getframe().f_back 47 | try: 48 | while cur_frame is not None: 49 | if cur_frame.f_code.co_name == 'render': 50 | node = cur_frame.f_locals['self'] 51 | if isinstance(node, Node): 52 | template_info = get_template_info(node.source) 53 | break 54 | cur_frame = cur_frame.f_back 55 | except: 56 | pass 57 | del cur_frame 58 | 59 | alias = getattr(self, 'alias', 'default') 60 | conn = connections[alias].connection 61 | # HACK: avoid imports 62 | if conn: 63 | engine = conn.__class__.__module__.split('.', 1)[0] 64 | else: 65 | engine = 'unknown' 66 | 67 | params = { 68 | 'engine': engine, 69 | 'alias': alias, 70 | 'sql': self.db.ops.last_executed_query(self.cursor, sql, params), 71 | 'duration': duration, 72 | 'raw_sql': sql, 73 | 'params': _params, 74 | 'hash': sha_constructor(settings.SECRET_KEY + sql + _params).hexdigest(), 75 | 'stacktrace': stacktrace, 76 | 'start_time': start, 77 | 'stop_time': stop, 78 | 'is_slow': (duration > SQL_WARNING_THRESHOLD), 79 | 'is_select': sql.lower().strip().startswith('select'), 80 | 'template_info': template_info, 81 | } 82 | 83 | if engine == 'psycopg2': 84 | params.update({ 85 | 'trans_id': self.logger.get_transaction_id(alias), 86 | 'trans_status': conn.get_transaction_status(), 87 | 'iso_level': conn.isolation_level, 88 | 'encoding': conn.encoding, 89 | }) 90 | 91 | 92 | # We keep `sql` to maintain backwards compatibility 93 | self.logger.record(**params) 94 | 95 | def executemany(self, sql, param_list): 96 | return self.cursor.executemany(sql, param_list) 97 | 98 | def __getattr__(self, attr): 99 | if attr in self.__dict__: 100 | return self.__dict__[attr] 101 | else: 102 | return getattr(self.cursor, attr) 103 | 104 | def __iter__(self): 105 | return iter(self.cursor) -------------------------------------------------------------------------------- /debug_toolbar/panels/logger.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import logging 3 | try: 4 | import threading 5 | except ImportError: 6 | threading = None 7 | from django.template.loader import render_to_string 8 | from django.utils.translation import ugettext_lazy as _ 9 | from debug_toolbar.panels import DebugPanel 10 | 11 | 12 | class LogCollector(object): 13 | def __init__(self): 14 | if threading is None: 15 | raise NotImplementedError("threading module is not available, \ 16 | the logging panel cannot be used without it") 17 | self.records = {} # a dictionary that maps threads to log records 18 | 19 | def add_record(self, record, thread=None): 20 | # Avoid logging SQL queries since they are already in the SQL panel 21 | # TODO: Make this check whether SQL panel is enabled 22 | if record.get('channel', '') == 'django.db.backends': 23 | return 24 | 25 | self.get_records(thread).append(record) 26 | 27 | def get_records(self, thread=None): 28 | """ 29 | Returns a list of records for the provided thread, of if none is provided, 30 | returns a list for the current thread. 31 | """ 32 | if thread is None: 33 | thread = threading.currentThread() 34 | if thread not in self.records: 35 | self.records[thread] = [] 36 | return self.records[thread] 37 | 38 | def clear_records(self, thread=None): 39 | if thread is None: 40 | thread = threading.currentThread() 41 | if thread in self.records: 42 | del self.records[thread] 43 | 44 | 45 | class ThreadTrackingHandler(logging.Handler): 46 | def __init__(self, collector): 47 | logging.Handler.__init__(self) 48 | self.collector = collector 49 | 50 | def emit(self, record): 51 | record = { 52 | 'message': record.getMessage(), 53 | 'time': datetime.datetime.fromtimestamp(record.created), 54 | 'level': record.levelname, 55 | 'file': record.pathname, 56 | 'line': record.lineno, 57 | 'channel': record.name, 58 | } 59 | self.collector.add_record(record) 60 | 61 | 62 | collector = LogCollector() 63 | logging_handler = ThreadTrackingHandler(collector) 64 | logging.root.setLevel(logging.NOTSET) 65 | logging.root.addHandler(logging_handler) # register with logging 66 | 67 | try: 68 | import logbook 69 | logbook_supported = True 70 | except ImportError: 71 | # logbook support is optional, so fail silently 72 | logbook_supported = False 73 | 74 | if logbook_supported: 75 | class LogbookThreadTrackingHandler(logbook.handlers.Handler): 76 | def __init__(self, collector): 77 | logbook.handlers.Handler.__init__(self, bubble=True) 78 | self.collector = collector 79 | 80 | def emit(self, record): 81 | record = { 82 | 'message': record.message, 83 | 'time': record.time, 84 | 'level': record.level_name, 85 | 'file': record.filename, 86 | 'line': record.lineno, 87 | 'channel': record.channel, 88 | } 89 | self.collector.add_record(record) 90 | 91 | 92 | logbook_handler = LogbookThreadTrackingHandler(collector) 93 | logbook_handler.push_application() # register with logbook 94 | 95 | class LoggingPanel(DebugPanel): 96 | name = 'Logging' 97 | has_content = True 98 | 99 | def process_request(self, request): 100 | collector.clear_records() 101 | 102 | def get_and_delete(self): 103 | records = collector.get_records() 104 | collector.clear_records() 105 | return records 106 | 107 | def nav_title(self): 108 | return _("Logging") 109 | 110 | def nav_subtitle(self): 111 | # FIXME l10n: use ngettext 112 | return "%s message%s" % (len(collector.get_records()), (len(collector.get_records()) == 1) and '' or 's') 113 | 114 | def title(self): 115 | return _('Log Messages') 116 | 117 | def url(self): 118 | return '' 119 | 120 | def content(self): 121 | records = self.get_and_delete() 122 | context = self.context.copy() 123 | context.update({'records': records}) 124 | 125 | return render_to_string('debug_toolbar/panels/logger.html', context) 126 | 127 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/sql.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 || 18 | | {% trans 'Query' %} | 19 |{% trans 'Timeline' %} | 20 |{% trans 'Time (ms)' %} | 21 |{% trans "Action" %} | 22 ||||
|---|---|---|---|---|---|---|---|
| 28 | | 29 | + 30 | | 31 |
32 |
33 |
35 | {{ query.sql|safe }}
34 | |
36 |
37 | {{ query.width_ratio }}% |
39 | 40 | {{ query.duration|floatformat:"2" }} 41 | | 42 |43 | {% if query.params %} 44 | {% if query.is_select %} 45 | Sel 46 | Expl 47 | {% ifequal query.engine 'mysql' %} 48 | Prof 49 | {% endifequal %} 50 | {% endif %} 51 | {% endif %} 52 | | 53 |||
| 56 | |
57 |
58 |
80 | Connection: {{ query.alias }} 59 | {% if query.iso_level %} 60 |Isolation Level: {{ query.iso_level }} 61 | {% endif %} 62 | {% if query.trans_status %} 63 |Transaction Status: {{ query.trans_status }} 64 | {% endif %} 65 | {% if query.stacktrace %} 66 |{{ query.stacktrace }}
67 | {% endif %}
68 | {% if query.template_info %}
69 |
{{ query.template_info.name|default:"(unknown)" }} 78 | {% endif %} 79 | |
81 | ||||||
No SQL queries were recorded during this request.
87 | {% endif %} 88 | -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/js/jquery.cookie.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Cookie plugin 3 | * 4 | * Copyright (c) 2006 Klaus Hartl (stilbuero.de) 5 | * Dual licensed under the MIT and GPL licenses: 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * http://www.gnu.org/licenses/gpl.html 8 | * 9 | */ 10 | 11 | /** 12 | * Create a cookie with the given name and value and other optional parameters. 13 | * 14 | * @example $.cookie('the_cookie', 'the_value'); 15 | * @desc Set the value of a cookie. 16 | * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); 17 | * @desc Create a cookie with all available options. 18 | * @example $.cookie('the_cookie', 'the_value'); 19 | * @desc Create a session cookie. 20 | * @example $.cookie('the_cookie', null); 21 | * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain 22 | * used when the cookie was set. 23 | * 24 | * @param String name The name of the cookie. 25 | * @param String value The value of the cookie. 26 | * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. 27 | * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. 28 | * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. 29 | * If set to null or omitted, the cookie will be a session cookie and will not be retained 30 | * when the the browser exits. 31 | * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). 32 | * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). 33 | * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will 34 | * require a secure protocol (like HTTPS). 35 | * @type undefined 36 | * 37 | * @name $.cookie 38 | * @cat Plugins/Cookie 39 | * @author Klaus Hartl/klaus.hartl@stilbuero.de 40 | */ 41 | 42 | /** 43 | * Get the value of a cookie with the given name. 44 | * 45 | * @example $.cookie('the_cookie'); 46 | * @desc Get the value of a cookie. 47 | * 48 | * @param String name The name of the cookie. 49 | * @return The value of the cookie. 50 | * @type String 51 | * 52 | * @name $.cookie 53 | * @cat Plugins/Cookie 54 | * @author Klaus Hartl/klaus.hartl@stilbuero.de 55 | */ 56 | jQuery.cookie = function(name, value, options) { 57 | if (typeof value != 'undefined') { // name and value given, set cookie 58 | options = options || {}; 59 | if (value === null) { 60 | value = ''; 61 | options.expires = -1; 62 | } 63 | var expires = ''; 64 | if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { 65 | var date; 66 | if (typeof options.expires == 'number') { 67 | date = new Date(); 68 | date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); 69 | } else { 70 | date = options.expires; 71 | } 72 | expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE 73 | } 74 | // CAUTION: Needed to parenthesize options.path and options.domain 75 | // in the following expressions, otherwise they evaluate to undefined 76 | // in the packed version for some reason... 77 | var path = options.path ? '; path=' + (options.path) : ''; 78 | var domain = options.domain ? '; domain=' + (options.domain) : ''; 79 | var secure = options.secure ? '; secure' : ''; 80 | document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); 81 | } else { // only name given, get cookie 82 | var cookieValue = null; 83 | if (document.cookie && document.cookie != '') { 84 | var cookies = document.cookie.split(';'); 85 | for (var i = 0; i < cookies.length; i++) { 86 | var cookie = jQuery.trim(cookies[i]); 87 | // Does this cookie string begin with the name we want? 88 | if (cookie.substring(0, name.length + 1) == (name + '=')) { 89 | cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 90 | break; 91 | } 92 | } 93 | } 94 | return cookieValue; 95 | } 96 | }; -------------------------------------------------------------------------------- /debug_toolbar/utils/sqlparse/formatter.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2008 Andi Albrecht, albrecht.andi@gmail.com 2 | # 3 | # This module is part of python-sqlparse and is released under 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php. 5 | 6 | """SQL formatter""" 7 | 8 | from debug_toolbar.utils.sqlparse import SQLParseError 9 | from debug_toolbar.utils.sqlparse import filters 10 | 11 | 12 | def validate_options(options): 13 | """Validates options.""" 14 | kwcase = options.get('keyword_case', None) 15 | if kwcase not in [None, 'upper', 'lower', 'capitalize']: 16 | raise SQLParseError('Invalid value for keyword_case: %r' % kwcase) 17 | 18 | idcase = options.get('identifier_case', None) 19 | if idcase not in [None, 'upper', 'lower', 'capitalize']: 20 | raise SQLParseError('Invalid value for identifier_case: %r' % idcase) 21 | 22 | ofrmt = options.get('output_format', None) 23 | if ofrmt not in [None, 'sql', 'python', 'php']: 24 | raise SQLParseError('Unknown output format: %r' % ofrmt) 25 | 26 | strip_comments = options.get('strip_comments', False) 27 | if strip_comments not in [True, False]: 28 | raise SQLParseError('Invalid value for strip_comments: %r' 29 | % strip_comments) 30 | 31 | strip_ws = options.get('strip_whitespace', False) 32 | if strip_ws not in [True, False]: 33 | raise SQLParseError('Invalid value for strip_whitespace: %r' 34 | % strip_ws) 35 | 36 | reindent = options.get('reindent', False) 37 | if reindent not in [True, False]: 38 | raise SQLParseError('Invalid value for reindent: %r' 39 | % reindent) 40 | elif reindent: 41 | options['strip_whitespace'] = True 42 | indent_tabs = options.get('indent_tabs', False) 43 | if indent_tabs not in [True, False]: 44 | raise SQLParseError('Invalid value for indent_tabs: %r' % indent_tabs) 45 | elif indent_tabs: 46 | options['indent_char'] = '\t' 47 | else: 48 | options['indent_char'] = ' ' 49 | indent_width = options.get('indent_width', 2) 50 | try: 51 | indent_width = int(indent_width) 52 | except (TypeError, ValueError): 53 | raise SQLParseError('indent_width requires an integer') 54 | if indent_width < 1: 55 | raise SQLParseError('indent_width requires an positive integer') 56 | options['indent_width'] = indent_width 57 | 58 | right_margin = options.get('right_margin', None) 59 | if right_margin is not None: 60 | try: 61 | right_margin = int(right_margin) 62 | except (TypeError, ValueError): 63 | raise SQLParseError('right_margin requires an integer') 64 | if right_margin < 10: 65 | raise SQLParseError('right_margin requires an integer > 10') 66 | options['right_margin'] = right_margin 67 | 68 | return options 69 | 70 | 71 | def build_filter_stack(stack, options): 72 | """Setup and return a filter stack. 73 | 74 | Args: 75 | stack: :class:`~sqlparse.filters.FilterStack` instance 76 | options: Dictionary with options validated by validate_options. 77 | """ 78 | # Token filter 79 | if 'keyword_case' in options: 80 | stack.preprocess.append( 81 | filters.KeywordCaseFilter(options['keyword_case'])) 82 | 83 | if 'identifier_case' in options: 84 | stack.preprocess.append( 85 | filters.IdentifierCaseFilter(options['identifier_case'])) 86 | 87 | # After grouping 88 | if options.get('strip_comments', False): 89 | stack.enable_grouping() 90 | stack.stmtprocess.append(filters.StripCommentsFilter()) 91 | 92 | if (options.get('strip_whitespace', False) 93 | or options.get('reindent', False)): 94 | stack.enable_grouping() 95 | stack.stmtprocess.append(filters.StripWhitespaceFilter()) 96 | 97 | if options.get('reindent', False): 98 | stack.enable_grouping() 99 | stack.stmtprocess.append( 100 | filters.ReindentFilter(char=options['indent_char'], 101 | width=options['indent_width'])) 102 | 103 | if options.get('right_margin', False): 104 | stack.enable_grouping() 105 | stack.stmtprocess.append( 106 | filters.RightMarginFilter(width=options['right_margin'])) 107 | 108 | # Serializer 109 | if options.get('output_format'): 110 | frmt = options['output_format'] 111 | if frmt.lower() == 'php': 112 | fltr = filters.OutputPHPFilter() 113 | elif frmt.lower() == 'python': 114 | fltr = filters.OutputPythonFilter() 115 | else: 116 | fltr = None 117 | if fltr is not None: 118 | stack.postprocess.append(fltr) 119 | 120 | return stack 121 | 122 | 123 | -------------------------------------------------------------------------------- /debug_toolbar/middleware.py: -------------------------------------------------------------------------------- 1 | """ 2 | Debug Toolbar middleware 3 | """ 4 | import thread 5 | 6 | from django.conf import settings 7 | from django.http import HttpResponseRedirect 8 | from django.shortcuts import render_to_response 9 | from django.utils.encoding import smart_unicode 10 | from django.conf.urls.defaults import include, patterns 11 | 12 | import debug_toolbar.urls 13 | from debug_toolbar.toolbar.loader import DebugToolbar 14 | 15 | _HTML_TYPES = ('text/html', 'application/xhtml+xml') 16 | 17 | def replace_insensitive(string, target, replacement): 18 | """ 19 | Similar to string.replace() but is case insensitive 20 | Code borrowed from: http://forums.devshed.com/python-programming-11/case-insensitive-string-replace-490921.html 21 | """ 22 | no_case = string.lower() 23 | index = no_case.rfind(target.lower()) 24 | if index >= 0: 25 | return string[:index] + replacement + string[index + len(target):] 26 | else: # no results so return the original string 27 | return string 28 | 29 | class DebugToolbarMiddleware(object): 30 | """ 31 | Middleware to set up Debug Toolbar on incoming request and render toolbar 32 | on outgoing response. 33 | """ 34 | debug_toolbars = {} 35 | 36 | @classmethod 37 | def get_current(cls): 38 | return cls.debug_toolbars.get(thread.get_ident()) 39 | 40 | def __init__(self): 41 | self.override_url = True 42 | 43 | # Set method to use to decide to show toolbar 44 | self.show_toolbar = self._show_toolbar # default 45 | 46 | # The tag to attach the toolbar to 47 | self.tag= u'