Codebase list python-django-debug-toolbar / 1ecc720
Imported Upstream version 1.4 Andrew Starr-Bochicchio 8 years ago
96 changed file(s) with 1377 addition(s) and 815 deletion(s). Raw diff Collapse all Expand all
00 language: python
1 sudo: false
12 python:
2 - "2.6"
33 - "2.7"
44 - "3.2"
55 - "3.3"
66 - "3.4"
7 - "3.5"
78 env:
8 - DJANGO_VERSION=1.4.10
9 - DJANGO_VERSION=1.5.5
10 - DJANGO_VERSION=1.6.1
9 - DJANGO="Django>=1.7.0,<1.8.0"
10 - DJANGO="Django>=1.8.0,<1.9.0"
11 - DJANGO="https://www.djangoproject.com/download/1.9a1/tarball/"
1112 matrix:
1213 exclude:
1314 - python: "3.2"
14 env: DJANGO_VERSION=1.4.10
15 env: DJANGO="https://www.djangoproject.com/download/1.9a1/tarball/"
1516 - python: "3.3"
16 env: DJANGO_VERSION=1.4.10
17 - python: "3.4"
18 env: DJANGO_VERSION=1.4.10
17 env: DJANGO="https://www.djangoproject.com/download/1.9a1/tarball/"
18 - python: "3.5"
19 env: DJANGO="Django>=1.7.0,<1.8.0"
20 - python: "3.5"
21 env: DJANGO="Django>=1.8.0,<1.9.0"
1922 install:
2023 - pip install -e .
21 - pip install Django==$DJANGO_VERSION django-discover-runner sqlparse
24 - travis_retry pip install $DJANGO django-discover-runner sqlparse
2225 script: make test
22 flake8:
33 flake8 debug_toolbar example tests
44
5 isort:
6 isort -rc debug_toolbar example tests
7
8 isort_check_only:
9 isort -rc -c debug_toolbar example tests
10
511 example:
612 DJANGO_SETTINGS_MODULE=example.settings \
7 django-admin.py runserver
13 django-admin runserver
814
915 test:
1016 DJANGO_SETTINGS_MODULE=tests.settings \
11 django-admin.py test tests
17 django-admin test tests
1218
1319 test_selenium:
1420 DJANGO_SELENIUM_TESTS=true DJANGO_SETTINGS_MODULE=tests.settings \
15 django-admin.py test tests
21 django-admin test tests
1622
1723 coverage:
1824 coverage erase
1925 DJANGO_SETTINGS_MODULE=tests.settings \
20 coverage run --branch --source=debug_toolbar `which django-admin.py` test tests
26 coverage run --branch --source=debug_toolbar `which django-admin` test tests
2127 coverage html
2228
2329 translatable_strings:
24 cd debug_toolbar && django-admin.py makemessages -l en --no-obsolete
30 cd debug_toolbar && django-admin makemessages -l en --no-obsolete
2531 @echo "Please commit changes and run 'tx push -s' (or wait for Transifex to pick them)"
2632
2733 update_translations:
2834 tx pull -a --minimum-perc=10
29 cd debug_toolbar && django-admin.py compilemessages
35 cd debug_toolbar && django-admin compilemessages
1818 In addition to the built-in panels, a number of third-party panels are
1919 contributed by the community.
2020
21 The current version of the Debug Toolbar is 1.2.1. It works on Django 1.4 to 1.7.
22
23 If you're using Django 1.4, you will need Django ≥ 1.4.2 and Python ≥ 2.6.5.
24 If you're using Django ≥ 1.5, there aren't any restrictions.
21 The current version of the Debug Toolbar is 1.4. It works on Django ≥ 1.7.
2522
2623 Documentation, including installation and configuration instructions, is
2724 available at http://django-debug-toolbar.readthedocs.org/.
00 from __future__ import absolute_import, unicode_literals
1
21
32 __all__ = ['VERSION']
43
1212 def ready(self):
1313 if dt_settings.PATCH_SETTINGS:
1414 dt_settings.patch_all()
15 dt_settings.check_middleware()
0 """
1 This file exists to contain all Django and Python compatibility issues.
2
3 In order to avoid circular references, nothing should be imported from
4 debug_toolbar.
5 """
6
7 from django.conf import settings
8 from django.core.exceptions import ImproperlyConfigured
9
10 try:
11 from django.template.base import linebreak_iter # NOQA
12 except ImportError: # Django < 1.9
13 from django.views.debug import linebreak_iter # NOQA
14
15 try:
16 from django.template.engine import Engine
17 except ImportError: # Django < 1.8
18 Engine = None
19 from django.template.context import get_standard_processors # NOQA
20 from django.template.loader import find_template_loader # NOQA
21
22
23 def get_template_dirs():
24 """Compatibility method to fetch the template directories."""
25 if Engine:
26 try:
27 engine = Engine.get_default()
28 except ImproperlyConfigured:
29 template_dirs = []
30 else:
31 template_dirs = engine.dirs
32 else: # Django < 1.8
33 template_dirs = settings.TEMPLATE_DIRS
34 return template_dirs
35
36
37 def get_template_loaders():
38 """Compatibility method to fetch the template loaders."""
39 if Engine:
40 try:
41 engine = Engine.get_default()
42 except ImproperlyConfigured:
43 loaders = []
44 else:
45 loaders = engine.template_loaders
46 else: # Django < 1.8
47 loaders = [
48 find_template_loader(loader_name)
49 for loader_name in settings.TEMPLATE_LOADERS]
50 return loaders
51
52
53 def get_template_context_processors():
54 """Compatibility method to fetch the template context processors."""
55 if Engine:
56 try:
57 engine = Engine.get_default()
58 except ImproperlyConfigured:
59 context_processors = []
60 else:
61 context_processors = engine.template_context_processors
62 else: # Django < 1.8
63 context_processors = get_standard_processors()
64 return context_processors
55 msgstr ""
66 "Project-Id-Version: Django Debug Toolbar\n"
77 "Report-Msgid-Bugs-To: \n"
8 "POT-Creation-Date: 2014-04-25 21:52+0200\n"
8 "POT-Creation-Date: 2015-07-06 16:50-0400\n"
99 "PO-Revision-Date: 2012-03-31 20:10+0000\n"
1010 "Last-Translator: \n"
1111 "Language-Team: \n"
1919 msgid "Debug Toolbar"
2020 msgstr ""
2121
22 #: views.py:14
23 msgid ""
24 "Data for this panel isn't available anymore. Please reload the page and "
25 "retry."
26 msgstr ""
27
28 #: panels/cache.py:191
22 #: panels/cache.py:209
2923 msgid "Cache"
3024 msgstr ""
3125
32 #: panels/cache.py:196
26 #: panels/cache.py:214
3327 #, python-format
3428 msgid "%(cache_calls)d call in %(time).2fms"
3529 msgid_plural "%(cache_calls)d calls in %(time).2fms"
3630 msgstr[0] ""
3731 msgstr[1] ""
3832
39 #: panels/cache.py:204
33 #: panels/cache.py:222
4034 #, python-format
4135 msgid "Cache calls from %(count)d backend"
4236 msgid_plural "Cache calls from %(count)d backends"
4337 msgstr[0] ""
4438 msgstr[1] ""
4539
46 #: panels/headers.py:35
40 #: panels/headers.py:33
4741 msgid "Headers"
4842 msgstr ""
4943
50 #: panels/logging.py:64
44 #: panels/logging.py:63
5145 msgid "Logging"
5246 msgstr ""
5347
54 #: panels/logging.py:70
48 #: panels/logging.py:69
5549 #, python-format
5650 msgid "%(count)s message"
5751 msgid_plural "%(count)s messages"
5852 msgstr[0] ""
5953 msgstr[1] ""
6054
61 #: panels/logging.py:73
55 #: panels/logging.py:72
6256 msgid "Log messages"
6357 msgstr ""
6458
8276 msgid "<unavailable>"
8377 msgstr ""
8478
79 #: panels/settings.py:17
80 msgid "Settings"
81 msgstr ""
82
8583 #: panels/settings.py:20
86 msgid "Settings"
87 msgstr ""
88
89 #: panels/settings.py:23
9084 #, python-format
9185 msgid "Settings from <code>%s</code>"
9286 msgstr ""
9387
94 #: panels/signals.py:45
88 #: panels/signals.py:42
9589 #, python-format
9690 msgid "%(num_receivers)d receiver of 1 signal"
9791 msgid_plural "%(num_receivers)d receivers of 1 signal"
9892 msgstr[0] ""
9993 msgstr[1] ""
10094
101 #: panels/signals.py:48
95 #: panels/signals.py:45
10296 #, python-format
10397 msgid "%(num_receivers)d receiver of %(num_signals)d signals"
10498 msgid_plural "%(num_receivers)d receivers of %(num_signals)d signals"
10599 msgstr[0] ""
106100 msgstr[1] ""
107101
108 #: panels/signals.py:53
102 #: panels/signals.py:50
109103 msgid "Signals"
110104 msgstr ""
111105
112 #: panels/staticfiles.py:89
106 #: panels/sql/panel.py:23
107 msgid "Autocommit"
108 msgstr ""
109
110 #: panels/sql/panel.py:24
111 msgid "Read uncommitted"
112 msgstr ""
113
114 #: panels/sql/panel.py:25
115 msgid "Read committed"
116 msgstr ""
117
118 #: panels/sql/panel.py:26
119 msgid "Repeatable read"
120 msgstr ""
121
122 #: panels/sql/panel.py:27
123 msgid "Serializable"
124 msgstr ""
125
126 #: panels/sql/panel.py:38
127 msgid "Idle"
128 msgstr ""
129
130 #: panels/sql/panel.py:39
131 msgid "Active"
132 msgstr ""
133
134 #: panels/sql/panel.py:40
135 msgid "In transaction"
136 msgstr ""
137
138 #: panels/sql/panel.py:41
139 msgid "In error"
140 msgstr ""
141
142 #: panels/sql/panel.py:42
143 msgid "Unknown"
144 msgstr ""
145
146 #: panels/sql/panel.py:106
147 msgid "SQL"
148 msgstr ""
149
150 #: panels/staticfiles.py:86
113151 #, python-format
114152 msgid "Static files (%(num_found)s found, %(num_used)s used)"
115153 msgstr ""
116154
117 #: panels/staticfiles.py:107
155 #: panels/staticfiles.py:104
118156 msgid "Static files"
119157 msgstr ""
120158
121 #: panels/staticfiles.py:112
159 #: panels/staticfiles.py:109
122160 #, python-format
123161 msgid "%(num_used)s file used"
124162 msgid_plural "%(num_used)s files used"
125163 msgstr[0] ""
126164 msgstr[1] ""
165
166 #: panels/templates/panel.py:171
167 msgid "Templates"
168 msgstr ""
169
170 #: panels/templates/panel.py:176
171 #, python-format
172 msgid "Templates (%(num_templates)s rendered)"
173 msgstr ""
174
175 #: panels/templates/panel.py:207
176 msgid "No origin"
177 msgstr ""
127178
128179 #: panels/timer.py:23
129180 #, python-format
187238 msgid "%(vcsw)d voluntary, %(ivcsw)d involuntary"
188239 msgstr ""
189240
190 #: panels/versions.py:25
241 #: panels/versions.py:21
191242 msgid "Versions"
192 msgstr ""
193
194 #: panels/sql/panel.py:22
195 msgid "Autocommit"
196 msgstr ""
197
198 #: panels/sql/panel.py:23
199 msgid "Read uncommitted"
200 msgstr ""
201
202 #: panels/sql/panel.py:24
203 msgid "Read committed"
204 msgstr ""
205
206 #: panels/sql/panel.py:25
207 msgid "Repeatable read"
208 msgstr ""
209
210 #: panels/sql/panel.py:26
211 msgid "Serializable"
212 msgstr ""
213
214 #: panels/sql/panel.py:37
215 msgid "Idle"
216 msgstr ""
217
218 #: panels/sql/panel.py:38
219 msgid "Active"
220 msgstr ""
221
222 #: panels/sql/panel.py:39
223 msgid "In transaction"
224 msgstr ""
225
226 #: panels/sql/panel.py:40
227 msgid "In error"
228 msgstr ""
229
230 #: panels/sql/panel.py:41
231 msgid "Unknown"
232 msgstr ""
233
234 #: panels/sql/panel.py:105
235 msgid "SQL"
236 msgstr ""
237
238 #: panels/templates/panel.py:141
239 msgid "Templates"
240 msgstr ""
241
242 #: panels/templates/panel.py:146
243 #, python-format
244 msgid "Templates (%(num_templates)s rendered)"
245243 msgstr ""
246244
247245 #: templates/debug_toolbar/base.html:19
264262 msgid "Show toolbar"
265263 msgstr ""
266264
267 #: templates/debug_toolbar/base.html:53
268 msgid "Close"
269 msgstr ""
270
271 #: templates/debug_toolbar/redirect.html:8
272 msgid "Location:"
273 msgstr ""
274
275 #: templates/debug_toolbar/redirect.html:10
276 msgid ""
277 "The Django Debug Toolbar has intercepted a redirect to the above URL for "
278 "debug viewing purposes. You can click the above link to continue with the "
279 "redirect as normal."
280 msgstr ""
281
282265 #: templates/debug_toolbar/panels/cache.html:2
283266 msgid "Summary"
284267 msgstr ""
308291 msgstr ""
309292
310293 #: templates/debug_toolbar/panels/cache.html:43
311 #: templates/debug_toolbar/panels/sql.html:20
294 #: templates/debug_toolbar/panels/sql.html:23
312295 msgid "Time (ms)"
313296 msgstr ""
314297
482465 msgstr[0] ""
483466 msgstr[1] ""
484467
485 #: templates/debug_toolbar/panels/sql.html:18
468 #: templates/debug_toolbar/panels/sql.html:9
469 #, python-format
470 msgid "including %(dupes)s duplicates"
471 msgstr ""
472
473 #: templates/debug_toolbar/panels/sql.html:21
486474 msgid "Query"
487475 msgstr ""
488476
489 #: templates/debug_toolbar/panels/sql.html:19
477 #: templates/debug_toolbar/panels/sql.html:22
490478 #: templates/debug_toolbar/panels/timer.html:36
491479 msgid "Timeline"
492480 msgstr ""
493481
494 #: templates/debug_toolbar/panels/sql.html:21
482 #: templates/debug_toolbar/panels/sql.html:24
495483 msgid "Action"
496484 msgstr ""
497485
498 #: templates/debug_toolbar/panels/sql.html:64
486 #: templates/debug_toolbar/panels/sql.html:39
487 #, python-format
488 msgid "Duplicated %(dupes)s times."
489 msgstr ""
490
491 #: templates/debug_toolbar/panels/sql.html:71
499492 msgid "Connection:"
500493 msgstr ""
501494
502 #: templates/debug_toolbar/panels/sql.html:66
495 #: templates/debug_toolbar/panels/sql.html:73
503496 msgid "Isolation level:"
504497 msgstr ""
505498
506 #: templates/debug_toolbar/panels/sql.html:69
499 #: templates/debug_toolbar/panels/sql.html:76
507500 msgid "Transaction status:"
508501 msgstr ""
509502
510 #: templates/debug_toolbar/panels/sql.html:83
503 #: templates/debug_toolbar/panels/sql.html:90
511504 msgid "(unknown)"
512505 msgstr ""
513506
514 #: templates/debug_toolbar/panels/sql.html:92
507 #: templates/debug_toolbar/panels/sql.html:99
515508 msgid "No SQL queries were recorded during this request."
516 msgstr ""
517
518 #: templates/debug_toolbar/panels/sql_explain.html:3
519 #: templates/debug_toolbar/panels/sql_profile.html:3
520 #: templates/debug_toolbar/panels/sql_select.html:3
521 #: templates/debug_toolbar/panels/template_source.html:3
522 msgid "Back"
523509 msgstr ""
524510
525511 #: templates/debug_toolbar/panels/sql_explain.html:4
651637 #: templates/debug_toolbar/panels/versions.html:6
652638 msgid "Version"
653639 msgstr ""
640
641 #: templates/debug_toolbar/redirect.html:8
642 msgid "Location:"
643 msgstr ""
644
645 #: templates/debug_toolbar/redirect.html:10
646 msgid ""
647 "The Django Debug Toolbar has intercepted a redirect to the above URL for "
648 "debug viewing purposes. You can click the above link to continue with the "
649 "redirect as normal."
650 msgstr ""
651
652 #: views.py:14
653 msgid ""
654 "Data for this panel isn't available anymore. Please reload the page and "
655 "retry."
656 msgstr ""
11
22 from time import time
33
4 import sqlparse
45 # 'debugsqlshell' is the same as the 'shell'.
5 from django.core.management.commands.shell import Command # noqa
6 try:
7 from django.db.backends import utils
8 except ImportError:
9 from django.db.backends import util as utils
10
11 import sqlparse
6 from django.core.management.commands.shell import Command # noqa
7 from django.db.backends import utils as db_backends_utils
128
139
14 class PrintQueryWrapper(utils.CursorDebugWrapper):
10 class PrintQueryWrapper(db_backends_utils.CursorDebugWrapper):
1511 def execute(self, sql, params=()):
1612 start_time = time()
1713 try:
2420 print('%s [%.2fms]' % (formatted_sql, duration))
2521
2622
27 utils.CursorDebugWrapper = PrintQueryWrapper
23 db_backends_utils.CursorDebugWrapper = PrintQueryWrapper
77 import threading
88
99 from django.conf import settings
10 from django.utils import six
1011 from django.utils.encoding import force_text
11 from django.utils.importlib import import_module
12 from django.utils.module_loading import import_string
1213
14 from debug_toolbar import settings as dt_settings
1315 from debug_toolbar.toolbar import DebugToolbar
14 from debug_toolbar import settings as dt_settings
1516
1617 _HTML_TYPES = ('text/html', 'application/xhtml+xml')
1718 # Handles python threading module bug - http://bugs.python.org/issue14308
3839 """
3940 debug_toolbars = {}
4041
42 def __init__(self):
43 # If SHOW_TOOLBAR_CALLBACK is a string, which is the recommended
44 # setup, resolve it to the corresponding callable.
45 func_or_path = dt_settings.CONFIG['SHOW_TOOLBAR_CALLBACK']
46 if isinstance(func_or_path, six.string_types):
47 self.show_toolbar = import_string(func_or_path)
48 else:
49 self.show_toolbar = func_or_path
50
4151 def process_request(self, request):
4252 # Decide whether the toolbar is active for this request.
43 func_path = dt_settings.CONFIG['SHOW_TOOLBAR_CALLBACK']
44 # Replace this with import_by_path in Django >= 1.6.
45 mod_path, func_name = func_path.rsplit('.', 1)
46 show_toolbar = getattr(import_module(mod_path), func_name)
47 if not show_toolbar(request):
53 if not self.show_toolbar(request):
4854 return
4955
5056 toolbar = DebugToolbar(request)
117123 # When the body ends with a newline, there's two trailing groups.
118124 bits.append(''.join(m[0] for m in matches if m[1] == ''))
119125 if len(bits) > 1:
126 # When the toolbar will be inserted for sure, generate the stats.
127 for panel in reversed(toolbar.enabled_panels):
128 panel.generate_stats(request, response)
129
120130 bits[-2] += toolbar.render_toolbar()
121131 response.content = insert_before.join(bits)
122132 if response.get('Content-Length', None):
+0
-9
debug_toolbar/models.py less more
0 from __future__ import absolute_import, unicode_literals
1
2 import django
3
4 from debug_toolbar import settings as dt_settings
5
6
7 if dt_settings.PATCH_SETTINGS and django.VERSION[:2] < (1, 7):
8 dt_settings.patch_all()
2323 @property
2424 def enabled(self):
2525 # Check to see if settings has a default value for it
26 if get_name_from_obj(self) in dt_settings.CONFIG['DISABLE_PANELS']:
26 disabled_panels = dt_settings.CONFIG['DISABLE_PANELS']
27 panel_path = get_name_from_obj(self)
28 # Some panels such as the SQLPanel and TemplatesPanel exist in a
29 # panel module, but can be disabled without panel in the path.
30 # For that reason, replace .panel. in the path and check for that
31 # value in the disabled panels as well.
32 disable_panel = (
33 panel_path in disabled_panels or
34 panel_path.replace('.panel.', '.') in disabled_panels)
35 if disable_panel:
2736 default = 'off'
2837 else:
2938 default = 'on'
157166
158167 def process_response(self, request, response):
159168 """
160 Like process_response in Django's middleware.
169 Like process_response in Django's middleware. This is similar to
170 :meth:`generate_stats <debug_toolbar.panels.Panel.generate_stats>`,
171 but will be executed on every request. It should be used when either
172 the logic needs to be executed on every request or it needs to change
173 the response entirely, such as :class:`RedirectsPanel`.
161174
162175 Write panel logic related to the response there. Post-process data
163176 gathered while the view executed. Save data with :meth:`record_stats`.
177
178 Return a response to overwrite the existing response.
179 """
180
181 def generate_stats(self, request, response):
182 """
183 Similar to :meth:`process_response
184 <debug_toolbar.panels.Panel.process_response>`,
185 but may not be executed on every request. This will only be called if
186 the toolbar will be inserted into the request.
187
188 Write panel logic related to the response there. Post-process data
189 gathered while the view executed. Save data with :meth:`record_stats`.
190
191 Does not return a value.
164192 """
165193
166194
22 import inspect
33 import sys
44 import time
5
5 from collections import OrderedDict
6
7 import django
68 from django.conf import settings
79 from django.core import cache
8 from django.core.cache import cache as original_cache, get_cache as original_get_cache
10 from django.core.cache import CacheHandler, caches as original_caches
911 from django.core.cache.backends.base import BaseCache
1012 from django.dispatch import Signal
11 from django.template import Node
13 from django.middleware import cache as middleware_cache
1214 from django.utils.translation import ugettext_lazy as _, ungettext
13 try:
14 from collections import OrderedDict
15 except ImportError:
16 from django.utils.datastructures import SortedDict as OrderedDict
17
15
16 from debug_toolbar import settings as dt_settings
1817 from debug_toolbar.panels import Panel
19 from debug_toolbar.utils import (tidy_stacktrace, render_stacktrace,
20 get_template_info, get_stack)
21 from debug_toolbar import settings as dt_settings
22
18 from debug_toolbar.utils import (
19 get_stack, get_template_info, render_stacktrace, tidy_stacktrace,
20 )
21
22 if django.VERSION[:2] < (1, 9):
23 from django.core.cache import get_cache as original_get_cache
2324
2425 cache_called = Signal(providing_args=[
2526 "time_taken", "name", "return_value", "args", "kwargs", "trace"])
3637 else:
3738 stacktrace = []
3839
39 template_info = None
40 cur_frame = sys._getframe().f_back
41 try:
42 while cur_frame is not None:
43 if cur_frame.f_code.co_name == 'render':
44 node = cur_frame.f_locals['self']
45 if isinstance(node, Node):
46 template_info = get_template_info(node.source)
47 break
48 cur_frame = cur_frame.f_back
49 except Exception:
50 pass
51 del cur_frame
40 template_info = get_template_info()
5241 cache_called.send(sender=self.__class__, time_taken=t,
5342 name=method.__name__, return_value=value,
5443 args=args, kwargs=kwargs, trace=stacktrace,
9382 return self.cache.delete(*args, **kwargs)
9483
9584 @send_signal
85 def clear(self, *args, **kwargs):
86 return self.cache.clear(*args, **kwargs)
87
88 @send_signal
9689 def has_key(self, *args, **kwargs):
97 return self.cache.has_key(*args, **kwargs)
90 # Ignore flake8 rules for has_key since we need to support caches
91 # that may be using has_key.
92 return self.cache.has_key(*args, **kwargs) # noqa
9893
9994 @send_signal
10095 def incr(self, *args, **kwargs):
125120 return self.cache.decr_version(*args, **kwargs)
126121
127122
128 def get_cache(*args, **kwargs):
129 return CacheStatTracker(original_get_cache(*args, **kwargs))
123 if django.VERSION[:2] < (1, 9):
124 def get_cache(*args, **kwargs):
125 return CacheStatTracker(original_get_cache(*args, **kwargs))
126
127
128 class CacheHandlerPatch(CacheHandler):
129 def __getitem__(self, alias):
130 actual_cache = super(CacheHandlerPatch, self).__getitem__(alias)
131 return CacheStatTracker(actual_cache)
132
133
134 # Must monkey patch the middleware's cache module as well in order to
135 # cover per-view level caching. This needs to be monkey patched outside
136 # of the enable_instrumentation method since the django's
137 # decorator_from_middleware_with_args will store the cache from core.caches
138 # when it wraps the view.
139 if django.VERSION[:2] < (1, 9):
140 middleware_cache.get_cache = get_cache
141 middleware_cache.caches = CacheHandlerPatch()
130142
131143
132144 class CachePanel(Panel):
146158 ('get', 0),
147159 ('set', 0),
148160 ('delete', 0),
161 ('clear', 0),
149162 ('get_many', 0),
150163 ('set_many', 0),
151164 ('delete_many', 0),
205218 count) % dict(count=count)
206219
207220 def enable_instrumentation(self):
208 # This isn't thread-safe because cache connections aren't thread-local
209 # in Django, unlike database connections.
210 cache.cache = CacheStatTracker(original_cache)
211 cache.get_cache = get_cache
221 if django.VERSION[:2] < (1, 9):
222 cache.get_cache = get_cache
223 if isinstance(middleware_cache.caches, CacheHandlerPatch):
224 cache.caches = middleware_cache.caches
225 else:
226 cache.caches = CacheHandlerPatch()
212227
213228 def disable_instrumentation(self):
214 cache.cache = original_cache
215 cache.get_cache = original_get_cache
216
217 def process_response(self, request, response):
229 if django.VERSION[:2] < (1, 9):
230 cache.get_cache = original_get_cache
231 cache.caches = original_caches
232 # While it can be restored to the original, any views that were
233 # wrapped with the cache_page decorator will continue to use a
234 # monkey patched cache.
235 middleware_cache.caches = original_caches
236
237 def generate_stats(self, request, response):
218238 self.record_stats({
219239 'total_calls': len(self.calls),
220240 'calls': self.calls,
00 from __future__ import absolute_import, unicode_literals
11
2 try:
3 from collections import OrderedDict
4 except ImportError:
5 from django.utils.datastructures import SortedDict as OrderedDict
2 from collections import OrderedDict
3
64 from django.utils.translation import ugettext_lazy as _
5
76 from debug_toolbar.panels import Panel
87
98
4847 'environ': self.environ,
4948 })
5049
51 def process_response(self, request, response):
50 def generate_stats(self, request, response):
5251 self.response_headers = OrderedDict(sorted(response.items()))
5352 self.record_stats({
5453 'response_headers': self.response_headers,
11
22 import datetime
33 import logging
4
5 from django.utils.translation import ugettext_lazy as _, ungettext
6
7 from debug_toolbar.panels import Panel
8 from debug_toolbar.utils import ThreadCollector
9
410 try:
511 import threading
612 except ImportError:
713 threading = None
8 from django.utils.translation import ungettext, ugettext_lazy as _
9 from debug_toolbar.panels import Panel
10 from debug_toolbar.utils import ThreadCollector
1114
1215 MESSAGE_IF_STRING_REPRESENTATION_INVALID = '[Could not get log message]'
1316
4952
5053 collector = LogCollector()
5154 logging_handler = ThreadTrackingHandler(collector)
52 logging.root.setLevel(logging.NOTSET)
5355 logging.root.addHandler(logging_handler)
5456
5557
7476 def process_request(self, request):
7577 collector.clear_collection()
7678
77 def process_response(self, request, response):
79 def generate_stats(self, request, response):
7880 records = collector.get_collection()
7981 self._records[threading.currentThread()] = records
8082 collector.clear_collection()
00 from __future__ import absolute_import, division, unicode_literals
11
2 import cProfile
3 import os
4 from colorsys import hsv_to_rgb
5 from pstats import Stats
6
7 from django.utils import six
8 from django.utils.safestring import mark_safe
29 from django.utils.translation import ugettext_lazy as _
3 from django.utils.safestring import mark_safe
10
11 from debug_toolbar import settings as dt_settings
412 from debug_toolbar.panels import Panel
5 from debug_toolbar import settings as dt_settings
613
7 import cProfile
8 from pstats import Stats
9 from colorsys import hsv_to_rgb
10 import os
14 # Occasionally the disable method on the profiler is listed before
15 # the actual view functions. This function call should be ignored as
16 # it leads to an error within the tests.
17 INVALID_PROFILER_FUNC = '_lsprof.Profiler'
18
19
20 def contains_profiler(func_tuple):
21 """Helper function that checks to see if the tuple contains
22 the INVALID_PROFILE_FUNC in any string value of the tuple."""
23 has_profiler = False
24 for value in func_tuple:
25 if isinstance(value, six.string_types):
26 has_profiler |= INVALID_PROFILER_FUNC in value
27 return has_profiler
1128
1229
1330 class DjangoDebugToolbarStats(Stats):
1633 def get_root_func(self):
1734 if self.__root is None:
1835 for func, (cc, nc, tt, ct, callers) in self.stats.items():
19 if len(callers) == 0:
36 if len(callers) == 0 and not contains_profiler(func):
2037 self.__root = func
2138 break
2239 return self.__root
6178 file_path, file_name = file_name.rsplit(os.sep, 1)
6279
6380 return mark_safe(
64 '<span class="path">{0}/</span>'
65 '<span class="file">{1}</span>'
66 ' in <span class="func">{3}</span>'
67 '(<span class="lineno">{2}</span>)'.format(
81 '<span class="djdt-path">{0}/</span>'
82 '<span class="djdt-file">{1}</span>'
83 ' in <span class="djdt-func">{3}</span>'
84 '(<span class="djdt-lineno">{2}</span>)'.format(
6885 file_path,
6986 file_name,
7087 line_num,
141158 func.has_subfuncs = True
142159 self.add_node(func_list, subfunc, max_depth, cum_time=cum_time)
143160
144 def process_response(self, request, response):
161 def generate_stats(self, request, response):
145162 if not hasattr(self, 'profiler'):
146163 return None
147164 # Could be delayed until the panel content is requested (perf. optim.)
00 from __future__ import absolute_import, unicode_literals
11
2 from django.core.handlers.wsgi import STATUS_CODE_TEXT
32 from django.shortcuts import render_to_response
43 from django.utils.translation import ugettext_lazy as _
54
1918 if 300 <= int(response.status_code) < 400:
2019 redirect_to = response.get('Location', None)
2120 if redirect_to:
22 try: # Django >= 1.6
23 reason_phrase = response.reason_phrase
24 except AttributeError:
25 reason_phrase = STATUS_CODE_TEXT.get(response.status_code,
26 'UNKNOWN STATUS CODE')
27 status_line = '%s %s' % (response.status_code, reason_phrase)
21 status_line = '%s %s' % (response.status_code, response.reason_phrase)
2822 cookies = response.cookies
2923 context = {'redirect_to': redirect_to, 'status_line': status_line}
3024 response = render_to_response('debug_toolbar/redirect.html', context)
2424 view_func = self.get_stats().get('view_func', '')
2525 return view_func.rsplit('.', 1)[-1]
2626
27 def process_response(self, request, response):
27 def generate_stats(self, request, response):
2828 self.record_stats({
2929 'get': [(k, request.GET.getlist(k)) for k in sorted(request.GET)],
3030 'post': [(k, request.POST.getlist(k)) for k in sorted(request.POST)],
00 from __future__ import absolute_import, unicode_literals
11
2 from collections import OrderedDict
3
24 from django.conf import settings
5 from django.utils.translation import ugettext_lazy as _
36 from django.views.debug import get_safe_settings
4 from django.utils.translation import ugettext_lazy as _
5 try:
6 from collections import OrderedDict
7 except ImportError:
8 from django.utils.datastructures import SortedDict as OrderedDict
97
108 from debug_toolbar.panels import Panel
119
2119 def title(self):
2220 return _("Settings from <code>%s</code>") % settings.SETTINGS_MODULE
2321
24 def process_response(self, request, response):
22 def generate_stats(self, request, response):
2523 self.record_stats({
2624 'settings': OrderedDict(sorted(get_safe_settings().items(),
2725 key=lambda s: s[0])),
00 from __future__ import absolute_import, unicode_literals
11
2 import weakref
3 from importlib import import_module
4
25 from django.core.signals import (
3 request_started, request_finished, got_request_exception)
6 got_request_exception, request_finished, request_started,
7 )
48 from django.db.backends.signals import connection_created
59 from django.db.models.signals import (
6 class_prepared, pre_init, post_init, pre_save, post_save,
7 pre_delete, post_delete, post_syncdb)
8 try:
9 from django.dispatch.dispatcher import WEAKREF_TYPES
10 except ImportError:
11 import weakref
12 WEAKREF_TYPES = weakref.ReferenceType,
10 class_prepared, post_delete, post_init, post_migrate, post_save,
11 pre_delete, pre_init, pre_save,
12 )
1313 from django.utils.translation import ugettext_lazy as _, ungettext
14 from django.utils.importlib import import_module
1514
1615 from debug_toolbar.panels import Panel
1716
3130 'post_save': post_save,
3231 'pre_delete': pre_delete,
3332 'post_delete': post_delete,
34 'post_syncdb': post_syncdb,
33 'post_migrate': post_migrate,
3534 }
3635
3736 def nav_subtitle(self):
6059 signals[signal_name] = getattr(signals_mod, signal_name)
6160 return signals
6261
63 def process_response(self, request, response):
62 def generate_stats(self, request, response):
6463 signals = []
6564 for name, signal in sorted(self.signals.items(), key=lambda x: x[0]):
6665 if signal is None:
6867 receivers = []
6968 for receiver in signal.receivers:
7069 receiver = receiver[1]
71 if isinstance(receiver, WEAKREF_TYPES):
70 if isinstance(receiver, weakref.ReferenceType):
7271 receiver = receiver()
7372 if receiver is None:
7473 continue
0 from debug_toolbar.panels.sql.panel import SQLPanel # noqa
0 from debug_toolbar.panels.sql.panel import SQLPanel # noqa
00 from __future__ import absolute_import, unicode_literals
11
2 import hashlib
23 import json
3 import hashlib
44
55 from django import forms
66 from django.conf import settings
7 from django.core.exceptions import ValidationError
78 from django.db import connections
89 from django.utils.encoding import force_text
910 from django.utils.functional import cached_property
10 from django.core.exceptions import ValidationError
1111
1212 from debug_toolbar.panels.sql.utils import reformat_sql
1313
00 from __future__ import absolute_import, unicode_literals
11
22 import uuid
3 from collections import defaultdict
34 from copy import copy
4 from collections import defaultdict
5
6 from django.conf.urls import patterns, url
5
6 from django.conf.urls import url
77 from django.db import connections
88 from django.utils.translation import ugettext_lazy as _, ungettext_lazy as __
99
1010 from debug_toolbar.panels import Panel
11 from debug_toolbar.panels.sql import views
1112 from debug_toolbar.panels.sql.forms import SQLSelectForm
13 from debug_toolbar.panels.sql.tracking import unwrap_cursor, wrap_cursor
14 from debug_toolbar.panels.sql.utils import (
15 contrasting_color_generator, reformat_sql,
16 )
1217 from debug_toolbar.utils import render_stacktrace
13 from debug_toolbar.panels.sql.utils import reformat_sql, contrasting_color_generator
14 from debug_toolbar.panels.sql.tracking import wrap_cursor, unwrap_cursor
1518
1619
1720 def get_isolation_level_display(vendor, level):
119122
120123 @classmethod
121124 def get_urls(cls):
122 return patterns('debug_toolbar.panels.sql.views', # noqa
123 url(r'^sql_select/$', 'sql_select', name='sql_select'),
124 url(r'^sql_explain/$', 'sql_explain', name='sql_explain'),
125 url(r'^sql_profile/$', 'sql_profile', name='sql_profile'),
126 )
125 return [
126 url(r'^sql_select/$', views.sql_select, name='sql_select'),
127 url(r'^sql_explain/$', views.sql_explain, name='sql_explain'),
128 url(r'^sql_profile/$', views.sql_profile, name='sql_profile'),
129 ]
127130
128131 def enable_instrumentation(self):
129132 # This is thread-safe because database connections are thread-local.
134137 for connection in connections.all():
135138 unwrap_cursor(connection)
136139
137 def process_response(self, request, response):
140 def generate_stats(self, request, response):
138141 colors = contrasting_color_generator()
139142 trace_colors = defaultdict(lambda: next(colors))
143 query_duplicates = defaultdict(lambda: defaultdict(int))
140144 if self._queries:
141145 width_ratio_tally = 0
142146 factor = int(256.0 / (len(self._databases) * 2.5))
159163 trans_id = None
160164 i = 0
161165 for alias, query in self._queries:
166 query_duplicates[alias][query["raw_sql"]] += 1
167
162168 trans_id = query.get('trans_id')
163169 last_trans_id = trans_ids.get(alias)
164170
202208 if trans_id:
203209 self._queries[(i - 1)][1]['ends_trans'] = True
204210
211 # Queries are duplicates only if there's as least 2 of them.
212 # Also, to hide queries, we need to give all the duplicate groups an id
213 query_duplicates = dict(
214 (alias, dict(
215 (query, duplicate_count)
216 for query, duplicate_count in queries.items()
217 if duplicate_count >= 2
218 ))
219 for alias, queries in query_duplicates.items()
220 )
221
222 for alias, query in self._queries:
223 try:
224 duplicates_count = query_duplicates[alias][query["raw_sql"]]
225 query["duplicate_count"] = duplicates_count
226 except KeyError:
227 pass
228
229 for alias, alias_info in self._databases.items():
230 try:
231 alias_info["duplicate_count"] = sum(e for e in query_duplicates[alias].values())
232 except KeyError:
233 pass
234
205235 self.record_stats({
206236 'databases': sorted(self._databases.items(), key=lambda x: -x[1]['time_spent']),
207237 'queries': [q for a, q in self._queries],
00 from __future__ import absolute_import, unicode_literals
1
2 import sys
31
42 import json
53 from threading import local
64 from time import time
75
8 from django.template import Node
6 from django.utils import six
97 from django.utils.encoding import force_text
10 from django.utils import six
118
12 from debug_toolbar.utils import tidy_stacktrace, get_template_info, get_stack
139 from debug_toolbar import settings as dt_settings
10 from debug_toolbar.utils import get_stack, get_template_info, tidy_stacktrace
1411
1512
1613 class SQLQueryTriggered(Exception):
114111 except Exception:
115112 pass # object not JSON serializable
116113
117 template_info = None
118 cur_frame = sys._getframe().f_back
119 try:
120 while cur_frame is not None:
121 if cur_frame.f_code.co_name == 'render':
122 node = cur_frame.f_locals['self']
123 if isinstance(node, Node):
124 template_info = get_template_info(node.source)
125 break
126 cur_frame = cur_frame.f_back
127 except Exception:
128 pass
129 del cur_frame
114 template_info = get_template_info()
130115
131116 alias = getattr(self.db, 'alias', 'default')
132117 conn = self.db.connection
11
22 import re
33
4 import sqlparse
45 from django.utils.html import escape
5
6 import sqlparse
76 from sqlparse import tokens as T
87
98
00 from __future__ import absolute_import, unicode_literals
1 from os.path import normpath, join
1
2 from collections import OrderedDict
3 from os.path import join, normpath
4
5 from django.conf import settings
6 from django.contrib.staticfiles import finders, storage
7 from django.contrib.staticfiles.templatetags import staticfiles
8 from django.core.files.storage import get_storage_class
9 from django.utils.encoding import python_2_unicode_compatible
10 from django.utils.functional import LazyObject
11 from django.utils.translation import ugettext_lazy as _, ungettext
12
13 from debug_toolbar import panels
14 from debug_toolbar.utils import ThreadCollector
15
216 try:
317 import threading
418 except ImportError:
519 threading = None
6
7 from django.conf import settings
8 from django.core.files.storage import get_storage_class
9 from django.contrib.staticfiles import finders, storage
10 from django.contrib.staticfiles.templatetags import staticfiles
11
12 from django.utils.encoding import python_2_unicode_compatible
13 from django.utils.functional import LazyObject
14 from django.utils.translation import ungettext, ugettext_lazy as _
15 try:
16 from collections import OrderedDict
17 except ImportError:
18 from django.utils.datastructures import SortedDict as OrderedDict
19
20 from debug_toolbar import panels
21 from debug_toolbar.utils import ThreadCollector
2220
2321
2422 @python_2_unicode_compatible
115113 def process_request(self, request):
116114 collector.clear_collection()
117115
118 def process_response(self, request, response):
116 def generate_stats(self, request, response):
119117 used_paths = collector.get_collection()
120118 self._paths[threading.currentThread()] = used_paths
121119
0 from debug_toolbar.panels.templates.panel import TemplatesPanel # noqa
0 from debug_toolbar.panels.templates.panel import TemplatesPanel # noqa
00 from __future__ import absolute_import, unicode_literals
11
2 try:
3 from collections import OrderedDict
4 except ImportError:
5 from django.utils.datastructures import SortedDict as OrderedDict
2 from collections import OrderedDict
3 from contextlib import contextmanager
64 from os.path import normpath
75 from pprint import pformat
86
97 import django
108 from django import http
11 from django.conf import settings
12 from django.conf.urls import patterns, url
9 from django.conf.urls import url
1310 from django.db.models.query import QuerySet, RawQuerySet
1411 from django.template import Context, RequestContext, Template
15 from django.template.context import get_standard_processors
1612 from django.test.signals import template_rendered
1713 from django.test.utils import instrumented_test_render
14 from django.utils import six
1815 from django.utils.encoding import force_text
19 from django.utils import six
2016 from django.utils.translation import ugettext_lazy as _
2117
18 from debug_toolbar.compat import (
19 get_template_context_processors, get_template_dirs,
20 )
2221 from debug_toolbar.panels import Panel
23 from debug_toolbar.panels.sql.tracking import recording, SQLQueryTriggered
24
22 from debug_toolbar.panels.sql.tracking import SQLQueryTriggered, recording
23 from debug_toolbar.panels.templates import views
2524
2625 # Monkey-patch to enable the template_rendered signal. The receiver returns
2726 # immediately when the panel is disabled to keep the overhead small.
3736 # Monkey-patch to store items added by template context processors. The
3837 # overhead is sufficiently small to justify enabling it unconditionally.
3938
40 def _request_context__init__(
41 self, request, dict_=None, processors=None, current_app=None,
42 use_l10n=None, use_tz=None):
43 Context.__init__(
44 self, dict_, current_app=current_app,
45 use_l10n=use_l10n, use_tz=use_tz)
46 if processors is None:
47 processors = ()
48 else:
49 processors = tuple(processors)
50 self.context_processors = OrderedDict()
51 updates = dict()
52 for processor in get_standard_processors() + processors:
53 name = '%s.%s' % (processor.__module__, processor.__name__)
54 context = processor(request)
55 self.context_processors[name] = context
56 updates.update(context)
57 self.update(updates)
58
59 RequestContext.__init__ = _request_context__init__
60
61
62 # Monkey-patch versions of Django where Template doesn't store origin.
63 # See https://code.djangoproject.com/ticket/16096.
64
65 if django.VERSION[:2] < (1, 7):
66
67 old_template_init = Template.__init__
68
69 def new_template_init(self, template_string, origin=None, name='<Unknown Template>'):
70 old_template_init(self, template_string, origin, name)
71 self.origin = origin
72
73 Template.__init__ = new_template_init
39 if django.VERSION[:2] < (1, 8):
40
41 def _request_context___init__(
42 self, request, dict_=None, processors=None, current_app=None,
43 use_l10n=None, use_tz=None):
44 Context.__init__(
45 self, dict_, current_app=current_app,
46 use_l10n=use_l10n, use_tz=use_tz)
47 if processors is None:
48 processors = ()
49 else:
50 processors = tuple(processors)
51 self.context_processors = OrderedDict()
52 updates = dict()
53 std_processors = get_template_context_processors()
54 for processor in std_processors + processors:
55 name = '%s.%s' % (processor.__module__, processor.__name__)
56 context = processor(request)
57 self.context_processors[name] = context
58 updates.update(context)
59 self.update(updates)
60
61 RequestContext.__init__ = _request_context___init__
62
63 else:
64
65 @contextmanager
66 def _request_context_bind_template(self, template):
67 if self.template is not None:
68 raise RuntimeError("Context is already bound to a template")
69
70 self.template = template
71 # Set context processors according to the template engine's settings.
72 processors = (template.engine.template_context_processors +
73 self._processors)
74 self.context_processors = OrderedDict()
75 updates = {}
76 for processor in processors:
77 name = '%s.%s' % (processor.__module__, processor.__name__)
78 context = processor(self.request)
79 self.context_processors[name] = context
80 updates.update(context)
81 self.dicts[self._processors_index] = updates
82
83 try:
84 yield
85 finally:
86 self.template = None
87 # Unset context processors.
88 self.dicts[self._processors_index] = {}
89
90 RequestContext.bind_template = _request_context_bind_template
7491
7592
7693 class TemplatesPanel(Panel):
154171
155172 @classmethod
156173 def get_urls(cls):
157 return patterns('debug_toolbar.panels.templates.views', # noqa
158 url(r'^template_source/$', 'template_source', name='template_source'),
159 )
174 return [
175 url(r'^template_source/$', views.template_source, name='template_source'),
176 ]
160177
161178 def enable_instrumentation(self):
162179 template_rendered.connect(self._store_template_info)
164181 def disable_instrumentation(self):
165182 template_rendered.disconnect(self._store_template_info)
166183
167 def process_response(self, request, response):
184 def generate_stats(self, request, response):
168185 template_context = []
169186 for template_data in self.templates:
170187 info = {}
171188 # Clean up some info about templates
172189 template = template_data.get('template', None)
173 if not hasattr(template, 'origin'):
174 continue
175 if template.origin and template.origin.name:
190 if hasattr(template, 'origin') and template.origin and template.origin.name:
176191 template.origin_name = template.origin.name
177192 else:
178 template.origin_name = 'No origin'
193 template.origin_name = _('No origin')
179194 info['template'] = template
180195 # Clean up context for better readability
181196 if self.toolbar.config['SHOW_TEMPLATE_CONTEXT']:
189204 else:
190205 context_processors = None
191206
207 template_dirs = get_template_dirs()
208
192209 self.record_stats({
193210 'templates': template_context,
194 'template_dirs': [normpath(x) for x in settings.TEMPLATE_DIRS],
211 'template_dirs': [normpath(x) for x in template_dirs],
195212 'context_processors': context_processors,
196213 })
00 from __future__ import absolute_import, unicode_literals
11
22 from django.http import HttpResponseBadRequest
3 from django.conf import settings
43 from django.shortcuts import render_to_response
54 from django.template import TemplateDoesNotExist
6 from django.template.loader import find_template_loader
75 from django.utils.safestring import mark_safe
6
7 from debug_toolbar.compat import get_template_loaders
88
99
1010 def template_source(request):
1616 if template_name is None:
1717 return HttpResponseBadRequest('"template" key is required')
1818
19 loaders = []
20 for loader_name in settings.TEMPLATE_LOADERS:
21 loader = find_template_loader(loader_name)
19 final_loaders = []
20 loaders = get_template_loaders()
21
22 for loader in loaders:
2223 if loader is not None:
23 loaders.append(loader)
24 for loader in loaders:
24 # When the loader has loaders associated with it,
25 # append those loaders to the list. This occurs with
26 # django.template.loaders.cached.Loader
27 if hasattr(loader, 'loaders'):
28 final_loaders += loader.loaders
29 else:
30 final_loaders.append(loader)
31
32 for loader in final_loaders:
2533 try:
2634 source, display_name = loader.load_template_source(template_name)
2735 break
00 from __future__ import absolute_import, unicode_literals
1
2 import time
3
4 from django.template.loader import render_to_string
5 from django.utils.translation import ugettext_lazy as _
6
7 from debug_toolbar.panels import Panel
18
29 try:
310 import resource # Not available on Win32 systems
411 except ImportError:
512 resource = None
6 import time
7 from django.template.loader import render_to_string
8 from django.utils.translation import ugettext_lazy as _
9 from debug_toolbar.panels import Panel
1013
1114
1215 class TimerPanel(Panel):
5154 if self.has_content:
5255 self._start_rusage = resource.getrusage(resource.RUSAGE_SELF)
5356
54 def process_response(self, request, response):
57 def generate_stats(self, request, response):
5558 stats = {}
5659 if hasattr(self, '_start_time'):
5760 stats['total_time'] = (time.time() - self._start_time) * 1000
00 from __future__ import absolute_import, unicode_literals
11
22 import sys
3 from collections import OrderedDict
34
45 import django
5 from django.conf import settings
6 from django.utils.importlib import import_module
6 from django.apps import apps
77 from django.utils.translation import ugettext_lazy as _
8 try:
9 from collections import OrderedDict
10 except ImportError:
11 from django.utils.datastructures import SortedDict as OrderedDict
128
139 from debug_toolbar.panels import Panel
1410
2521
2622 template = 'debug_toolbar/panels/versions.html'
2723
28 def process_response(self, request, response):
24 def generate_stats(self, request, response):
2925 versions = [
3026 ('Python', '%d.%d.%d' % sys.version_info[:3]),
3127 ('Django', self.get_app_version(django)),
3228 ]
33 if django.VERSION[:2] >= (1, 7):
34 versions += list(self.gen_app_versions_1_7())
35 else:
36 versions += list(self.gen_app_versions_1_6())
29 versions += list(self.gen_app_versions())
3730 self.record_stats({
3831 'versions': OrderedDict(sorted(versions, key=lambda v: v[0])),
3932 'paths': sys.path,
4033 })
4134
42 def gen_app_versions_1_7(self):
43 from django.apps import apps
35 def gen_app_versions(self):
4436 for app_config in apps.get_app_configs():
4537 name = app_config.verbose_name
4638 app = app_config.module
47 version = self.get_app_version(app)
48 if version:
49 yield name, version
50
51 def gen_app_versions_1_6(self):
52 for app in list(settings.INSTALLED_APPS):
53 name = app.split('.')[-1].replace('_', ' ').capitalize()
54 app = import_module(app)
5539 version = self.get_app_version(app)
5640 if version:
5741 yield name, version
00 from __future__ import absolute_import, unicode_literals
11
22 import warnings
3 from importlib import import_module
34
45 from django.conf import settings
5 from django.utils.importlib import import_module
66 from django.utils import six
7
7 from django.utils.module_loading import import_string
88
99 # Always import this module as follows:
1010 # from debug_toolbar import settings [as dt_settings]
1717 # Toolbar options
1818 'DISABLE_PANELS': set(['debug_toolbar.panels.redirects.RedirectsPanel']),
1919 'INSERT_BEFORE': '</body>',
20 'JQUERY_URL': '//ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js',
20 'JQUERY_URL': '//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js',
2121 'RENDER_PANELS': None,
22 'RESULTS_STORE_SIZE': 10,
22 'RESULTS_CACHE_SIZE': 10,
2323 'ROOT_TAG_EXTRA_ATTRS': '',
2424 'SHOW_COLLAPSED': False,
2525 'SHOW_TOOLBAR_CALLBACK': 'debug_toolbar.middleware.show_toolbar',
6464
6565 CONFIG = CONFIG_DEFAULTS.copy()
6666 CONFIG.update(USER_CONFIG)
67 if not isinstance(CONFIG['SHOW_TOOLBAR_CALLBACK'], six.string_types):
68 warnings.warn(
69 "SHOW_TOOLBAR_CALLBACK is now a dotted path. Update your "
70 "DEBUG_TOOLBAR_CONFIG setting.", DeprecationWarning)
7167
7268
7369 PANELS_DEFAULTS = [
149145 'debug_toolbar.panels.redirects.RedirectsPanel'
150146 )
151147
152
153148 PATCH_SETTINGS = getattr(settings, 'DEBUG_TOOLBAR_PATCH_SETTINGS', settings.DEBUG)
154149
155150
157152 # imports are placed inside functions to make it safe to import this module.
158153
159154
160 def is_toolbar_middleware(middleware_path):
155 def check_middleware():
156 from django.middleware.gzip import GZipMiddleware
161157 from debug_toolbar.middleware import DebugToolbarMiddleware
162 # This could be replaced by import_by_path in Django >= 1.6.
158 gzip_index = None
159 debug_toolbar_index = None
160
161 # Determine the indexes which gzip and/or the toolbar are installed at
162 for i, middleware in enumerate(settings.MIDDLEWARE_CLASSES):
163 if is_middleware_class(GZipMiddleware, middleware):
164 gzip_index = i
165 elif is_middleware_class(DebugToolbarMiddleware, middleware):
166 debug_toolbar_index = i
167 # If the toolbar appears before the gzip index, raise a warning
168 if gzip_index is not None and debug_toolbar_index < gzip_index:
169 warnings.warn(
170 "Please use an explicit setup with the "
171 "debug_toolbar.middleware.DebugToolbarMiddleware "
172 "after django.middleware.gzip.GZipMiddlware "
173 "in MIDDLEWARE_CLASSES.", Warning)
174
175
176 def is_middleware_class(middleware_class, middleware_path):
163177 try:
164 mod_path, cls_name = middleware_path.rsplit('.', 1)
165 mod = import_module(mod_path)
166 middleware_cls = getattr(mod, cls_name)
167 except (AttributeError, ImportError, ValueError):
178 middleware_cls = import_string(middleware_path)
179 except ImportError:
168180 return
169 return issubclass(middleware_cls, DebugToolbarMiddleware)
181 return issubclass(middleware_cls, middleware_class)
170182
171183
172184 def is_toolbar_middleware_installed():
173 return any(is_toolbar_middleware(middleware)
185 from debug_toolbar.middleware import DebugToolbarMiddleware
186 return any(is_middleware_class(DebugToolbarMiddleware, middleware)
174187 for middleware in settings.MIDDLEWARE_CLASSES)
175188
176189
195208
196209
197210 def patch_root_urlconf():
198 from django.conf.urls import include, patterns, url
211 from django.conf.urls import include, url
199212 from django.core.urlresolvers import clear_url_caches, reverse, NoReverseMatch
200213 import debug_toolbar
201214 try:
202215 reverse('djdt:render_panel')
203216 except NoReverseMatch:
204217 urlconf_module = import_module(settings.ROOT_URLCONF)
205 urlconf_module.urlpatterns = patterns('', # noqa
218 urlconf_module.urlpatterns = [
206219 url(r'^__debug__/', include(debug_toolbar.urls)),
207 ) + urlconf_module.urlpatterns
220 ] + urlconf_module.urlpatterns
208221 clear_url_caches()
209222
210223
00 /* http://www.positioniseverything.net/easyclearing.html */
1 #djDebug .clearfix:after {
1 #djDebug .djdt-clearfix:after {
22 content: ".";
33 display: block;
44 height: 0;
55 clear: both;
66 visibility: hidden;
77 }
8 #djDebug .clearfix {display: inline-block;}
8 #djDebug .djdt-clearfix {display: inline-block;}
99 /* Hides from IE-mac \*/
10 #djDebug .clearfix {display: block;}
11 * html #djDebug .clearfix {height: 1%;}
10 #djDebug .djdt-clearfix {display: block;}
11 * html #djDebug .djdt-clearfix {height: 1%;}
1212 /* end hide from IE-mac */
1313
1414 /* Debug Toolbar CSS Reset, adapted from Eric Meyer's CSS Reset */
125125 }
126126
127127 #djDebug #djDebugToolbar li>a,
128 #djDebug #djDebugToolbar li>div.contentless {
128 #djDebug #djDebugToolbar li>div.djdt-contentless {
129129 font-weight:normal;
130130 font-style:normal;
131131 text-decoration:none;
134134 padding:10px 10px 5px 25px;
135135 color:#fff;
136136 }
137 #djDebug #djDebugToolbar li>div.disabled {
137 #djDebug #djDebugToolbar li>div.djdt-disabled {
138138 font-style: italic;
139139 color: #999;
140140 }
144144 background-color:#ffc;
145145 }
146146
147 #djDebug #djDebugToolbar li.active {
147 #djDebug #djDebugToolbar li.djdt-active {
148148 background: #333 no-repeat left center;
149149 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAQAAAAngNWGAAABe0lEQVR4AW2SO0tDQRCFz+bGJxEUrKzsBBsb/4DYiIWdECvB/6CCYGtp6QNRjJ1FihSCVpZGMIhYSBAfIGKRx70xyY3JbrKOk7DJLp7DXm7Il9nMmREYQgQeAI1W1/zZUhR9ZI9gjSZb0iHMRSPbE1QzhhF2jN4H6YdRCHaPvOTjdDb1jWECBhiJoC1tg6Kotbw9WkxBoIUGaqiiQs8fSCj+t9qAIL1nlg9fKgSGKKNEJ2RUMqh7QCDIr58k31AlrIiA0CqhDTQJtUFAqsTFxjV85FGAz1XrkDZodPewkih8IkdwCRWu2U6VerQ0O3OzuTSJ/k62JiIXJI2NL0wBjDiTseQHW8fnGY6myf3+Dz49x88+vjr9SoPaoG6lLteuCApMiu1otAWG/s7BXtYEzv3yZOyrc5nV3XTZjPAv7Jqp2AVf9+dOyx4EFCTqCAnimZB1z9X38fk05RblfVQE1LkR5a6vwCivruANV2ynjU5FHpIE+AsCnCuNfgGtjt1gZaIn2wAAAABJRU5ErkJggg==");
150150 padding-left:10px;
151151 }
152152
153 #djDebug #djDebugToolbar li.active a:hover {
153 #djDebug #djDebugToolbar li.djdt-active a:hover {
154154 color:#b36a60;
155155 background-color:transparent;
156156 }
213213 background-color:#f5f5f5;
214214 }
215215
216 #djDebug .panelContent {
216 #djDebug .djdt-panelContent {
217217 display:none;
218218 position:fixed;
219219 margin:0;
226226 z-index:100000000;
227227 }
228228
229 #djDebug .panelContent > div {
229 #djDebug .djdt-panelContent > div {
230230 border-bottom:1px solid #ddd;
231231 }
232232
256256 padding:5px 0 0 20px;
257257 }
258258
259 #djDebug .djDebugPanelContent .loader {
259 #djDebug .djDebugPanelContent .djdt-loader {
260260 display:block;
261261 margin:80px auto;
262262 }
263263
264 #djDebug .djDebugPanelContent .scroll {
264 #djDebug .djDebugPanelContent .djdt-scroll {
265265 height:100%;
266266 overflow:auto;
267267 display:block;
280280 margin-top:0.8em;
281281 }
282282
283 #djDebug .panelContent table {
283 #djDebug .djdt-panelContent table {
284284 border:1px solid #ccc;
285285 border-collapse:collapse;
286286 width:100%;
289289 margin-top:0.8em;
290290 overflow: auto;
291291 }
292 #djDebug .panelContent tbody td,
293 #djDebug .panelContent tbody th {
292 #djDebug .djdt-panelContent tbody td,
293 #djDebug .djdt-panelContent tbody th {
294294 vertical-align:top;
295295 padding:2px 3px;
296296 }
297 #djDebug .panelContent tbody td.time {
297 #djDebug .djdt-panelContent tbody td.djdt-time {
298298 text-align: center;
299299 }
300300
301 #djDebug .panelContent thead th {
301 #djDebug .djdt-panelContent thead th {
302302 padding:1px 6px 1px 3px;
303303 text-align:left;
304304 font-weight:bold;
305305 font-size:14px;
306306 white-space: nowrap;
307307 }
308 #djDebug .panelContent tbody th {
308 #djDebug .djdt-panelContent tbody th {
309309 width:12em;
310310 text-align:right;
311311 color:#666;
317317 }
318318
319319 /*
320 #djDebug .panelContent p a:hover, #djDebug .panelContent dd a:hover {
320 #djDebug .djdt-panelContent p a:hover, #djDebug .djdt-panelContent dd a:hover {
321321 color:#111;
322322 background-color:#ffc;
323323 }
324324
325 #djDebug .panelContent p {
325 #djDebug .djdt-panelContent p {
326326 padding:0 5px;
327327 }
328328
329 #djDebug .panelContent p, #djDebug .panelContent table, #djDebug .panelContent ol, #djDebug .panelContent ul, #djDebug .panelContent dl {
329 #djDebug .djdt-panelContent p, #djDebug .djdt-panelContent table, #djDebug .djdt-panelContent ol, #djDebug .djdt-panelContent ul, #djDebug .djdt-panelContent dl {
330330 margin:5px 0 15px;
331331 background-color:#fff;
332332 }
333 #djDebug .panelContent table {
333 #djDebug .djdt-panelContent table {
334334 clear:both;
335335 border:0;
336336 padding:0;
339339 border-spacing:0;
340340 }
341341
342 #djDebug .panelContent table a {
342 #djDebug .djdt-panelContent table a {
343343 color:#000;
344344 padding:2px 4px;
345345 }
346 #djDebug .panelContent table a:hover {
346 #djDebug .djdt-panelContent table a:hover {
347347 background-color:#ffc;
348348 }
349349
350 #djDebug .panelContent table th {
350 #djDebug .djdt-panelContent table th {
351351 background-color:#333;
352352 font-weight:bold;
353353 color:#fff;
355355 text-align:left;
356356 cursor:pointer;
357357 }
358 #djDebug .panelContent table td {
358 #djDebug .djdt-panelContent table td {
359359 padding:5px 10px;
360360 font-size:14px;
361361 background-color:#fff;
363363 vertical-align:top;
364364 border:0;
365365 }
366 #djDebug .panelContent table tr.djDebugOdd td {
366 #djDebug .djdt-panelContent table tr.djDebugOdd td {
367367 background-color:#eee;
368368 }
369369 */
370370
371 #djDebug .panelContent .djDebugClose {
372 text-indent:-9999999px;
371 #djDebug .djdt-panelContent .djDebugClose {
373372 display:block;
374373 position:absolute;
375374 top:4px;
380379 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAQAAACQTsNJAAABuUlEQVR4Ab2WXeoaMRTFZxHz6pObcA0DeXUHhXktFl8LXYAPXYBLKhQGBOFqW3XS8YOW6vjHmnp6wWZyHU1maqHnQDAf/Ehu7twYhUQxdUixO/wr8ts3oeg9TQjCEx5R7SGvKCd4nPNsIyShD4QGf6QkBBkQWnrgg4zqS2fm01kbze3M3GFGjyBvCdLFqYRUySM1zLAOUXJ6dZAACcoPBOHkFpK5qY1BQBt5sExC0gAijEkriMuLfI9m8SqXNxbSd+QSbVSCnPtXyNjdCCoZ7PANF7C4/Y4tznASNzW+QqaP9lFcj4cLW4PY+vFepsSQ2Hbnp5vw2ShB231Cau72EkfUs53lC4R+YQkSXsBAiFdXc72IkupmDODDfKkhwKtdygUgHAuXw7gEIN7jCIQNsfc43sDuqlgsbC57A+u94q82nFVscv8Vy2Rbi72csGKQ+RPignvytGuZbPW0P6KNjvdpz97aIf3jLz/ArfuKXz9dCt7IojR9qihNAuUx33vL454grOqF+t2/F2rPk/H5pzaa2+Ynw3lIaOlh6BlVlDUCMlLND3pKhRdQUPof/1o4x9Qlxe6G/+T8BlqvQqkd4EyZAAAAAElFTkSuQmCC");
381380 }
382381
383 #djDebug .panelContent .djDebugClose:hover {
382 #djDebug .djdt-panelContent .djDebugClose:hover {
384383 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAACiUlEQVR4Ad2Yz2oTURSH+xCz7cqX6DMUZtudCxExigq2WhcKYtGFVLrwAboSKoVGxT+tJWpTa2lLTDsm6SSTjtZoIq0prf+2Hu8PcmHInJvJPYwuPPDBMDPn8DE5c+fcDEgjDENHMahwOwx2zg1IsE1wFXcVvoIM+J173L8hckrRUpAlLeSmITKsKNoKMHioJRUZU1DKjNmKTCUWDWpUL21RJbcAcIxz/chM9StyvVeh8rOHtH7nJi2dOc6Ba7gnSWY8ScQ1JVdfv6C1yQlegAH3+su5XjLDvUTKXNK77H0Ul4Bck0jZJJLhEry5GV1ULvNg1iSTiYlw64SfX0ShNEAtfp3pEhnhjJmekIJapqcyEhWZZt4OtuDqlXPUWHxKYXaGli+c1Ocpf/4E1Wfv0afcPK1dG+VyTW/TdFQk6Pdp7BfWSMdhtQIZSFDbe0s6DiqezVMJtIjTfXGnuv3b9Iib+RxF47C2Te3SJkUDsqZ81GZkHIgMdV+ora8YC62MnqbvH0Iyxa/WZ3pz+awxH7UZkSH9YaMolZfPdaJZZvd9XOJLU0sYQW1ucROJoCcOyh51x1G9ip4Ri1j9NLoxDaEbWPDTWDbrx/lHsZ740dilSKChBc1q+fp+3SyQjp/NBnoi1sB4KpLXl13QSo/n2GKFW1fpaKdG+8UNSEQbmPY2VulbWKfi5A0uFzUTFzR+ib/NFJSBWolLvKYd++i9WkhNxF9i35Y29/W9KB8DxDPJJU4EBP9wMPJFoyLmCetRUc8gPK5JRDOhIBOlJ9nE4Rn3yIdnwXYi2Crq7QSOU99OaGBNKTMu3XK63GQvADXcNDbhGcWeQAA5mf/ybwkOR3FM4XbAsSOt9wcLTn8FNtAKkQAAAABJRU5ErkJggg==");
385384 }
386385
387 #djDebug .panelContent .djDebugClose.djDebugBack {
386 #djDebug .djdt-panelContent .djDebugClose.djDebugBack {
388387 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAACBUlEQVR4Ad2Y0WriQBSGfYjc7tW+hM8g5HbfYMHbxcXbhT6AF30AH6cXvRCEttK0JgZi0qhQaRNtNWV2fuiADicZcxirdOCn45mccz4mMyczbXDbeDx2pH5IuRD6n7YGR3UdkPBSaiQlSoQxPOMeA+S3VIxENRXD1wZIS2rAANA1RCwuSAdBLKtTF6RnCur7fjGZTLZJkhQQ+rAdANM7FORfVaA0Td/zPBdlDWN4xgDTNYG4Zc7T6TQjASqA4jjOKmBaVSA3lNN8Pi8Es8GXBkEuGqTNh2DDtCkQvU5gal+FpYZYZJ3RQH5RxPqaWG82qmuw02uGyoHcuyB9anfowZ6el+I2jITellkOu9gWH5UwJbupvwvimWZDgVzdeWLohyqpAlF2zE7dWfEUiKMPBkGwNxt6QmjwEKik+Ltnz9ZvpTCITcA4AGnqA1EUreFkgrm+fwSEsuO3spfCIDYB0gRIi9gtlVsWSVRSAOzaMSOw4zVSDbGp4nZGIPxXg6TWXo39xarsjMV6LtuXLmiz2cx6QUNMuqAZSvxqtbJW4hHLVOKVFvpDSZK8HPmjt6C+vn9OcAz4S4FA3hcejEasoyKmlnFUVK+DklsFAl2c9vDMuE6EYbhR1wn0bV8nlEAtLKvLvXK62smeK8RwbVzC21IpAyCF77f8twQlR+onEkLow8aN9x+oYk85YNJqYQAAAABJRU5ErkJggg==");
389388 }
390389
391 #djDebug .panelContent .djDebugClose.djDebugBack:hover {
390 #djDebug .djdt-panelContent .djDebugClose.djDebugBack:hover {
392391 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAACLElEQVR4Ad2YT8sSURTG/RCzbdWX8DMIs23XMrBlTLiTSIKKIqgP4C6KQAuKsLCycqGLRHNsXqck2giStIiiRdDtPtABuz0zNw+XkAYe3vHce57zY/7cOfetaI/VahVZHbOKIZz/ilU02jcBBW9YZVaGC2OYg7nhQU5ZrVlhj9bIDQFSs5ooAFzN4KUFSWASWMm+INe8pvnSvJ1PzaLfg3COmB8G3n8Jcq7MKH14z4yvXjCD0yepMIY5HpiGDyQuSj56+cSMrrQ4ABHmZi/6ZTC1MpCUJb3u3oa5SsjlIKjFQeosYda5JaZ6mLt3OAxquiBsncieP4ZRCMGLrjMuyAlG7D4To2Yi5/44eWZYDdTeBWmzt8M1W95sm09Z+kd8dv0S4maY1EthCt6m9i5ITq8GAcHx+cN7KSogEqdXx3NVcgGJ3MF3R29+MCMpiOPbx40Uxd/f4q8uNgth4E1gIoBU3YHleOgYcJjvX78AQuL4LfFCGHgTkCpAau7A4umj0nuNIlIUALtxXBEcuI0kF950cTsoEO2tQdGAtyb8w4rfiof1cF5fvqDN73dCL2jwpAuaf4m/fD7UEg8v7xIv2rqTsme9cB+9AX1btuzre0bdBuh7krMMBMr/YWOUaVpF9BP7t4rSg3DFvua5xRJF8wddb/OMOfrmWbGdyKcT2U7gPPh2QgRqE1gN7ZYzZp29Qim8QmzC61YbBcAGuf/hvyW4IqvjKAjhHDGt309H4mp9BS17eAAAAABJRU5ErkJggg==");
393392 }
394393
395 #djDebug .panelContent dt, #djDebug .panelContent dd {
396 display:block;
397 }
398
399 #djDebug .panelContent dt {
394 #djDebug .djdt-panelContent dt, #djDebug .djdt-panelContent dd {
395 display:block;
396 }
397
398 #djDebug .djdt-panelContent dt {
400399 margin-top:0.75em;
401400 }
402401
403 #djDebug .panelContent dd {
402 #djDebug .djdt-panelContent dd {
404403 margin-left:10px;
405404 }
406405
547546 }
548547
549548
550 #djDebug .panelContent ul.stats {
549 #djDebug .djdt-panelContent ul.djdt-stats {
551550 position: relative;
552551 list-style-type: none;
553552 }
554 #djDebug .panelContent ul.stats li {
553 #djDebug .djdt-panelContent ul.djdt-stats li {
555554 width: 30%;
556555 float: left;
557556 }
558 #djDebug .panelContent ul.stats li strong.label {
557 #djDebug .djdt-panelContent ul.djdt-stats li strong.djdt-label {
559558 display: block;
560559 }
561 #djDebug .panelContent ul.stats li span.color {
560 #djDebug .djdt-panelContent ul.djdt-stats li span.djdt-color {
562561 height: 12px;
563562 width: 3px;
564563 display: inline-block;
565564 }
566 #djDebug .panelContent ul.stats li span.info {
565 #djDebug .djdt-panelContent ul.djdt-stats li span.djdt-info {
567566 display: block;
568567 padding-left: 5px;
569568 }
570569
571 #djDebug .panelcontent thead th {
570 #djDebug .djdt-panelContent thead th {
572571 white-space: nowrap;
573572 }
574 #djDebug .djDebugRowWarning .time {
573 #djDebug .djDebugRowWarning .djdt-time {
575574 color: red;
576575 }
577 #djdebug .panelcontent table .toggle {
576 #djdebug .djdt-panelContent table .djdt-toggle {
578577 width: 14px;
579578 padding-top: 3px;
580579 }
581 #djDebug .panelContent table .actions {
580 #djDebug .djdt-panelContent table .djdt-actions {
582581 min-width: 70px;
583582 white-space: nowrap;
584583 }
585 #djdebug .panelcontent table .color {
584 #djdebug .djdt-panelContent table .djdt-color {
586585 width: 3px;
587586 }
588 #djdebug .panelcontent table .color span {
587 #djdebug .djdt-panelContent table .djdt-color span {
589588 width: 3px;
590589 height: 12px;
591590 overflow: hidden;
629628 margin-bottom: 3px;
630629 font-family:Consolas, Monaco, "Bitstream Vera Sans Mono", "Lucida Console", monospace;
631630 }
632 #djDebug .stack span {
631 #djDebug .djdt-stack span {
633632 color: #000;
634633 font-weight: bold;
635634 }
636 #djDebug .stack span.path {
635 #djDebug .djdt-stack span.djdt-path {
637636 color: #777;
638637 font-weight: normal;
639638 }
640 #djDebug .stack span.code {
639 #djDebug .djdt-stack span.djdt-code {
641640 font-weight: normal;
642641 }
643642
644643 @media print {
645644 #djDebug {
646 display: none;
645 display: none !important;
647646 }
648647 }
648
649 #djDebug .djdt-width-20 {
650 width: 20%;
651 }
652 #djDebug .djdt-width-60 {
653 width: 60%;
654 }
655 #djDebug .djdt-highlighted {
656 background-color: lightgrey;
657 }
0 var djdt = {jQuery: jQuery.noConflict(true)}; window.define = _djdt_define_backup;
0 var _djdt_define_backup = window.define; window.define = undefined;
0 (function ($) {
0 (function ($, publicAPI) {
11 var djdt = {
22 handleDragged: false,
33 events: {
77 init: function() {
88 $('#djDebug').show();
99 var current = null;
10 $(document).on('click', '#djDebugPanelList li a', function() {
10 $('#djDebugPanelList').on('click', 'li a', function() {
1111 if (!this.className) {
1212 return false;
1313 }
1414 current = $('#djDebug #' + this.className);
1515 if (current.is(':visible')) {
1616 $(document).trigger('close.djDebug');
17 $(this).parent().removeClass('active');
17 $(this).parent().removeClass('djdt-active');
1818 } else {
19 $('.panelContent').hide(); // Hide any that are already open
20 var inner = current.find('.djDebugPanelContent .scroll'),
19 $('.djdt-panelContent').hide(); // Hide any that are already open
20 var inner = current.find('.djDebugPanelContent .djdt-scroll'),
2121 store_id = $('#djDebug').data('store-id'),
2222 render_panel_url = $('#djDebug').data('render-panel-url');
2323 if (store_id !== '' && inner.children().length === 0) {
3333 inner.prev().remove(); // Remove AJAX loader
3434 inner.html(data);
3535 }).fail(function(xhr){
36 var message = '<div class="djDebugPanelTitle"><a class="djDebugClose djDebugBack" href="">Back</a><h3>'+xhr.status+': '+xhr.statusText+'</h3></div>';
36 var message = '<div class="djDebugPanelTitle"><a class="djDebugClose djDebugBack" href=""></a><h3>'+xhr.status+': '+xhr.statusText+'</h3></div>';
3737 $('#djDebugWindow').html(message).show();
3838 });
3939 }
4040 current.show();
41 $('#djDebugToolbar li').removeClass('active');
42 $(this).parent().addClass('active');
43 }
44 return false;
45 });
46 $(document).on('click', '#djDebug a.djDebugClose', function() {
41 $('#djDebugToolbar li').removeClass('djdt-active');
42 $(this).parent().addClass('djdt-active');
43 }
44 return false;
45 });
46 $('#djDebug').on('click', 'a.djDebugClose', function() {
4747 $(document).trigger('close.djDebug');
48 $('#djDebugToolbar li').removeClass('active');
49 return false;
50 });
51 $(document).on('click', '#djDebug .djDebugPanelButton input[type=checkbox]', function() {
48 $('#djDebugToolbar li').removeClass('djdt-active');
49 return false;
50 });
51 $('#djDebug').on('click', '.djDebugPanelButton input[type=checkbox]', function() {
5252 djdt.cookie.set($(this).attr('data-cookie'), $(this).prop('checked') ? 'on' : 'off', {
5353 path: '/',
5454 expires: 10
5656 });
5757
5858 // Used by the SQL and template panels
59 $(document).on('click', '#djDebug .remoteCall', function() {
59 $('#djDebug').on('click', '.remoteCall', function() {
6060 var self = $(this);
6161 var name = self[0].tagName.toLowerCase();
6262 var ajax_data = {};
7878 $.ajax(ajax_data).done(function(data){
7979 $('#djDebugWindow').html(data).show();
8080 }).fail(function(xhr){
81 var message = '<div class="djDebugPanelTitle"><a class="djDebugClose djDebugBack" href="">Back</a><h3>'+xhr.status+': '+xhr.statusText+'</h3></div>';
81 var message = '<div class="djDebugPanelTitle"><a class="djDebugClose djDebugBack" href=""></a><h3>'+xhr.status+': '+xhr.statusText+'</h3></div>';
8282 $('#djDebugWindow').html(message).show();
8383 });
8484
85 $(document).on('click', '#djDebugWindow a.djDebugBack', function() {
85 $('#djDebugWindow').on('click', 'a.djDebugBack', function() {
8686 $(this).parent().parent().hide();
8787 return false;
8888 });
9191 });
9292
9393 // Used by the cache, profiling and SQL panels
94 $(document).on('click', '#djDebug a.djToggleSwitch', function(e) {
94 $('#djDebug').on('click', 'a.djToggleSwitch', function(e) {
9595 e.preventDefault();
9696 var btn = $(this);
9797 var id = btn.attr('data-toggle-id');
133133 $('#djShowToolBarButton').on('mousedown', function (event) {
134134 var startPageY = event.pageY;
135135 var baseY = handle.offset().top - startPageY;
136 var windowHeight = $(window).height();
136137 $(document).on('mousemove.djDebug', function (event) {
137138 // Chrome can send spurious mousemove events, so don't do anything unless the
138139 // cursor really moved. Otherwise, it will be impossible to expand the toolbar
139140 // due to djdt.handleDragged being set to true.
140141 if (djdt.handleDragged || event.pageY != startPageY) {
141 var offset = handle.offset();
142 offset.top = baseY + event.pageY;
143 handle.offset(offset);
142 var top = baseY + event.clientY;
143
144 if (top < 0) {
145 top = 0;
146 } else if (top + handle.height() > windowHeight) {
147 top = windowHeight - handle.height();
148 }
149
150 handle.css({top: top});
144151 djdt.handleDragged = true;
145152 }
146153 });
149156 $(document).on('mouseup', function () {
150157 $(document).off('mousemove.djDebug');
151158 if (djdt.handleDragged) {
152 var top = handle.offset().top;
159 var top = handle.offset().top - window.pageYOffset;
153160 djdt.cookie.set('djdttop', top, {
154161 path: '/',
155162 expires: 10
167174 return;
168175 }
169176 // If a panel is open, close that
170 if ($('.panelContent').is(':visible')) {
171 $('.panelContent').hide();
172 $('#djDebugToolbar li').removeClass('active');
177 if ($('.djdt-panelContent').is(':visible')) {
178 $('.djdt-panelContent').hide();
179 $('#djDebugToolbar li').removeClass('djdt-active');
173180 return;
174181 }
175182 // Otherwise, just minimize the toolbar
201208 // close any sub panels
202209 $('#djDebugWindow').hide();
203210 // close all panels
204 $('.panelContent').hide();
205 $('#djDebugToolbar li').removeClass('active');
211 $('.djdt-panelContent').hide();
212 $('#djDebugToolbar li').removeClass('djdt-active');
206213 // finally close toolbar
207214 $('#djDebugToolbar').hide('fast');
208215 $('#djDebugToolbarHandle').show();
277284
278285 return value;
279286 }
287 },
288 applyStyle: function(name) {
289 $('#djDebug [data-' + name + ']').each(function() {
290 var css = {};
291 css[name] = $(this).data(name);
292 $(this).css(css);
293 });
280294 }
281295 };
296 $.extend(publicAPI, {
297 show_toolbar: djdt.show_toolbar,
298 hide_toolbar: djdt.hide_toolbar,
299 close: djdt.close,
300 cookie: djdt.cookie,
301 applyStyle: djdt.applyStyle
302 });
282303 $(document).ready(djdt.init);
283 })(djdt.jQuery);
304 })(djdt.jQuery, djdt);
1616 subcalls.hide();
1717 }
1818 });
19 djdt.applyStyle('padding-left');
1920 })(djdt.jQuery);
33 $(this).parent().find('.djDebugCollapsed').toggle();
44 $(this).parent().find('.djDebugUncollapsed').toggle();
55 });
6 djdt.applyStyle('background-color');
7 djdt.applyStyle('left');
8 djdt.applyStyle('width');
69 })(djdt.jQuery);
2323 if (endStat) {
2424 // Render a start through end bar
2525 $row.html('<td>' + stat.replace('Start', '') + '</td>' +
26 '<td class="timeline"><div class="djDebugTimeline"><div class="djDebugLineChart" style="left:' + getLeft(stat) + '%;"><strong style="width:' + getCSSWidth(stat, endStat) + ';">&nbsp;</strong></div></div></td>' +
26 '<td class="timeline"><div class="djDebugTimeline"><div class="djDebugLineChart"><strong>&nbsp;</strong></div></div></td>' +
2727 '<td>' + (perf.timing[stat] - timingOffset) + ' (+' + (perf.timing[endStat] - perf.timing[stat]) + ')</td>');
28 $row.find('strong').css({width: getCSSWidth(stat, endStat)});
2829 } else {
2930 // Render a point in time
3031 $row.html('<td>' + stat + '</td>' +
31 '<td class="timeline"><div class="djDebugTimeline"><div class="djDebugLineChart" style="left:' + getLeft(stat) + '%;"><strong style="width:2px;">&nbsp;</strong></div></div></td>' +
32 '<td class="timeline"><div class="djDebugTimeline"><div class="djDebugLineChart"><strong>&nbsp;</strong></div></div></td>' +
3233 '<td>' + (perf.timing[stat] - timingOffset) + '</td>');
34 $row.find('strong').css({width: 2});
3335 }
36 $row.find('djDebugLineChart').css({left: getLeft(stat) + '%'});
3437 $('#djDebugBrowserTimingTableBody').append($row);
3538 }
3639
0 {% load i18n %}{% load static from staticfiles %}{% load url from future %}
1 <style type="text/css">
2 @media print { #djDebug {display:none;}}
3 </style>
0 {% load i18n %}{% load static from staticfiles %}
1 <link rel="stylesheet" href="{% static 'debug_toolbar/css/print.css' %}" type="text/css" media="print" />
42 <link rel="stylesheet" href="{% static 'debug_toolbar/css/toolbar.css' %}" type="text/css" />
53 {% if toolbar.config.JQUERY_URL %}
64 <!-- Prevent our copy of jQuery from registering as an AMD module on sites that use RequireJS. -->
7 <script>var _djdt_define_backup = window.define; window.define = undefined;</script>
5 <script src="{% static 'debug_toolbar/js/jquery_pre.js' %}"></script>
86 <script src="{{ toolbar.config.JQUERY_URL }}"></script>
9 <script>var djdt = {jQuery: jQuery.noConflict(true)}; window.define = _djdt_define_backup;</script>
7 <script src="{% static 'debug_toolbar/js/jquery_post.js' %}"></script>
108 {% else %}
11 <script>var djdt = {jQuery: jQuery};</script>
9 <script src="{% static 'debug_toolbar/js/jquery_existing.js' %}"></script>
1210 {% endif %}
1311 <script src="{% static 'debug_toolbar/js/toolbar.js' %}"></script>
14 <div id="djDebug" style="display:none;" dir="ltr"
12 <div id="djDebug" hidden="hidden" dir="ltr"
1513 data-store-id="{{ toolbar.store_id }}" data-render-panel-url="{% url 'djdt:render_panel' %}"
1614 {{ toolbar.config.ROOT_TAG_EXTRA_ATTRS|safe }}>
17 <div style="display:none;" id="djDebugToolbar">
15 <div hidden="hidden" id="djDebugToolbar">
1816 <ul id="djDebugPanelList">
1917 {% if toolbar.panels %}
2018 <li><a id="djHideToolBarButton" href="#" title="{% trans "Hide toolbar" %}">{% trans "Hide" %} &#187;</a></li>
2725 {% if panel.has_content and panel.enabled %}
2826 <a href="#" title="{{ panel.title }}" class="{{ panel.panel_id }}">
2927 {% else %}
30 <div class="contentless{% if not panel.enabled %} disabled{% endif %}">
28 <div class="djdt-contentless{% if not panel.enabled %} djdt-disabled{% endif %}">
3129 {% endif %}
3230 {{ panel.nav_title }}
3331 {% if panel.enabled %}
4442 {% endfor %}
4543 </ul>
4644 </div>
47 <div style="display:none;" id="djDebugToolbarHandle">
45 <div hidden="hidden" id="djDebugToolbarHandle">
4846 <span title="{% trans "Show toolbar" %}" id="djShowToolBarButton">&#171;</span>
4947 </div>
5048 {% for panel in toolbar.panels %}
5149 {% if panel.has_content and panel.enabled %}
52 <div id="{{ panel.panel_id }}" class="panelContent">
50 <div id="{{ panel.panel_id }}" class="djdt-panelContent">
5351 <div class="djDebugPanelTitle">
54 <a href="" class="djDebugClose">{% trans "Close" %}</a>
52 <a href="" class="djDebugClose"></a>
5553 <h3>{{ panel.title|safe }}</h3>
5654 </div>
5755 <div class="djDebugPanelContent">
5856 {% if toolbar.store_id %}
59 <img src="{% static 'debug_toolbar/img/ajax-loader.gif' %}" alt="loading" class="loader" />
60 <div class="scroll"></div>
57 <img src="{% static 'debug_toolbar/img/ajax-loader.gif' %}" alt="loading" class="djdt-loader" />
58 <div class="djdt-scroll"></div>
6159 {% else %}
62 <div class="scroll">{{ panel.content }}</div>
60 <div class="djdt-scroll">{{ panel.content }}</div>
6361 {% endif %}
6462 </div>
6563 </div>
6664 {% endif %}
6765 {% endfor %}
68 <div id="djDebugWindow" class="panelContent"></div>
66 <div id="djDebugWindow" class="djdt-panelContent"></div>
6967 </div>
0 {% load i18n %}
0 {% load i18n %}{% load cycle from debug_toolbar_compat %}
11 <h4>{% trans "Summary" %}</h4>
22 <table>
33 <thead>
4949 <tbody>
5050 {% for call in calls %}
5151 <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}" id="cacheMain_{{ forloop.counter }}">
52 <td class="toggle">
53 <a class="djToggleSwitch" data-toggle-name="cacheMain" data-toggle-id="{{ forloop.counter }}" data-toggle-open="+" data-toggle-close="-" href="javascript:void(0)">+</a>
52 <td class="djdt-toggle">
53 <a class="djToggleSwitch" data-toggle-name="cacheMain" data-toggle-id="{{ forloop.counter }}" data-toggle-open="+" data-toggle-close="-" href>+</a>
5454 </td>
5555 <td>{{ call.time|floatformat:"4" }}</td>
5656 <td>{{ call.name|escape }}</td>
6060 </tr>
6161 <tr class="djUnselected djDebugHoverable {% cycle 'djDebugOdd' 'djDebugEven' %} djToggleDetails_{{ forloop.counter }}" id="cacheDetails_{{ forloop.counter }}">
6262 <td colspan="1"></td>
63 <td colspan="5"><pre class="stack">{{ call.trace }}</pre></td>
63 <td colspan="5"><pre class="djdt-stack">{{ call.trace }}</pre></td>
6464 </tr>
6565 {% endfor %}
6666 </tbody>
0 {% load i18n %}
0 {% load i18n %}{% load cycle from debug_toolbar_compat %}
11
22 <h4>{% trans "Request headers" %}</h4>
33
0 {% load i18n %}
0 {% load i18n %}{% load cycle from debug_toolbar_compat %}
11 {% if records %}
22 <table>
33 <thead>
1111 </thead>
1212 <tbody>
1313 {% for call in func_list %}
14 <!-- style="background:{{ call.background }}" -->
1514 <tr class="djDebugProfileRow{% for parent_id in call.parent_ids %} djToggleDetails_{{ parent_id }}{% endfor %}" depth="{{ call.depth }}">
1615 <td>
17 <div style="padding-left: {{ call.indent }}px;">
16 <div data-padding-left="{{ call.indent }}px">
1817 {% if call.has_subfuncs %}
19 <a class="djProfileToggleDetails djToggleSwitch" data-toggle-id="{{ call.id }}" data-toggle-open="+" data-toggle-close="-" href="javascript:void(0)">-</a>
18 <a class="djProfileToggleDetails djToggleSwitch" data-toggle-id="{{ call.id }}" data-toggle-open="+" data-toggle-close="-" href>-</a>
2019 {% else %}
2120 <span class="djNoToggleSwitch"></span>
2221 {% endif %}
23 <span class="stack">{{ call.func_std_string }}</span>
22 <span class="djdt-stack">{{ call.func_std_string }}</span>
2423 </div>
2524 </td>
2625 <td>{{ call.cumtime|floatformat:3 }}</td>
0 {% load i18n %}
0 {% load i18n %}{% load cycle from debug_toolbar_compat %}
11
22 <h4>{% trans "View information" %}</h4>
33 <table>
2323 <h4>{% trans "Cookies" %}</h4>
2424 <table>
2525 <colgroup>
26 <col style="width:20%"/>
26 <col class="djdt-width-20"/>
2727 <col/>
2828 </colgroup>
2929 <thead>
4949 <h4>{% trans "Session data" %}</h4>
5050 <table>
5151 <colgroup>
52 <col style="width:20%"/>
52 <col class="djdt-width-20"/>
5353 <col/>
5454 </colgroup>
5555 <thead>
7575 <h4>{% trans "GET data" %}</h4>
7676 <table>
7777 <colgroup>
78 <col style="width:20%"/>
78 <col class="djdt-width-20"/>
7979 <col/>
8080 </colgroup>
8181 <thead>
101101 <h4>{% trans "POST data" %}</h4>
102102 <table>
103103 <colgroup>
104 <col style="width:20%"/>
104 <col class="djdt-width-20"/>
105105 <col/>
106 </colgr
106 </colgroup>
107107 <tr>
108108 <th>{% trans "Variable" %}</th>
109109 <th>{% trans "Value" %}</th>
0 {% load i18n %}
0 {% load i18n %}{% load cycle from debug_toolbar_compat %}
11 <table>
22 <thead>
33 <tr>
0 {% load i18n %}
0 {% load i18n %}{% load cycle from debug_toolbar_compat %}
11 <table>
22 <thead>
33 <tr>
0 {% load i18n l10n %}{% load static from staticfiles %}{% load url from future %}
1 <div class="clearfix">
2 <ul class="stats">
0 {% load i18n l10n %}{% load cycle from debug_toolbar_compat %}{% load static from staticfiles %}
1 <div class="djdt-clearfix">
2 <ul class="djdt-stats">
33 {% for alias, info in databases %}
44 <li>
5 <strong class="label"><span style="background-color: rgb({{ info.rgb_color|join:", " }})" class="color">&#160;</span> {{ alias }}</strong>
6 <span class="info">{{ info.time_spent|floatformat:"2" }} ms ({% blocktrans count info.num_queries as num %}{{ num }} query{% plural %}{{ num }} queries{% endblocktrans %})</span>
5 <strong class="djdt-label"><span data-background-color="rgb({{ info.rgb_color|join:", " }})" class="djdt-color">&#160;</span> {{ alias }}</strong>
6 <span class="djdt-info">{{ info.time_spent|floatformat:"2" }} ms ({% blocktrans count info.num_queries as num %}{{ num }} query{% plural %}{{ num }} queries{% endblocktrans %}
7 {% if info.duplicate_count %}
8 {% blocktrans with dupes=info.duplicate_count %}including {{ dupes }} duplicates{% endblocktrans %}
9 {% endif %})</span>
710 </li>
811 {% endfor %}
912 </ul>
1316 <table>
1417 <thead>
1518 <tr>
16 <th class="color">&#160;</th>
19 <th class="djdt-color">&#160;</th>
1720 <th class="query" colspan="2">{% trans "Query" %}</th>
1821 <th class="timeline">{% trans "Timeline" %}</th>
19 <th class="time">{% trans "Time (ms)" %}</th>
20 <th class="actions">{% trans "Action" %}</th>
22 <th class="djdt-time">{% trans "Time (ms)" %}</th>
23 <th class="djdt-actions">{% trans "Action" %}</th>
2124 </tr>
2225 </thead>
2326 <tbody>
2427 {% for query in queries %}
2528 <tr class="djDebugHoverable {% cycle 'djDebugOdd' 'djDebugEven' %}{% if query.is_slow %} djDebugRowWarning{% endif %}{% if query.starts_trans %} djDebugStartTransaction{% endif %}{% if query.ends_trans %} djDebugEndTransaction{% endif %}{% if query.in_trans %} djDebugInTransaction{% endif %}" id="sqlMain_{{ forloop.counter }}">
26 <td class="color"><span style="background-color: rgb({{ query.rgb_color|join:", " }});">&#160;</span></td>
27 <td class="toggle">
28 <a class="djToggleSwitch" data-toggle-name="sqlMain" data-toggle-id="{{ forloop.counter }}" data-toggle-open="+" data-toggle-close="-" href="javascript:void(0)">+</a>
29 <td class="djdt-color"><span data-background-color="rgb({{ query.rgb_color|join:", " }})">&#160;</span></td>
30 <td class="djdt-toggle">
31 <a class="djToggleSwitch" data-toggle-name="sqlMain" data-toggle-id="{{ forloop.counter }}" data-toggle-open="+" data-toggle-close="-" href>+</a>
2932 </td>
3033 <td class="query">
3134 <div class="djDebugSqlWrap">
3235 <div class="djDebugSql">{{ query.sql|safe }}</div>
3336 </div>
37 {% if query.duplicate_count %}
38 <strong>{% blocktrans with dupes=query.duplicate_count %}Duplicated {{ dupes }} times.{% endblocktrans %}
39 </strong>
40 {% endif %}
3441 </td>
3542 <td class="timeline">
36 <div class="djDebugTimeline"><div class="djDebugLineChart{% if query.is_slow %} djDebugLineChartWarning{% endif %}" style="left:{{ query.start_offset|unlocalize }}%;"><strong style="width:{{ query.width_ratio_relative|unlocalize }}%; background-color:{{ query.trace_color }};">{{ query.width_ratio }}%</strong></div></div>
43 <div class="djDebugTimeline"><div class="djDebugLineChart{% if query.is_slow %} djDebugLineChartWarning{% endif %}" data-left="{{ query.start_offset|unlocalize }}%"><strong data-width="{{ query.width_ratio_relative|unlocalize }}%" data-background-color"{{ query.trace_color }}">{{ query.width_ratio }}%</strong></div></div>
3744 </td>
38 <td class="time">
45 <td class="djdt-time">
3946 {{ query.duration|floatformat:"2" }}
4047 </td>
41 <td class="actions">
48 <td class="djdt-actions">
4249
4350 {% if query.params %}
4451 {% if query.is_select %}
6875 <p><strong>{% trans "Transaction status:" %}</strong> {{ query.trans_status }}</p>
6976 {% endif %}
7077 {% if query.stacktrace %}
71 <pre class="stack">{{ query.stacktrace }}</pre>
78 <pre class="djdt-stack">{{ query.stacktrace }}</pre>
7279 {% endif %}
7380 {% if query.template_info %}
7481 <table>
7582 {% for line in query.template_info.context %}
7683 <tr>
7784 <td>{{ line.num }}</td>
78 <td><code style="font-family: monospace;{% if line.highlight %}background-color: lightgrey{% endif %}">{{ line.content }}</code></td>
85 <td><code {% if line.highlight %}class="djdt-highlighted"{% endif %}>{{ line.content }}</code></td>
7986 </tr>
8087 {% endfor %}
8188 </table>
0 {% load i18n %}{% load static from staticfiles %}
0 {% load i18n %}{% load cycle from debug_toolbar_compat %}{% load static from staticfiles %}
11 <div class="djDebugPanelTitle">
2 <a class="djDebugClose djDebugBack" href="">{% trans "Back" %}</a>
2 <a class="djDebugClose djDebugBack" href=""></a>
33 <h3>{% trans "SQL explained" %}</h3>
44 </div>
55 <div class="djDebugPanelContent">
6 <div class="scroll">
6 <div class="djdt-scroll">
77 <dl>
88 <dt>{% trans "Executed SQL" %}</dt>
99 <dd>{{ sql|safe }}</dd>
0 {% load i18n %}{% load static from staticfiles %}
0 {% load i18n %}{% load cycle from debug_toolbar_compat %}{% load static from staticfiles %}
11 <div class="djDebugPanelTitle">
2 <a class="djDebugClose djDebugBack" href="">{% trans "Back" %}</a>
2 <a class="djDebugClose djDebugBack" href=""></a>
33 <h3>{% trans "SQL profiled" %}</h3>
44 </div>
55 <div class="djDebugPanelContent">
6 <div class="scroll">
6 <div class="djdt-scroll">
77 {% if result %}
88 <dl>
99 <dt>{% trans "Executed SQL" %}</dt>
0 {% load i18n %}{% load static from staticfiles %}
0 {% load i18n %}{% load cycle from debug_toolbar_compat %}{% load static from staticfiles %}
11 <div class="djDebugPanelTitle">
2 <a class="djDebugClose djDebugBack" href="">{% trans "Back" %}</a>
2 <a class="djDebugClose djDebugBack" href=""></a>
33 <h3>{% trans "SQL selected" %}</h3>
44 </div>
55 <div class="djDebugPanelContent">
6 <div class="scroll">
6 <div class="djdt-scroll">
77 <dl>
88 <dt>{% trans "Executed SQL" %}</dt>
99 <dd>{{ sql|safe }}</dd>
0 {% load i18n %}
1 {% load static from staticfiles%}
0 {% load i18n %}{% load cycle from debug_toolbar_compat %}{% load static from staticfiles%}
21
32 <h4>{% blocktrans count staticfiles_dirs|length as dirs_count %}Static file path{% plural %}Static file paths{% endblocktrans %}</h4>
43 {% if staticfiles_dirs %}
00 {% load i18n %}
11 <div class="djDebugPanelTitle">
2 <a class="djDebugClose djDebugBack" href="">{% trans "Back" %}</a>
2 <a class="djDebugClose djDebugBack" href=""></a>
33 <h3>{% trans "Template source:" %} <code>{{ template_name }}</code></h3>
44 </div>
55 <div class="djDebugPanelContent">
6 <div class="scroll">
6 <div class="djdt-scroll">
77 {% if not source.pygmentized %}
88 <code>{{ source }}</code>
99 {% else %}
0 {% load i18n %}{% load static from staticfiles %}{% load url from future %}
0 {% load i18n %}{% load static from staticfiles %}
11 <h4>{% blocktrans count template_dirs|length as template_count %}Template path{% plural %}Template paths{% endblocktrans %}</h4>
22 {% if template_dirs %}
33 <ol>
1818 {% if template.context %}
1919 <dd>
2020 <div class="djTemplateShowContextDiv"><a class="djTemplateShowContext"><span class="toggleArrow">&#x25B6;</span> {% trans "Toggle context" %}</a></div>
21 <div class="djTemplateHideContextDiv" style="display:none;"><code>{{ template.context }}</code></div>
21 <div class="djTemplateHideContextDiv" hidden="hidden"><code>{{ template.context }}</code></div>
2222 </dd>
2323 {% endif %}
2424 {% endfor %}
3434 <dt><strong>{{ key|escape }}</strong></dt>
3535 <dd>
3636 <div class="djTemplateShowContextDiv"><a class="djTemplateShowContext"><span class="toggleArrow">&#x25B6;</span> {% trans "Toggle context" %}</a></div>
37 <div class="djTemplateHideContextDiv" style="display:none;"><code>{{ value|escape }}</code></div>
37 <div class="djTemplateHideContextDiv" hidden="hidden"><code>{{ value|escape }}</code></div>
3838 </dd>
3939 {% endfor %}
4040 </dl>
0 {% load i18n %}{% load static from staticfiles %}
0 {% load i18n %}{% load cycle from debug_toolbar_compat %}{% load static from staticfiles %}
11 <h4>{% trans "Resource usage" %}</h4>
22 <table>
33 <colgroup>
4 <col style="width:20%"/>
4 <col class="djdt-width-20"/>
55 <col/>
66 </colgroup>
77 <thead>
2121 </table>
2222
2323 <!-- This hidden div is populated and displayed by code in toolbar.timer.js -->
24 <div id="djDebugBrowserTiming" style="display:none">
24 <div id="djDebugBrowserTiming" hidden="hidden">
2525 <h4>{% trans "Browser timing" %}</h4>
2626 <table>
2727 <colgroup>
28 <col style="width:20%"/>
29 <col style="width:60%"/>
30 <col style="width:20%"/>
28 <col class="djdt-width-20"/>
29 <col class="djdt-width-60"/>
30 <col class="djdt-width-20"/>
3131 </colgroup>
3232 <thead>
3333 <tr>
3434 <th>{% trans "Timing attribute" %}</th>
3535 <th class="timeline">{% trans "Timeline" %}</th>
36 <th class="time">{% trans "Milliseconds since navigation start (+length)" %}</th>
36 <th class="djdt-time">{% trans "Milliseconds since navigation start (+length)" %}</th>
3737 </tr>
3838 </thead>
3939 <tbody id="djDebugBrowserTimingTableBody">
0 {% load i18n %}
0 {% load i18n %}{% load cycle from debug_toolbar_compat %}
11 <table>
22 <thead>
33 <tr>
0 import django
1 from django.template import Library
2
3 if django.VERSION >= (1, 8):
4 from django.template.defaulttags import cycle
5 else:
6 from django.templatetags.future import cycle
7
8
9 register = Library()
10
11
12 cycle = register.tag(cycle)
44 from __future__ import absolute_import, unicode_literals
55
66 import uuid
7 from collections import OrderedDict
8 from importlib import import_module
79
8 import django
9 from django.conf import settings
10 from django.conf.urls import patterns, url
10 from django.apps import apps
11 from django.conf.urls import url
1112 from django.core.exceptions import ImproperlyConfigured
1213 from django.template import TemplateSyntaxError
1314 from django.template.loader import render_to_string
14 from django.utils.importlib import import_module
15 try:
16 from collections import OrderedDict
17 except ImportError:
18 from django.utils.datastructures import SortedDict as OrderedDict
1915
2016 from debug_toolbar import settings as dt_settings
2117
6662 context = {'toolbar': self}
6763 return render_to_string('debug_toolbar/base.html', context)
6864 except TemplateSyntaxError:
69 if django.VERSION[:2] >= (1, 7):
70 from django.apps import apps
71 staticfiles_installed = apps.is_installed(
72 'django.contrib.staticfiles')
73 else:
74 staticfiles_installed = ('django.contrib.staticfiles'
75 in settings.INSTALLED_APPS)
76 if not staticfiles_installed:
65 if not apps.is_installed('django.contrib.staticfiles'):
7766 raise ImproperlyConfigured(
7867 "The debug toolbar requires the staticfiles contrib app. "
7968 "Add 'django.contrib.staticfiles' to INSTALLED_APPS and "
8877 def should_render_panels(self):
8978 render_panels = self.config['RENDER_PANELS']
9079 if render_panels is None:
91 # Django 1.4 still supports mod_python :( Fall back to the safe
92 # and inefficient default in that case. Revert when we drop 1.4.
93 render_panels = self.request.META.get('wsgi.multiprocess', True)
80 render_panels = self.request.META['wsgi.multiprocess']
9481 return render_panels
9582
9683 def store(self):
9784 self.store_id = uuid.uuid4().hex
9885 cls = type(self)
9986 cls._store[self.store_id] = self
100 for _ in range(len(cls._store) - self.config['RESULTS_STORE_SIZE']):
87 for _ in range(len(cls._store) - self.config['RESULTS_CACHE_SIZE']):
10188 try:
10289 # collections.OrderedDict
10390 cls._store.popitem(last=False)
147134 @classmethod
148135 def get_urls(cls):
149136 if cls._urlpatterns is None:
137 from . import views
150138 # Load URLs in a temporary variable for thread safety.
151139 # Global URLs
152 urlpatterns = patterns('debug_toolbar.views', # noqa
153 url(r'^render_panel/$', 'render_panel', name='render_panel'),
154 )
140 urlpatterns = [
141 url(r'^render_panel/$', views.render_panel, name='render_panel'),
142 ]
155143 # Per-panel URLs
156144 for panel_class in cls.get_panel_classes():
157145 urlpatterns += panel_class.get_urls()
33 import os.path
44 import re
55 import sys
6 from importlib import import_module
7
8 import django
9 from django.core.exceptions import ImproperlyConfigured
10 from django.template import Node
11 from django.utils import six
12 from django.utils.encoding import force_text
13 from django.utils.html import escape
14 from django.utils.safestring import mark_safe
15
16 from debug_toolbar.compat import linebreak_iter
17
18 from .settings import CONFIG
19
620 try:
721 import threading
822 except ImportError:
923 threading = None
1024
11 import django
12 from django.core.exceptions import ImproperlyConfigured
13 from django.utils.encoding import force_text
14 from django.utils.html import escape
15 from django.utils.importlib import import_module
16 from django.utils.safestring import mark_safe
17 from django.utils import six
18 from django.views.debug import linebreak_iter
19
20 from .settings import CONFIG
2125
2226 # Figure out some paths
2327 django_path = os.path.realpath(os.path.dirname(django.__file__))
7074 params = map(escape, frame[0].rsplit(os.path.sep, 1) + list(frame[1:]))
7175 params_dict = dict((six.text_type(idx), v) for idx, v in enumerate(params))
7276 try:
73 stacktrace.append('<span class="path">%(0)s/</span>'
74 '<span class="file">%(1)s</span>'
75 ' in <span class="func">%(3)s</span>'
76 '(<span class="lineno">%(2)s</span>)\n'
77 ' <span class="code">%(4)s</span>'
77 stacktrace.append('<span class="djdt-path">%(0)s/</span>'
78 '<span class="djdt-file">%(1)s</span>'
79 ' in <span class="djdt-func">%(3)s</span>'
80 '(<span class="djdt-lineno">%(2)s</span>)\n'
81 ' <span class="djdt-code">%(4)s</span>'
7882 % params_dict)
7983 except KeyError:
8084 # This frame doesn't have the expected format, so skip it and move on to the next one
8286 return mark_safe('\n'.join(stacktrace))
8387
8488
85 def get_template_info(source, context_lines=3):
89 def get_template_info():
90 template_info = None
91 cur_frame = sys._getframe().f_back
92 try:
93 while cur_frame is not None:
94 in_utils_module = cur_frame.f_code.co_filename.endswith(
95 "/debug_toolbar/utils.py"
96 )
97 is_get_template_context = (
98 cur_frame.f_code.co_name == get_template_context.__name__
99 )
100 if in_utils_module and is_get_template_context:
101 # If the method in the stack trace is this one
102 # then break from the loop as it's being check recursively.
103 break
104 elif cur_frame.f_code.co_name == 'render':
105 node = cur_frame.f_locals['self']
106 if isinstance(node, Node):
107 template_info = get_template_context(node.source)
108 break
109 cur_frame = cur_frame.f_back
110 except Exception:
111 pass
112 del cur_frame
113 return template_info
114
115
116 def get_template_context(source, context_lines=3):
86117 line = 0
87118 upto = 0
88119 source_lines = []
00 Change log
11 ==========
2
3 1.4
4 ---
5
6 This version is compatible with the upcoming Django 1.9 release. It requires
7 Django 1.7 or later.
8
9 New features
10 ~~~~~~~~~~~~
11
12 * New panel method :meth:`debug_toolbar.panels.Panel.generate_stats` allows panels
13 to only record stats when the toolbar is going to be inserted into the
14 response.
15
16 Bugfixes
17 ~~~~~~~~
18
19 * Response time for requests of projects with numerous media files has
20 been improved.
21
22 1.3
23 ---
24
25 This is the first version compatible with Django 1.8.
26
27 New features
28 ~~~~~~~~~~~~
29
30 * A new panel is available: Template Profiler.
31 * The ``SHOW_TOOLBAR_CALLBACK`` accepts a callable.
32 * The toolbar now provides a :ref:`javascript-api`.
33
34 Bugfixes
35 ~~~~~~~~
36
37 * The toolbar handle cannot leave the visible area anymore when the toolbar is
38 collapsed.
39 * The root level logger is preserved.
40 * The ``RESULTS_CACHE_SIZE`` setting is taken into account.
41 * CSS classes are prefixed with ``djdt-`` to prevent name conflicts.
42 * The private copy of jQuery no longer registers as an AMD module on sites
43 that load RequireJS.
244
345 1.2
446 ---
1111 # All configuration values have a default; values that are commented out
1212 # serve to show the default.
1313
14 import datetime
1415 import sys
1516 import os
1617
4950
5051 # General information about the project.
5152 project = u'Django Debug Toolbar'
52 copyright = u'2013, Django Debug Toolbar developers and contributors'
53 copyright = u'{}, Django Debug Toolbar developers and contributors'
54 copyright = copyright.format(datetime.date.today().year)
5355
5456 # The version info for the project you're documenting, acts as replacement for
5557 # |version| and |release|, also used in various other places throughout the
5658 # built documents.
5759 #
5860 # The short X.Y version.
59 version = '1.2'
61 version = '1.4'
6062 # The full version, including alpha/beta/rc tags.
61 release = '1.2.1'
63 release = '1.4'
6264
6365 # The language for content autogenerated by Sphinx. Refer to documentation
6466 # for a list of supported languages.
7272
7373 * ``JQUERY_URL``
7474
75 Default: ``'//ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js'``
75 Default: ``'//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'``
7676
7777 URL of the copy of jQuery that will be used by the toolbar. Set it to a
7878 locally-hosted version of jQuery for offline development. Make it empty to
9292 right thing depending on whether the WSGI container runs multiple processes.
9393 This setting allows you to force a different behavior if needed.
9494
95 * ``RESULTS_STORE_SIZE``
95 * ``RESULTS_CACHE_SIZE``
9696
9797 Default: ``10``
9898
120120 This is the dotted path to a function used for determining whether the
121121 toolbar should show or not. The default checks are that ``DEBUG`` must be
122122 set to ``True``, the IP of the request must be in ``INTERNAL_IPS``, and the
123 request must no be an AJAX request. You can provide your own function
123 request must not be an AJAX request. You can provide your own function
124124 ``callback(request)`` which returns ``True`` or ``False``.
125125
126126 Panel options
190190 # This example is unlikely to be appropriate for your project.
191191 CONFIG_DEFAULTS = {
192192 # Toolbar options
193 'RESULTS_STORE_SIZE': 3,
193 'RESULTS_CACHE_SIZE': 3,
194194 'SHOW_COLLAPSED': True,
195195 # Panel options
196196 'SQL_WARNING_THRESHOLD': 100, # milliseconds
2323
2424 You can run now run the example application::
2525
26 $ DJANGO_SETTINGS_MODULE=example.settings django-admin.py syncdb
27 $ DJANGO_SETTINGS_MODULE=example.settings django-admin.py runserver
26 $ DJANGO_SETTINGS_MODULE=example.settings django-admin migrate
27 $ DJANGO_SETTINGS_MODULE=example.settings django-admin runserver
2828
2929 For convenience, there's an alias for the second command::
3030
7575
7676 $ make flake8
7777
78 Import style is enforce by isort. You can sort import automatically with::
79
80 $ make isort
81
7882 Patches
7983 -------
8084
2222
2323 Make sure that ``'django.contrib.staticfiles'`` is `set up properly
2424 <https://docs.djangoproject.com/en/stable/howto/static-files/>`_ and add
25 ``'debug_toolbar.apps.DebugToolbarConfig'`` (Django ≥ 1.7) or
26 ``'debug_toolbar'`` (Django < 1.7) to your ``INSTALLED_APPS`` setting::
25 ``'debug_toolbar'`` to your ``INSTALLED_APPS`` setting::
2726
2827 INSTALLED_APPS = (
2928 # ...
3029 'django.contrib.staticfiles',
3130 # ...
32 # If you're using Django 1.7.x or later
33 'debug_toolbar.apps.DebugToolbarConfig',
34 # If you're using Django 1.6.x or earlier
3531 'debug_toolbar',
3632 )
3733
6359 crashes with a long stack trace after hitting an :exc:`ImportError` or an
6460 :exc:`~django.core.exceptions.ImproperlyConfigured` exception, follow the
6561 explicit setup instructions.
62
63 When the automatic setup is used, the Debug Toolbar is not compatible with
64 :class:`~django.middleware.gzip.GZipMiddleware`. Please disable that
65 middleware during development or use the explicit setup to allow the
66 toolbar to function properly.
6667
6768 Explicit setup
6869 --------------
108109 The order of ``MIDDLEWARE_CLASSES`` is important. You should include the Debug
109110 Toolbar middleware as early as possible in the list. However, it must come
110111 after any other middleware that encodes the response's content, such as
111 ``GZipMiddleware``.
112 :class:`~django.middleware.gzip.GZipMiddleware`.
112113
113114 If ``MIDDLEWARE_CLASSES`` doesn't contain the middleware, the Debug Toolbar
114115 automatically adds it the beginning of the list.
7474
7575 Path: ``debug_toolbar.panels.cache.CachePanel``
7676
77 Cache queries.
77 Cache queries. Is incompatible with Django's per-site caching.
7878
7979 Signal
8080 ~~~~~~
104104 panel is included but inactive by default. You can activate it by default with
105105 the ``DISABLE_PANELS`` configuration option.
106106
107
108107 Non-default built-in panels
109108 ---------------------------
110109
111110 The following panels are disabled by default. You must add them to the
112111 ``DEBUG_TOOLBAR_PANELS`` setting to enable them.
113112
113 .. _profiling-panel:
114
114115 Profiling
115116 ~~~~~~~~~
116117
117118 Path: ``debug_toolbar.panels.profiling.ProfilingPanel``
118119
119 Profiling information for the view function.
120 Profiling information for the processing of the request.
121
122 If the ``debug_toolbar.middleware.DebugToolbarMiddleware`` is first in
123 ``MIDDLEWARE_CLASSES`` then the other middlewares' ``process_view`` methods
124 will not be executed. This is because ``ProfilingPanel.process_view`` will
125 return a ``HttpResponse`` which causes the other middlewares'
126 ``process_view`` methods to be skipped.
127
128 Note that the quick setup creates this situation, as it inserts
129 ``DebugToolbarMiddleware`` first in ``MIDDLEWARE_CLASSES``.
130
131 If you run into this issues, then you should either disable the
132 ``ProfilingPanel`` or move ``DebugToolbarMiddleware`` to the end of
133 ``MIDDLEWARE_CLASSES``. If you do the latter, then the debug toolbar won't
134 track the execution of other middleware.
120135
121136 Third-party panels
122137 ------------------
200215 Path: ``neo4j_panel.Neo4jPanel``
201216
202217 Trace neo4j rest API calls in your django application, this also works for neo4django and neo4jrestclient, support for py2neo is on its way.
218
219 Pympler
220 ~~~~~~~
221
222 URL: https://pythonhosted.org/Pympler/django.html
223
224 Path: ``pympler.panels.MemoryPanel``
225
226 Shows process memory information (virtual size, resident set size) and model instances for the current request.
227
228 Request History
229 ~~~~~~~~~~~~~~~
230
231 URL: https://github.com/djsutho/django-debug-toolbar-request-history
232
233 Path: ``ddt_request_history.panels.request_history.RequestHistoryPanel``
234
235 Switch between requests to view their stats. Also adds support for viewing stats for ajax requests.
203236
204237 Sites
205238 ~~~~~
213246 <https://bitbucket.org/uysrc/django-dynamicsites/src>`_ which sets SITE_ID
214247 dynamically.
215248
249 Template Profiler
250 ~~~~~~~~~~~~~~~~~
251
252 URL: https://github.com/node13h/django-debug-toolbar-template-profiler
253
254 Path: ``template_profiler_panel.panels.template.TemplateProfilerPanel``
255
256 Shows template render call duration and distribution on the timeline. Lightweight.
257 Compatible with WSGI servers which reuse threads for multiple requests (Werkzeug).
258
216259 Template Timings
217260 ~~~~~~~~~~~~~~~~
218261
238281 according to the public API described below. Unless noted otherwise, all
239282 methods are optional.
240283
241 Panels can ship their own templates, static files and views. They're no public
242 CSS or JavaScript API at this time, but they can assume jQuery is available in
243 ``djdt.jQuery``.
284 Panels can ship their own templates, static files and views. There is no public
285 CSS API at this time.
244286
245287 .. autoclass:: debug_toolbar.panels.Panel(*args, **kwargs)
246288
271313 .. automethod:: debug_toolbar.panels.Panel.process_view
272314
273315 .. automethod:: debug_toolbar.panels.Panel.process_response
316
317 .. automethod:: debug_toolbar.panels.Panel.generate_stats
318
319 .. _javascript-api:
320
321 JavaScript API
322 ~~~~~~~~~~~~~~
323
324 Panel templates should include any JavaScript files they need. There are a few
325 common methods available, as well as the toolbar's version of jQuery.
326
327 .. js:function:: djdt.close
328
329 Triggers the event to close any active panels.
330
331 .. js:function:: djdt.cookie.get
332
333 This is a helper function to fetch values stored in the cookies.
334
335 :param string key: The key for the value to be fetched.
336
337 .. js:function:: djdt.cookie.set
338
339 This is a helper function to set a value stored in the cookies.
340
341 :param string key: The key to be used.
342
343 :param string value: The value to be set.
344
345 :param Object options: The options for the value to be set. It should contain
346 the properties ``expires`` and ``path``.
347
348 .. js:function:: djdt.hide_toolbar
349
350 Closes any panels and hides the toolbar.
351
352 .. js:function:: djdt.jQuery
353
354 This is the toolbar's version of jQuery.
355
356 .. js:function:: djdt.show_toolbar
357
358 Shows the toolbar.
33 The toolbar isn't displayed!
44 ----------------------------
55
6 The Debug Toolbar will only display itself if the mimetype of the response is
6 The Debug Toolbar will only display when ``DEBUG = True`` in your project's
7 settings. It will also only display if the mimetype of the response is
78 either ``text/html`` or ``application/xhtml+xml`` and contains a closing
89 ``</body>`` tag.
910
1112 requests and return responses. Putting the debug toolbar middleware *after*
1213 the Flatpage middleware, for example, means the toolbar will not show up on
1314 flatpages.
15
16 Middleware isn't working correctly
17 ----------------------------------
18
19 Using the Debug Toolbar in its default configuration and with the profiling
20 panel will cause middlewares after
21 ``debug_toolbar.middleware.DebugToolbarMiddleware`` to not execute their
22 ``process_view`` functions. This can be resolved by disabling the profiling
23 panel or moving the ``DebugToolbarMiddleware`` to the end of
24 ``MIDDLEWARE_CLASSES``. Read more about it at
25 :ref:`ProfilingPanel <profiling-panel>`
1426
1527 Using the toolbar offline
1628 -------------------------
7183 By default, data gathered during the last 10 requests is kept in memory. This
7284 allows you to use the toolbar on a page even if you have browsed to a few
7385 other pages since you first loaded that page. You can reduce memory
74 consumption by setting the ``PANELS_CACHE_SIZE`` configuration option to a
86 consumption by setting the ``RESULTS_CACHE_SIZE`` configuration option to a
7587 lower value. At worst, the toolbar will tell you that the data you're looking
7688 for isn't available anymore.
7789
44 -----
55
66 This sample project demonstrates how to use the debug toolbar. It is designed
7 to run under the latest stable version of Django, currently 1.5.x.
7 to run under the latest stable version of Django.
88
99 It also provides a few test pages to ensure the debug toolbar doesn't
1010 interfere with common JavaScript frameworks.
2121
2222 Before running the example for the first time, you must create a database::
2323
24 $ PYTHONPATH=. django-admin.py syncdb --settings=example.settings
24 $ PYTHONPATH=. django-admin syncdb --settings=example.settings
2525
2626 Then you can use the following command to run the example::
2727
28 $ PYTHONPATH=. django-admin.py runserver --settings=example.settings
28 $ PYTHONPATH=. django-admin runserver --settings=example.settings
00 """Django settings for example project."""
11
22 import os
3
34 BASE_DIR = os.path.dirname(os.path.dirname(__file__))
45
56
2223 'django.contrib.messages',
2324 'django.contrib.staticfiles',
2425 'debug_toolbar',
26 )
27
28 MIDDLEWARE_CLASSES = (
29 'django.middleware.common.CommonMiddleware',
30 'django.contrib.sessions.middleware.SessionMiddleware',
31 'django.contrib.auth.middleware.AuthenticationMiddleware',
32 'django.contrib.messages.middleware.MessageMiddleware',
33 'django.middleware.csrf.CsrfViewMiddleware',
2534 )
2635
2736 ROOT_URLCONF = 'example.urls'
0 from django.conf.urls import patterns, include
0 from django.conf.urls import include, url
11 from django.contrib import admin
22 from django.views.generic import TemplateView
33
4 admin.autodiscover()
5
6 urlpatterns = patterns('', # noqa
7 (r'^$', TemplateView.as_view(template_name='index.html')),
8 (r'^jquery/$', TemplateView.as_view(template_name='jquery/index.html')),
9 (r'^mootools/$', TemplateView.as_view(template_name='mootools/index.html')),
10 (r'^prototype/$', TemplateView.as_view(template_name='prototype/index.html')),
11 (r'^admin/', include(admin.site.urls)),
12 )
4 urlpatterns = [
5 url(r'^$', TemplateView.as_view(template_name='index.html')),
6 url(r'^jquery/$', TemplateView.as_view(template_name='jquery/index.html')),
7 url(r'^mootools/$', TemplateView.as_view(template_name='mootools/index.html')),
8 url(r'^prototype/$', TemplateView.as_view(template_name='prototype/index.html')),
9 url(r'^admin/', include(admin.site.urls)),
10 ]
00 """WSGI config for example project."""
11
22 import os
3
4 from django.core.wsgi import get_wsgi_application
5
36 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings")
47
5 from django.core.wsgi import get_wsgi_application
68 application = get_wsgi_application()
99 # Testing
1010
1111 coverage
12 django-discover-runner
12 isort
1313 flake8
1414 selenium
1515 tox
44 ignore = W601 ; # noqa doesn't silence this one
55 max-line-length = 100
66
7 [isort]
8 combine_as_imports = true
9 default_section = THIRDPARTY
10 include_trailing_comma = true
11 known_first_party = debug_toolbar
12 multi_line_output = 5
13 not_skip = __init__.py
14
715 [wheel]
816 universal = 1
0 from setuptools import setup, find_packages
10 from io import open
1
2 from setuptools import find_packages, setup
23
34 setup(
45 name='django-debug-toolbar',
5 version='1.2.1',
6 version='1.4',
67 description='A configurable set of panels that display various debug '
78 'information about the current request/response.',
89 long_description=open('README.rst', encoding='utf-8').read(),
1112 url='https://github.com/django-debug-toolbar/django-debug-toolbar',
1213 download_url='https://pypi.python.org/pypi/django-debug-toolbar',
1314 license='BSD',
14 packages=find_packages(exclude=('tests', 'example')),
15 packages=find_packages(exclude=('tests.*', 'tests', 'example')),
1516 install_requires=[
16 'django>=1.4.2',
17 'Django>=1.7',
1718 'sqlparse',
1819 ],
1920 include_package_data=True,
2728 'Operating System :: OS Independent',
2829 'Programming Language :: Python',
2930 'Programming Language :: Python :: 2',
30 'Programming Language :: Python :: 2.6',
3131 'Programming Language :: Python :: 2.7',
3232 'Programming Language :: Python :: 3',
3333 'Programming Language :: Python :: 3.2',
3434 'Programming Language :: Python :: 3.3',
3535 'Programming Language :: Python :: 3.4',
36 'Programming Language :: Python :: 3.5',
3637 'Topic :: Software Development :: Libraries :: Python Modules',
3738 ],
3839 )
00 # Refresh the debug toolbar's configuration when overriding settings.
1
2 from debug_toolbar.toolbar import DebugToolbar
3 from debug_toolbar import settings as dt_settings
41
52 from django.dispatch import receiver
63 from django.test.signals import setting_changed
4
5 from debug_toolbar import settings as dt_settings
6 from debug_toolbar.toolbar import DebugToolbar
77
88
99 @receiver(setting_changed)
22 import threading
33
44 from django.http import HttpResponse
5 from django.test import TestCase, RequestFactory
5 from django.test import RequestFactory, TestCase
66
77 from debug_toolbar.middleware import DebugToolbarMiddleware
88 from debug_toolbar.toolbar import DebugToolbar
33
44 from django.contrib.auth.models import User
55 from django.core import management
6 try:
7 from django.db.backends import utils
8 except ImportError:
9 from django.db.backends import util as utils
6 from django.db.backends import utils as db_backends_utils
107 from django.test import TestCase
118 from django.test.utils import override_settings
129 from django.utils import six
1613 class DebugSQLShellTestCase(TestCase):
1714
1815 def setUp(self):
19 self.original_cursor_wrapper = utils.CursorDebugWrapper
16 self.original_cursor_wrapper = db_backends_utils.CursorDebugWrapper
2017 # Since debugsqlshell monkey-patches django.db.backends.utils, we can
2118 # test it simply by loading it, without executing it. But we have to
2219 # undo the monkey-patch on exit.
2522 management.load_command_class(app_name, command_name)
2623
2724 def tearDown(self):
28 utils.CursorDebugWrapper = self.original_cursor_wrapper
25 db_backends_utils.CursorDebugWrapper = self.original_cursor_wrapper
2926
3027 def test_command(self):
3128 original_stdout, sys.stdout = sys.stdout, six.StringIO()
3229 try:
3330 User.objects.count()
34 self.assertIn("SELECT COUNT(*)", sys.stdout.getvalue())
31 self.assertIn("SELECT COUNT", sys.stdout.getvalue())
3532 finally:
3633 sys.stdout = original_stdout
0 import django
1 from django.contrib.auth.models import User
2 from django.template.loaders.app_directories import Loader
3
4
5 class LoaderWithSQL(Loader):
6
7 if django.VERSION[:2] >= (1, 9):
8 def get_template(self, *args, **kwargs):
9 # Force the template loader to run some SQL. Simulates a CMS.
10 User.objects.all().count()
11 return super(LoaderWithSQL, self).get_template(*args, **kwargs)
12 else:
13 def load_template(self, *args, **kwargs):
14 # Force the template loader to run some SQL. Simulates a CMS.
15 User.objects.all().count()
16 return super(LoaderWithSQL, self).load_template(*args, **kwargs)
2222 cache.cache.set('foo', 'bar')
2323 cache.cache.get('foo')
2424 cache.cache.delete('foo')
25 self.assertEqual(len(self.panel.calls), 3)
25 # Verify that the cache has a valid clear method.
26 cache.cache.clear()
27 self.assertEqual(len(self.panel.calls), 4)
28
29 def test_recording_caches(self):
30 self.assertEqual(len(self.panel.calls), 0)
31 default_cache = cache.caches[cache.DEFAULT_CACHE_ALIAS]
32 second_cache = cache.caches['second']
33 default_cache.set('foo', 'bar')
34 second_cache.get('foo')
35 self.assertEqual(len(self.panel.calls), 2)
36
37 def test_insert_content(self):
38 """
39 Test that the panel only inserts content after generate_stats and
40 not the process_response.
41 """
42 cache.cache.get('café')
43 self.panel.process_response(self.request, self.response)
44 # ensure the panel does not have content yet.
45 self.assertNotIn('café', self.panel.content)
46 self.panel.generate_stats(self.request, self.response)
47 # ensure the panel renders correctly.
48 self.assertIn('café', self.panel.content)
0 # coding: utf-8
1
02 from __future__ import absolute_import, unicode_literals
13
24 import logging
35
46 from debug_toolbar.panels.logging import (
5 collector, MESSAGE_IF_STRING_REPRESENTATION_INVALID)
7 MESSAGE_IF_STRING_REPRESENTATION_INVALID, collector,
8 )
69
710 from ..base import BaseTestCase
811
1518 self.logger = logging.getLogger(__name__)
1619 collector.clear_collection()
1720
21 # Assume the root logger has been configured with level=DEBUG.
22 # Previously DDT forcefully set this itself to 0 (NOTSET).
23 logging.root.setLevel(logging.DEBUG)
24
1825 def test_happy_case(self):
1926 self.logger.info('Nothing to see here, move along!')
2027
2128 self.panel.process_response(self.request, self.response)
29 self.panel.generate_stats(self.request, self.response)
2230 records = self.panel.get_stats()['records']
2331
2432 self.assertEqual(1, len(records))
2937 self.logger.info('There are %d %s', 5, 'apples')
3038
3139 self.panel.process_response(self.request, self.response)
40 self.panel.generate_stats(self.request, self.response)
3241 records = self.panel.get_stats()['records']
3342
3443 self.assertEqual(1, len(records))
3544 self.assertEqual('There are 5 apples',
3645 records[0]['message'])
46
47 def test_insert_content(self):
48 """
49 Test that the panel only inserts content after generate_stats and
50 not the process_response.
51 """
52 self.logger.info('café')
53 self.panel.process_response(self.request, self.response)
54 # ensure the panel does not have content yet.
55 self.assertNotIn('café', self.panel.content)
56 self.panel.generate_stats(self.request, self.response)
57 # ensure the panel renders correctly.
58 self.assertIn('café', self.panel.content)
3759
3860 def test_failing_formatting(self):
3961 class BadClass(object):
4466 self.logger.debug('This class is misbehaving: %s', BadClass())
4567
4668 self.panel.process_response(self.request, self.response)
69 self.panel.generate_stats(self.request, self.response)
4770 records = self.panel.get_stats()['records']
4871
4972 self.assertEqual(1, len(records))
33 from django.db import IntegrityError, transaction
44 from django.test import TestCase
55 from django.test.utils import override_settings
6 from django.utils import unittest
76
87 from ..base import BaseTestCase
98 from ..views import regular_view
1615 super(ProfilingPanelTestCase, self).setUp()
1716 self.panel = self.toolbar.get_panel_by_id('ProfilingPanel')
1817
19 # This test fails randomly for a reason I don't understand.
20
21 @unittest.expectedFailure
2218 def test_regular_view(self):
2319 self.panel.process_view(self.request, regular_view, ('profiling',), {})
2420 self.panel.process_response(self.request, self.response)
21 self.panel.generate_stats(self.request, self.response)
2522 self.assertIn('func_list', self.panel.get_stats())
23 self.assertIn('regular_view', self.panel.content)
24
25 def test_insert_content(self):
26 """
27 Test that the panel only inserts content after generate_stats and
28 not the process_response.
29 """
30 self.panel.process_view(self.request, regular_view, ('profiling',), {})
31 self.panel.process_response(self.request, self.response)
32 # ensure the panel does not have content yet.
33 self.assertNotIn('regular_view', self.panel.content)
34 self.panel.generate_stats(self.request, self.response)
35 # ensure the panel renders correctly.
2636 self.assertIn('regular_view', self.panel.content)
2737
2838
3848 self.assertEqual(User.objects.count(), 1)
3949
4050 with self.assertRaises(IntegrityError):
41 if hasattr(transaction, 'atomic'): # Django >= 1.6
42 with transaction.atomic():
43 response = self.client.get('/new_user/')
44 else:
51 with transaction.atomic():
4552 response = self.client.get('/new_user/')
4653 self.assertEqual(User.objects.count(), 1)
00 from __future__ import absolute_import, unicode_literals
11
2 import django
32 from django.conf import settings
43 from django.http import HttpResponse
54 from django.test.utils import override_settings
6 from django.utils import unittest
75
86 from ..base import BaseTestCase
97
2927 redirect['Location'] = 'http://somewhere/else/'
3028 response = self.panel.process_response(self.request, redirect)
3129 self.assertFalse(response is redirect)
32 self.assertContains(response, '302 FOUND')
30 try:
31 self.assertContains(response, '302 Found')
32 except AssertionError: # Django < 1.9
33 self.assertContains(response, '302 FOUND')
3334 self.assertContains(response, 'http://somewhere/else/')
3435
3536 def test_redirect_with_broken_context_processor(self):
36 context_processors = settings.TEMPLATE_CONTEXT_PROCESSORS + (
37 context_processors = list(settings.TEMPLATE_CONTEXT_PROCESSORS) + [
3738 'tests.context_processors.broken',
38 )
39 ]
3940
4041 with self.settings(TEMPLATE_CONTEXT_PROCESSORS=context_processors):
4142 redirect = HttpResponse(status=302)
4243 redirect['Location'] = 'http://somewhere/else/'
4344 response = self.panel.process_response(self.request, redirect)
4445 self.assertFalse(response is redirect)
45 self.assertContains(response, '302 FOUND')
46 try:
47 self.assertContains(response, '302 Found')
48 except AssertionError: # Django < 1.9
49 self.assertContains(response, '302 FOUND')
4650 self.assertContains(response, 'http://somewhere/else/')
4751
4852 def test_unknown_status_code(self):
4953 redirect = HttpResponse(status=369)
5054 redirect['Location'] = 'http://somewhere/else/'
5155 response = self.panel.process_response(self.request, redirect)
52 self.assertContains(response, '369 UNKNOWN STATUS CODE')
56 try:
57 self.assertContains(response, '369 Unknown Status Code')
58 except AssertionError: # Django < 1.9
59 self.assertContains(response, '369 UNKNOWN STATUS CODE')
5360
54 @unittest.skipIf(django.VERSION[:2] < (1, 6), "reason isn't supported")
5561 def test_unknown_status_code_with_reason(self):
5662 redirect = HttpResponse(status=369, reason='Look Ma!')
5763 redirect['Location'] = 'http://somewhere/else/'
5864 response = self.panel.process_response(self.request, redirect)
5965 self.assertContains(response, '369 Look Ma!')
66
67 def test_insert_content(self):
68 """
69 Test that the panel only inserts content after generate_stats and
70 not the process_response.
71 """
72 redirect = HttpResponse(status=304)
73 response = self.panel.process_response(self.request, redirect)
74 self.assertIsNotNone(response)
75 response = self.panel.generate_stats(self.request, redirect)
76 self.assertIsNone(response)
1818 self.request.session['là'.encode('utf-8')] = 'là'.encode('utf-8')
1919 self.panel.process_request(self.request)
2020 self.panel.process_response(self.request, self.response)
21 self.panel.generate_stats(self.request, self.response)
2122 content = self.panel.content
2223 if six.PY3:
2324 self.assertIn('où', content)
2930 self.request.path = '/non_ascii_request/'
3031 self.panel.process_request(self.request)
3132 self.panel.process_response(self.request, self.response)
33 self.panel.generate_stats(self.request, self.response)
3234 self.assertIn('nôt åscíì', self.panel.content)
35
36 def test_insert_content(self):
37 """
38 Test that the panel only inserts content after generate_stats and
39 not the process_response.
40 """
41 self.request.path = '/non_ascii_request/'
42 self.panel.process_response(self.request, self.response)
43 # ensure the panel does not have content yet.
44 self.assertNotIn('nôt åscíì', self.panel.content)
45 self.panel.generate_stats(self.request, self.response)
46 # ensure the panel renders correctly.
47 self.assertIn('nôt åscíì', self.panel.content)
11
22 from __future__ import absolute_import, unicode_literals
33
4 import unittest
5
46 from django.contrib.auth.models import User
57 from django.db import connection
68 from django.db.utils import DatabaseError
7 from django.utils import unittest
9 from django.shortcuts import render
10 from django.test.utils import override_settings
811
912 from ..base import BaseTestCase
1013
1922 def tearDown(self):
2023 self.panel.disable_instrumentation()
2124 super(SQLPanelTestCase, self).tearDown()
25
26 def test_disabled(self):
27 config = {
28 'DISABLE_PANELS': set(['debug_toolbar.panels.sql.SQLPanel'])
29 }
30 self.assertTrue(self.panel.enabled)
31 with self.settings(DEBUG_TOOLBAR_CONFIG=config):
32 self.assertFalse(self.panel.enabled)
2233
2334 def test_recording(self):
2435 self.assertEqual(len(self.panel._queries), 0)
5263 self.assertEqual(len(self.panel._queries), 3)
5364
5465 self.panel.process_response(self.request, self.response)
66 self.panel.generate_stats(self.request, self.response)
5567
5668 # ensure the panel renders correctly
69 self.assertIn('café', self.panel.content)
70
71 def test_insert_content(self):
72 """
73 Test that the panel only inserts content after generate_stats and
74 not the process_response.
75 """
76 list(User.objects.filter(username='café'.encode('utf-8')))
77 self.panel.process_response(self.request, self.response)
78 # ensure the panel does not have content yet.
79 self.assertNotIn('café', self.panel.content)
80 self.panel.generate_stats(self.request, self.response)
81 # ensure the panel renders correctly.
5782 self.assertIn('café', self.panel.content)
5883
5984 @unittest.skipUnless(connection.vendor == 'postgresql',
83108
84109 # ensure the stacktrace is empty
85110 self.assertEqual([], query[1]['stacktrace'])
111
112 @override_settings(DEBUG=True, TEMPLATE_DEBUG=True,
113 TEMPLATE_LOADERS=('tests.loaders.LoaderWithSQL',))
114 def test_regression_infinite_recursion(self):
115 """
116 Test case for when the template loader runs a SQL query that causes
117 an infinite recursion in the SQL panel.
118 """
119 self.assertEqual(len(self.panel._queries), 0)
120
121 render(self.request, "basic.html", {})
122
123 # Two queries are logged because the loader runs SQL every time a
124 # template is loaded and basic.html extends base.html.
125 self.assertEqual(len(self.panel._queries), 2)
126 query = self.panel._queries[0]
127 self.assertEqual(query[0], 'default')
128 self.assertTrue('sql' in query[1])
129 self.assertTrue('duration' in query[1])
130 self.assertTrue('stacktrace' in query[1])
131
132 # ensure the stacktrace is populated
133 self.assertTrue(len(query[1]['stacktrace']) > 0)
1515 def test_default_case(self):
1616 self.panel.process_request(self.request)
1717 self.panel.process_response(self.request, self.response)
18 self.panel.generate_stats(self.request, self.response)
1819 self.assertIn('django.contrib.staticfiles.finders.'
1920 'AppDirectoriesFinder', self.panel.content)
2021 self.assertIn('django.contrib.staticfiles.finders.'
2526 ['django.contrib.admin', 'debug_toolbar'])
2627 self.assertEqual(self.panel.get_staticfiles_dirs(),
2728 finders.FileSystemFinder().locations)
29
30 def test_insert_content(self):
31 """
32 Test that the panel only inserts content after generate_stats and
33 not the process_response.
34 """
35 self.panel.process_request(self.request)
36 self.panel.process_response(self.request, self.response)
37 # ensure the panel does not have content yet.
38 self.assertNotIn('django.contrib.staticfiles.finders.'
39 'AppDirectoriesFinder', self.panel.content)
40 self.panel.generate_stats(self.request, self.response)
41 # ensure the panel renders correctly.
42 self.assertIn('django.contrib.staticfiles.finders.'
43 'AppDirectoriesFinder', self.panel.content)
11
22 from __future__ import absolute_import, unicode_literals
33
4 import django
54 from django.contrib.auth.models import User
65 from django.template import Context, RequestContext, Template
76
3635 # ensure the query was NOT logged
3736 self.assertEqual(len(self.sql_panel._queries), 0)
3837
39 base_ctx_idx = 1 if django.VERSION[:2] >= (1, 5) else 0
40 ctx = self.panel.templates[0]['context'][base_ctx_idx]
38 ctx = self.panel.templates[0]['context'][1]
4139 self.assertIn('<<queryset of auth.User>>', ctx)
4240 self.assertIn('<<triggers database query>>', ctx)
4341
4745 c = Context({'object': NonAsciiRepr()})
4846 t.render(c)
4947 self.panel.process_response(self.request, self.response)
48 self.panel.generate_stats(self.request, self.response)
49 self.assertIn('nôt åscíì', self.panel.content)
50
51 def test_insert_content(self):
52 """
53 Test that the panel only inserts content after generate_stats and
54 not the process_response.
55 """
56 t = Template("{{ object }}")
57 c = Context({'object': NonAsciiRepr()})
58 t.render(c)
59 self.panel.process_response(self.request, self.response)
60 # ensure the panel does not have content yet.
61 self.assertNotIn('nôt åscíì', self.panel.content)
62 self.panel.generate_stats(self.request, self.response)
63 # ensure the panel renders correctly.
5064 self.assertIn('nôt åscíì', self.panel.content)
5165
5266 def test_custom_context_processor(self):
5569 c = RequestContext(self.request, processors=[context_processor])
5670 t.render(c)
5771 self.panel.process_response(self.request, self.response)
72 self.panel.generate_stats(self.request, self.response)
5873 self.assertIn('tests.panels.test_template.context_processor', self.panel.content)
74
75 def test_disabled(self):
76 config = {
77 'DISABLE_PANELS': set([
78 'debug_toolbar.panels.templates.TemplatesPanel'])
79 }
80 self.assertTrue(self.panel.enabled)
81 with self.settings(DEBUG_TOOLBAR_CONFIG=config):
82 self.assertFalse(self.panel.enabled)
5983
6084
6185 def context_processor(request):
00 """Django settings for tests."""
11
22 import os
3 import django
43
54 BASE_DIR = os.path.dirname(os.path.dirname(__file__))
65
109 SECRET_KEY = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
1110
1211 INTERNAL_IPS = ['127.0.0.1']
12
13 LOGGING_CONFIG = None # avoids spurious output in tests
1314
1415
1516 # Application definition
5354 CACHES = {
5455 'default': {
5556 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
56 }
57 },
58 'second': {
59 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
60 },
5761 }
5862
5963 DATABASES = {
6973 # Django's test client sets wsgi.multiprocess to True inappropriately
7074 'RENDER_PANELS': False,
7175 }
72
73 if django.VERSION[:2] < (1, 6):
74 TEST_RUNNER = 'discover_runner.DiscoverRunner'
0 <!DOCTYPE html>
1 <html>
2 <head>
3 <title>{{ title }}</title>
4 </head>
5 <body>
6 {% block content %}{% endblock %}
7 </body>
8 </html>
0 <!DOCTYPE html>
1 <html>
2 <head>
3 <title>{{ title }}</title>
4 </head>
5 <body>
6 </body>
7 </html>
0 {% extends "base.html" %}
1 {% block content %}Test for {{ title }}{% endblock %}
22 from __future__ import absolute_import, unicode_literals
33
44 import os
5 import unittest
56 from xml.etree import ElementTree as ET
7
8 from django.contrib.staticfiles.testing import StaticLiveServerTestCase
9 from django.test import RequestFactory, TestCase
10 from django.test.utils import override_settings
11
12 from debug_toolbar.middleware import DebugToolbarMiddleware, show_toolbar
13
14 from .base import BaseTestCase
15 from .views import regular_view
616
717 try:
818 from selenium import webdriver
1020 from selenium.webdriver.support.wait import WebDriverWait
1121 except ImportError:
1222 webdriver = None
13
14 from django.test import LiveServerTestCase, RequestFactory, TestCase
15 from django.test.utils import override_settings
16 from django.utils.unittest import skipIf, skipUnless
17
18 from debug_toolbar.middleware import DebugToolbarMiddleware, show_toolbar
19
20 from .base import BaseTestCase
21 from .views import regular_view
2223
2324
2425 rf = RequestFactory()
4445 panel = self.toolbar.get_panel_by_id('RequestPanel')
4546 panel.process_request(self.request)
4647 panel.process_response(self.request, self.response)
48 panel.generate_stats(self.request, self.response)
4749 return panel.get_stats()
4850
4951 def test_url_resolving_positional(self):
8587 # check toolbar insertion before "</body>"
8688 self.assertContains(resp, '</div>\n</body>')
8789
90 def test_cache_page(self):
91 self.client.get('/cached_view/')
92 self.assertEqual(
93 len(self.toolbar.get_panel_by_id('CachePanel').calls), 3)
94 self.client.get('/cached_view/')
95 self.assertEqual(
96 len(self.toolbar.get_panel_by_id('CachePanel').calls), 5)
97
8898
8999 @override_settings(DEBUG=True)
90100 class DebugToolbarIntegrationTestCase(TestCase):
108118 ET.fromstring(response.content) # shouldn't raise ParseError
109119
110120
111 @skipIf(webdriver is None, "selenium isn't installed")
112 @skipUnless('DJANGO_SELENIUM_TESTS' in os.environ, "selenium tests not requested")
121 @unittest.skipIf(webdriver is None, "selenium isn't installed")
122 @unittest.skipUnless('DJANGO_SELENIUM_TESTS' in os.environ, "selenium tests not requested")
113123 @override_settings(DEBUG=True)
114 class DebugToolbarLiveTestCase(LiveServerTestCase):
124 class DebugToolbarLiveTestCase(StaticLiveServerTestCase):
115125
116126 @classmethod
117127 def setUpClass(cls):
140150 self.assertIn("Name", table.text)
141151 self.assertIn("Version", table.text)
142152
143 @override_settings(DEBUG_TOOLBAR_CONFIG={'RESULTS_STORE_SIZE': 0})
153 @override_settings(DEBUG_TOOLBAR_CONFIG={'RESULTS_CACHE_SIZE': 0})
144154 def test_expired_store(self):
145155 self.selenium.get(self.live_server_url + '/regular/basic/')
146156 version_panel = self.selenium.find_element_by_id('VersionsPanel')
152162 error = WebDriverWait(self.selenium, timeout=10).until(
153163 lambda selenium: version_panel.find_element_by_tag_name('p'))
154164 self.assertIn("Data for this panel isn't available anymore.", error.text)
165
166 @override_settings(TEMPLATE_LOADERS=[(
167 'django.template.loaders.cached.Loader', (
168 'django.template.loaders.filesystem.Loader',
169 'django.template.loaders.app_directories.Loader',
170 ),
171 )])
172 def test_django_cached_template_loader(self):
173 self.selenium.get(self.live_server_url + '/regular/basic/')
174 version_panel = self.selenium.find_element_by_id('TemplatesPanel')
175
176 # Click to show the versions panel
177 self.selenium.find_element_by_class_name('TemplatesPanel').click()
178
179 # Version panel loads
180 trigger = WebDriverWait(self.selenium, timeout=10).until(
181 lambda selenium: version_panel.find_element_by_css_selector(
182 '.remoteCall'))
183 trigger.click()
184
185 # Verify the code is displayed
186 WebDriverWait(self.selenium, timeout=10).until(
187 lambda selenium: self.selenium.find_element_by_css_selector(
188 '#djDebugWindow code'))
00 from __future__ import absolute_import, unicode_literals
11
2 from django.utils.unittest import TestCase
2 import unittest
33
44 from debug_toolbar.utils import get_name_from_obj
55
66
7 class GetNameFromObjTestCase(TestCase):
7 class GetNameFromObjTestCase(unittest.TestCase):
88
99 def test_func(self):
1010 def x():
11
22 from __future__ import absolute_import, unicode_literals
33
4 from django.conf.urls import include, patterns, url
5 from django.contrib import admin
4 from django.conf.urls import include, url
65
76 import debug_toolbar
87
8 from . import views
99 from .models import NonAsciiRepr
1010
11
12 admin.autodiscover()
13
14 urlpatterns = patterns('tests.views', # noqa
15 url(r'^resolving1/(.+)/(.+)/$', 'resolving_view', name='positional-resolving'),
16 url(r'^resolving2/(?P<arg1>.+)/(?P<arg2>.+)/$', 'resolving_view'),
17 url(r'^resolving3/(.+)/$', 'resolving_view', {'arg2': 'default'}),
18 url(r'^regular/(?P<title>.*)/$', 'regular_view'),
19 url(r'^non_ascii_request/$', 'regular_view', {'title': NonAsciiRepr()}),
20 url(r'^new_user/$', 'new_user'),
21 url(r'^execute_sql/$', 'execute_sql'),
11 urlpatterns = [
12 url(r'^resolving1/(.+)/(.+)/$', views.resolving_view, name='positional-resolving'),
13 url(r'^resolving2/(?P<arg1>.+)/(?P<arg2>.+)/$', views.resolving_view),
14 url(r'^resolving3/(.+)/$', views.resolving_view, {'arg2': 'default'}),
15 url(r'^regular/(?P<title>.*)/$', views.regular_view),
16 url(r'^non_ascii_request/$', views.regular_view, {'title': NonAsciiRepr()}),
17 url(r'^new_user/$', views.new_user),
18 url(r'^execute_sql/$', views.execute_sql),
19 url(r'^cached_view/$', views.cached_view),
2220 url(r'^__debug__/', include(debug_toolbar.urls)),
23 )
21 ]
44 from django.contrib.auth.models import User
55 from django.http import HttpResponse
66 from django.shortcuts import render
7 from django.views.decorators.cache import cache_page
78
89
910 def execute_sql(request):
2324 def resolving_view(request, arg1, arg2):
2425 # see test_url_resolving in tests.py
2526 return HttpResponse()
27
28
29 @cache_page(60)
30 def cached_view(request):
31 return HttpResponse()
00 [tox]
11 envlist =
2 py26-django14,
3 py27-django14,
4 py26-django15,
5 py27-django15,
6 py32-django15,
7 py33-django15,
8 py26-django16,
9 py27-django16,
10 py32-django16,
11 py33-django16,
12 py27-django17,
13 py32-django17,
14 py33-django17,
15 py34-django17,
16 flake8
2 py{27,32,33,34}-django{17,18},
3 py{27,34,35}-django19,
4 flake8,
5 isort
176
187 [testenv]
8 basepython =
9 py27: python2.7
10 py32: python3.2
11 py33: python3.3
12 py34: python3.4
13 py34: python3.5
1914 commands = make test
2015 deps =
16 django14: Django>=1.4,<1.5
17 django15: Django>=1.5,<1.6
18 django16: Django>=1.6,<1.7
19 django17: Django>=1.7,<1.8
20 django18: Django>=1.8,<1.9
21 django19: https://www.djangoproject.com/download/1.9a1/tarball/
2122 django-discover-runner
2223 selenium
2324 sqlparse
2526 PYTHONPATH = {toxinidir}
2627 whitelist_externals = make
2728
28 [testenv:py26-django14]
29 basepython = python2.6
30 deps =
31 Django>=1.4,<1.5
32 {[testenv]deps}
33
34 [testenv:py27-django14]
35 basepython = python2.7
36 deps =
37 Django>=1.4,<1.5
38 {[testenv]deps}
39
40 [testenv:py26-django15]
41 basepython = python2.6
42 deps =
43 Django>=1.5,<1.6
44 {[testenv]deps}
45
46 [testenv:py27-django15]
47 basepython = python2.7
48 deps =
49 Django>=1.5,<1.6
50 {[testenv]deps}
51
52 [testenv:py32-django15]
53 basepython = python3.2
54 deps =
55 Django>=1.5,<1.6
56 {[testenv]deps}
57
58 [testenv:py33-django15]
59 basepython = python3.3
60 deps =
61 Django>=1.5,<1.6
62 {[testenv]deps}
63
64 [testenv:py26-django16]
65 basepython = python2.6
66 deps =
67 Django>=1.6,<1.7
68 {[testenv]deps}
69
70 [testenv:py27-django16]
71 basepython = python2.7
72 deps =
73 Django>=1.6,<1.7
74 {[testenv]deps}
75
76 [testenv:py32-django16]
77 basepython = python3.2
78 deps =
79 Django>=1.6,<1.7
80 {[testenv]deps}
81
82 [testenv:py33-django16]
83 basepython = python3.3
84 deps =
85 Django>=1.6,<1.7
86 {[testenv]deps}
87
88 [testenv:py27-django17]
89 basepython = python2.7
90 deps =
91 https://www.djangoproject.com/download/1.7b1/tarball/
92 {[testenv]deps}
93
94 [testenv:py32-django17]
95 basepython = python3.2
96 deps =
97 https://www.djangoproject.com/download/1.7b1/tarball/
98 {[testenv]deps}
99
100 [testenv:py33-django17]
101 basepython = python3.3
102 deps =
103 https://www.djangoproject.com/download/1.7b1/tarball/
104 {[testenv]deps}
105
106 [testenv:py34-django17]
107 basepython = python3.4
108 deps =
109 https://www.djangoproject.com/download/1.7b1/tarball/
110 {[testenv]deps}
111
11229 [testenv:flake8]
30 basepython =
31 python2.7
11332 commands = make flake8
11433 deps =
11534 flake8
35
36 [testenv:isort]
37 basepython =
38 python2.7
39 commands = make isort_check_only
40 deps =
41 isort