├── .gitignore ├── AUTHORS ├── LICENSE ├── MANIFEST.in ├── NEWS ├── README.rst ├── debug_toolbar ├── __init__.py ├── locale │ ├── de │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── en │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── es │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── fr │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ ├── he │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ └── ru │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ └── debugsqlshell.py ├── media │ └── debug_toolbar │ │ ├── Makefile │ │ ├── css │ │ ├── toolbar.css │ │ └── toolbar.min.css │ │ ├── img │ │ ├── back.png │ │ ├── back_hover.png │ │ ├── close.png │ │ ├── close_hover.png │ │ ├── djdt_vertical.png │ │ ├── dot.gif │ │ ├── indicator.png │ │ └── panel_bg.png │ │ └── js │ │ ├── jquery.cookie.js │ │ ├── jquery.js │ │ ├── toolbar.js │ │ └── toolbar.min.js ├── middleware.py ├── models.py ├── panels │ ├── __init__.py │ ├── cache.py │ ├── headers.py │ ├── htmlvalidator.py │ ├── logger.py │ ├── profiling.py │ ├── request_vars.py │ ├── settings_vars.py │ ├── signals.py │ ├── sql.py │ ├── state.py │ ├── template.py │ ├── timer.py │ └── version.py ├── runtests.py ├── templates │ └── debug_toolbar │ │ ├── base.html │ │ ├── panels │ │ ├── cache.html │ │ ├── headers.html │ │ ├── htmlvalidator.html │ │ ├── logger.html │ │ ├── profiling.html │ │ ├── request_vars.html │ │ ├── settings_vars.html │ │ ├── signals.html │ │ ├── sql.html │ │ ├── sql_explain.html │ │ ├── sql_profile.html │ │ ├── sql_select.html │ │ ├── state.html │ │ ├── template_source.html │ │ ├── templates.html │ │ ├── timer.html │ │ └── versions.html │ │ └── redirect.html ├── tests │ ├── __init__.py │ ├── templates │ │ └── 404.html │ ├── tests.py │ ├── urls.py │ └── views.py ├── toolbar │ ├── __init__.py │ └── loader.py ├── urls.py ├── utils │ ├── __init__.py │ ├── compat │ │ ├── __init__.py │ │ └── db.py │ ├── sqlparse │ │ ├── __init__.py │ │ ├── engine │ │ │ ├── __init__.py │ │ │ ├── filter.py │ │ │ └── grouping.py │ │ ├── filters.py │ │ ├── formatter.py │ │ ├── keywords.py │ │ ├── lexer.py │ │ ├── sql.py │ │ └── tokens.py │ └── tracking │ │ ├── __init__.py │ │ └── db.py └── views.py ├── example ├── __init__.py ├── example.db ├── manage.py ├── media │ └── js │ │ ├── jquery.js │ │ ├── mootools.js │ │ └── prototype.js ├── models.py ├── settings.py ├── templates │ ├── admin │ │ └── login.html │ ├── index.html │ ├── jquery │ │ └── index.html │ ├── mootools │ │ └── index.html │ └── prototype │ │ └── index.html ├── urls.py └── views.py ├── setup.cfg └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.DS_Store 3 | *~ 4 | django_debug_toolbar.egg-info -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | The Django Debug Toolbar was original created by Rob Hudson in 2 | August 2008. 3 | 4 | The following is a list of much appreciated contributors: 5 | 6 | Reto Aebersold 7 | Andi Albrecht 8 | Chris Beaven 9 | Kenneth Belitzky 10 | Loic Bistuer 11 | Etienne Carrier 12 | David Cramer 13 | Michael Elsdoerfer 14 | Augie Fackler 15 | Dan Fairs 16 | Alex Gaynor 17 | Idan Gazit 18 | Matt George 19 | Adam Gomaa 20 | Daniel Hahler 21 | Jacob Kaplan-Moss 22 | Russell Keith-Magee 23 | Mikhail Korobov 24 | Arthur Koziel 25 | Jannis Leidel 26 | Martin Maney 27 | Percy Perez-Pinedo 28 | Nowell Strite 29 | Malcolm Tredinnick 30 | Bryan Veloso 31 | Simon Willison 32 | Diego Búrigo Zacarão 33 | Philip Zeyliger 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Rob Hudson and individual contributors. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Django nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without 16 | specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS 2 | include LICENSE 3 | include README.rst 4 | recursive-include debug_toolbar/media * 5 | recursive-include debug_toolbar/templates * 6 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | News for django-debug-toolbar 2 | ============================= 3 | 4 | 0.8.5 (2011 Apr 25) 5 | ------------------- 6 | 7 | * Ensure if we're overriding the urlconf that we're resetting handler404/500. 8 | 9 | * Updated middleware logic to avoid work if content-type isn't right. 10 | 11 | * Change .load() calls to GET to avoid CSRF protection. 12 | 13 | * Updated SQL panel to match Django's which now includes logging. 14 | 15 | * Added basic multi-db support. 16 | 17 | * Some HTML validation fixes. 18 | 19 | * Added support for `executemany`. Thanks to postal2600. 20 | 21 | * Added support for LogBook. Thanks to Vincent Driessen. 22 | 23 | * Added clean_params method to DatabaseStatTracker to scrub non-unicode 24 | data for displaying on the sql panel. Thanks to Matthew J Morrison 25 | 26 | 0.8.4 (2010 Nov 8) 27 | ------------------ 28 | 29 | * Added print style to hide the toolbar (issue 90) 30 | 31 | * Fixed "Badly formatted SQL query plan" (issue 86) 32 | 33 | * Fixed "SQL not selectable due to line chart" (issue 85) 34 | 35 | * Fixed "Redirect page does not set cookie" (issue 6) 36 | 37 | * Fixed template block inheritance bug (issues 77 and 97). 38 | 39 | * Fixed flash of unstyled toolbar. 40 | 41 | * Updated to work with old TEMPLATE_LOADERS settings from < 1.2. 42 | 43 | * Updated to stop template loader iteration when template is found. 44 | 45 | 46 | (Note: NEWS was started after the 0.8.3 release and is not complete) 47 | 48 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | Django Debug Toolbar 3 | ==================== 4 | 5 | The Django Debug Toolbar is a configurable set of panels that display various 6 | debug information about the current request/response and when clicked, display 7 | more details about the panel's content. 8 | 9 | Currently, the following panels have been written and are working: 10 | 11 | - Django version 12 | - Request timer 13 | - A list of settings in settings.py 14 | - Common HTTP headers 15 | - GET/POST/cookie/session variable display 16 | - Templates and context used, and their template paths 17 | - SQL queries including time to execute and links to EXPLAIN each query 18 | - List of signals, their args and receivers 19 | - Logging output via Python's built-in logging, or via the `logbook `_ module 20 | - State of available objects in the project - how much objects was created/udpated/deleted 21 | - Added HTML Validator panel which provide list of HTML warnings/errors on the page 22 | 23 | There is also one Django management command currently: 24 | 25 | - `debugsqlshell`: Outputs the SQL that gets executed as you work in the Python 26 | interactive shell. (See example below) 27 | 28 | If you have ideas for other panels please let us know. 29 | 30 | Installation 31 | ============ 32 | 33 | #. Add the `debug_toolbar` directory to your Python path. 34 | 35 | #. Execute 36 | 37 | ``pip install pytidylib`` 38 | 39 | *pytidylib required only for `HTMLValidationDebugPanel`* 40 | 41 | #. Add the following middleware to your project's `settings.py` file: 42 | 43 | ``'debug_toolbar.middleware.DebugToolbarMiddleware',`` 44 | 45 | Tying into middleware allows each panel to be instantiated on request and 46 | rendering to happen on response. 47 | 48 | The order of MIDDLEWARE_CLASSES is important: the Debug Toolbar middleware 49 | must come after any other middleware that encodes the response's content 50 | (such as GZipMiddleware). 51 | 52 | Note: The debug toolbar will only display itself if the mimetype of the 53 | response is either `text/html` or `application/xhtml+xml` and contains a 54 | closing `` tag. 55 | 56 | Note: Be aware of middleware ordering and other middleware that may 57 | intercept requests and return responses. Putting the debug toolbar 58 | middleware *after* the Flatpage middleware, for example, means the 59 | toolbar will not show up on flatpages. 60 | 61 | #. Make sure your IP is listed in the `INTERNAL_IPS` setting. If you are 62 | working locally this will be: 63 | 64 | INTERNAL_IPS = ('127.0.0.1',) 65 | 66 | Note: This is required because of the built-in requirements of the 67 | `show_toolbar` method. See below for how to define a method to determine 68 | your own logic for displaying the toolbar. 69 | 70 | #. Add `debug_toolbar` to your `INSTALLED_APPS` setting so Django can find the 71 | template files associated with the Debug Toolbar. 72 | 73 | Alternatively, add the path to the debug toolbar templates 74 | (``'path/to/debug_toolbar/templates'`` to your ``TEMPLATE_DIRS`` setting.) 75 | 76 | Configuration 77 | ============= 78 | 79 | The debug toolbar has two settings that can be set in `settings.py`: 80 | 81 | #. Optional: Add a tuple called `DEBUG_TOOLBAR_PANELS` to your ``settings.py`` 82 | file that specifies the full Python path to the panel that you want included 83 | in the Toolbar. This setting looks very much like the `MIDDLEWARE_CLASSES` 84 | setting. For example:: 85 | 86 | DEBUG_TOOLBAR_PANELS = ( 87 | 'debug_toolbar.panels.version.VersionDebugPanel', 88 | 'debug_toolbar.panels.timer.TimerDebugPanel', 89 | 'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel', 90 | 'debug_toolbar.panels.headers.HeaderDebugPanel', 91 | 'debug_toolbar.panels.request_vars.RequestVarsDebugPanel', 92 | 'debug_toolbar.panels.template.TemplateDebugPanel', 93 | 'debug_toolbar.panels.sql.SQLDebugPanel', 94 | 'debug_toolbar.panels.signals.SignalDebugPanel', 95 | 'debug_toolbar.panels.logger.LoggingPanel', 96 | 'debug_toolbar.panels.state.StateDebugPanel', 97 | 'debug_toolbar.panels.htmlvalidator.HTMLValidationDebugPanel', 98 | ) 99 | 100 | You can change the ordering of this tuple to customize the order of the 101 | panels you want to display, or add/remove panels. If you have custom panels 102 | you can include them in this way -- just provide the full Python path to 103 | your panel. 104 | 105 | #. Optional: There are a few configuration options to the debug toolbar that 106 | can be placed in a dictionary: 107 | 108 | * `INTERCEPT_REDIRECTS`: If set to True (default), the debug toolbar will 109 | show an intermediate page upon redirect so you can view any debug 110 | information prior to redirecting. This page will provide a link to the 111 | redirect destination you can follow when ready. If set to False, redirects 112 | will proceed as normal. 113 | 114 | * `SHOW_TOOLBAR_CALLBACK`: If not set or set to None, the debug_toolbar 115 | middleware will use its built-in show_toolbar method for determining whether 116 | the toolbar should show or not. The default checks are that DEBUG must be 117 | set to True and the IP of the request must be in INTERNAL_IPS. You can 118 | provide your own method for displaying the toolbar which contains your 119 | custom logic. This method should return True or False. 120 | 121 | * `EXTRA_SIGNALS`: An array of custom signals that might be in your project, 122 | defined as the python path to the signal. 123 | 124 | * `HIDE_DJANGO_SQL`: If set to True (the default) then code in Django itself 125 | won't be shown in SQL stacktraces. 126 | 127 | * `SHOW_TEMPLATE_CONTEXT`: If set to True (the default) then a template's 128 | context will be included with it in the Template debug panel. Turning this 129 | off is useful when you have large template contexts, or you have template 130 | contexts with lazy datastructures that you don't want to be evaluated. 131 | 132 | * `TAG`: If set, this will be the tag to which debug_toolbar will attach the 133 | debug toolbar. Defaults to 'body'. 134 | 135 | Example configuration:: 136 | 137 | def custom_show_toolbar(request): 138 | return True # Always show toolbar, for example purposes only. 139 | 140 | DEBUG_TOOLBAR_CONFIG = { 141 | 'INTERCEPT_REDIRECTS': False, 142 | 'SHOW_TOOLBAR_CALLBACK': custom_show_toolbar, 143 | 'EXTRA_SIGNALS': ['myproject.signals.MySignal'], 144 | 'HIDE_DJANGO_SQL': False, 145 | 'TAG': 'div', 146 | } 147 | 148 | `debugsqlshell` 149 | =============== 150 | The following is sample output from running the `debugsqlshell` management 151 | command. Each ORM call that results in a database query will be beautifully 152 | output in the shell:: 153 | 154 | $ ./manage.py debugsqlshell 155 | Python 2.6.1 (r261:67515, Jul 7 2009, 23:51:51) 156 | [GCC 4.2.1 (Apple Inc. build 5646)] on darwin 157 | Type "help", "copyright", "credits" or "license" for more information. 158 | (InteractiveConsole) 159 | >>> from page.models import Page 160 | >>> ### Lookup and use resulting in an extra query... 161 | >>> p = Page.objects.get(pk=1) 162 | SELECT "page_page"."id", 163 | "page_page"."number", 164 | "page_page"."template_id", 165 | "page_page"."description" 166 | FROM "page_page" 167 | WHERE "page_page"."id" = 1 168 | 169 | >>> print p.template.name 170 | SELECT "page_template"."id", 171 | "page_template"."name", 172 | "page_template"."description" 173 | FROM "page_template" 174 | WHERE "page_template"."id" = 1 175 | 176 | Home 177 | >>> ### Using select_related to avoid 2nd database call... 178 | >>> p = Page.objects.select_related('template').get(pk=1) 179 | SELECT "page_page"."id", 180 | "page_page"."number", 181 | "page_page"."template_id", 182 | "page_page"."description", 183 | "page_template"."id", 184 | "page_template"."name", 185 | "page_template"."description" 186 | FROM "page_page" 187 | INNER JOIN "page_template" ON ("page_page"."template_id" = "page_template"."id") 188 | WHERE "page_page"."id" = 1 189 | 190 | >>> print p.template.name 191 | Home 192 | 193 | Running the Tests 194 | ================= 195 | 196 | The Debug Toolbar includes a limited (and growing) test suite. If you commit code, please consider 197 | adding proper coverage (especially if it has a chance for a regression) in the test suite. 198 | 199 | :: 200 | 201 | python setup.py test 202 | 203 | TODOs and BUGS 204 | ============== 205 | See: https://github.com/django-debug-toolbar/django-debug-toolbar/issues 206 | -------------------------------------------------------------------------------- /debug_toolbar/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ('VERSION',) 2 | 3 | try: 4 | VERSION = __import__('pkg_resources') \ 5 | .get_distribution('django-debug-toolbar').version 6 | except Exception, e: 7 | VERSION = 'unknown' 8 | -------------------------------------------------------------------------------- /debug_toolbar/locale/de/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/locale/de/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /debug_toolbar/locale/de/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # Django Debug Toolbar auf Deutsch. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # Jannis Leidel, 2009. 5 | # 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2009-11-18 08:06-0800\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | #: panels/cache.py:92 20 | #, python-format 21 | msgid "Cache: %.2fms" 22 | msgstr "" 23 | 24 | #: panels/cache.py:95 25 | msgid "Cache Usage" 26 | msgstr "" 27 | 28 | #: panels/headers.py:36 panels/headers.py:39 29 | msgid "HTTP Headers" 30 | msgstr "" 31 | 32 | #: panels/logger.py:56 33 | msgid "Logging" 34 | msgstr "Logging" 35 | 36 | #: panels/logger.py:63 37 | #, fuzzy 38 | msgid "Log Messages" 39 | msgstr "Nachricht" 40 | 41 | #: panels/request_vars.py:13 panels/request_vars.py:16 42 | msgid "Request Vars" 43 | msgstr "" 44 | 45 | #: panels/settings_vars.py:16 46 | msgid "Settings" 47 | msgstr "Einstellungen" 48 | 49 | #: panels/settings_vars.py:19 50 | #, python-format 51 | msgid "Settings from %s" 52 | msgstr "" 53 | 54 | #: panels/signals.py:39 panels/signals.py:42 55 | msgid "Signals" 56 | msgstr "Signals" 57 | 58 | #: panels/sql.py:146 59 | msgid "SQL" 60 | msgstr "" 61 | 62 | #: panels/sql.py:160 63 | msgid "SQL Queries" 64 | msgstr "" 65 | 66 | #: panels/template.py:47 67 | msgid "Templates" 68 | msgstr "Templates" 69 | 70 | #: panels/template.py:52 71 | #, python-format 72 | msgid "Templates (%(num_templates)s rendered)" 73 | msgstr "" 74 | 75 | #: panels/timer.py:35 templates/debug_toolbar/panels/cache.html:39 76 | #: templates/debug_toolbar/panels/logger.html:7 77 | #: templates/debug_toolbar/panels/sql.html:5 78 | #: templates/debug_toolbar/panels/sql_explain.html:11 79 | #: templates/debug_toolbar/panels/sql_profile.html:12 80 | #: templates/debug_toolbar/panels/sql_select.html:11 81 | msgid "Time" 82 | msgstr "Zeit" 83 | 84 | #: panels/timer.py:47 85 | #, fuzzy 86 | msgid "Resource Usage" 87 | msgstr "Ressource" 88 | 89 | #: panels/timer.py:78 90 | msgid "User CPU time" 91 | msgstr "" 92 | 93 | #: panels/timer.py:79 94 | msgid "System CPU time" 95 | msgstr "" 96 | 97 | #: panels/timer.py:80 98 | #, fuzzy 99 | msgid "Total CPU time" 100 | msgstr "Zeit gesamt" 101 | 102 | #: panels/timer.py:81 103 | msgid "Elapsed time" 104 | msgstr "" 105 | 106 | #: panels/timer.py:82 107 | msgid "Context switches" 108 | msgstr "" 109 | 110 | #: panels/version.py:20 panels/version.py:29 111 | #, fuzzy 112 | msgid "Versions" 113 | msgstr "Django-Version" 114 | 115 | #: templates/debug_toolbar/base.html:23 116 | msgid "Hide Toolbar" 117 | msgstr "" 118 | 119 | #: templates/debug_toolbar/base.html:23 120 | msgid "Hide" 121 | msgstr "Verbergen" 122 | 123 | #: templates/debug_toolbar/base.html:48 124 | msgid "Show Toolbar" 125 | msgstr "" 126 | 127 | #: templates/debug_toolbar/base.html:54 128 | msgid "Close" 129 | msgstr "Schließen" 130 | 131 | #: templates/debug_toolbar/redirect.html:7 132 | #: templates/debug_toolbar/panels/logger.html:9 133 | msgid "Location" 134 | msgstr "Ort" 135 | 136 | #: templates/debug_toolbar/redirect.html:9 137 | msgid "" 138 | "The Django Debug Toolbar has intercepted a redirect to the above URL for " 139 | "debug viewing purposes. You can click the above link to continue with the " 140 | "redirect as normal. If you'd like to disable this feature, set the " 141 | "DEBUG_TOOLBAR_CONFIG dictionary's key " 142 | "INTERCEPT_REDIRECTS to False." 143 | msgstr "" 144 | 145 | #: templates/debug_toolbar/panels/cache.html:14 146 | msgid "Total Calls" 147 | msgstr "Aufrufe gesamt" 148 | 149 | #: templates/debug_toolbar/panels/cache.html:16 150 | msgid "Total Time" 151 | msgstr "Zeit gesamt" 152 | 153 | #: templates/debug_toolbar/panels/cache.html:18 154 | msgid "Hits" 155 | msgstr "Aufrufe" 156 | 157 | #: templates/debug_toolbar/panels/cache.html:20 158 | msgid "Misses" 159 | msgstr "" 160 | 161 | #: templates/debug_toolbar/panels/cache.html:35 162 | msgid "Breakdown" 163 | msgstr "" 164 | 165 | #: templates/debug_toolbar/panels/cache.html:40 166 | msgid "Type" 167 | msgstr "Typ" 168 | 169 | #: templates/debug_toolbar/panels/cache.html:41 170 | msgid "Parameters" 171 | msgstr "Parameter" 172 | 173 | #: templates/debug_toolbar/panels/cache.html:42 174 | msgid "Function" 175 | msgstr "Funktion" 176 | 177 | #: templates/debug_toolbar/panels/headers.html:5 178 | msgid "Key" 179 | msgstr "Schlüssel" 180 | 181 | #: templates/debug_toolbar/panels/headers.html:6 182 | #: templates/debug_toolbar/panels/request_vars.html:37 183 | #: templates/debug_toolbar/panels/request_vars.html:63 184 | #: templates/debug_toolbar/panels/request_vars.html:85 185 | #: templates/debug_toolbar/panels/request_vars.html:107 186 | #: templates/debug_toolbar/panels/settings_vars.html:6 187 | #: templates/debug_toolbar/panels/timer.html:10 188 | msgid "Value" 189 | msgstr "Wert" 190 | 191 | #: templates/debug_toolbar/panels/logger.html:6 192 | msgid "Level" 193 | msgstr "Niveau" 194 | 195 | #: templates/debug_toolbar/panels/logger.html:8 196 | msgid "Message" 197 | msgstr "Nachricht" 198 | 199 | #: templates/debug_toolbar/panels/logger.html:24 200 | msgid "No messages logged" 201 | msgstr "Keine Nachricht gespeichert" 202 | 203 | #: templates/debug_toolbar/panels/request_vars.html:3 204 | msgid "View information" 205 | msgstr "" 206 | 207 | #: templates/debug_toolbar/panels/request_vars.html:7 208 | #, fuzzy 209 | msgid "View Function" 210 | msgstr "Funktion" 211 | 212 | #: templates/debug_toolbar/panels/request_vars.html:8 213 | msgid "args" 214 | msgstr "" 215 | 216 | #: templates/debug_toolbar/panels/request_vars.html:9 217 | msgid "kwargs" 218 | msgstr "" 219 | 220 | #: templates/debug_toolbar/panels/request_vars.html:27 221 | #, fuzzy 222 | msgid "COOKIES Variables" 223 | msgstr "Variable" 224 | 225 | #: templates/debug_toolbar/panels/request_vars.html:36 226 | #: templates/debug_toolbar/panels/request_vars.html:62 227 | #: templates/debug_toolbar/panels/request_vars.html:84 228 | #: templates/debug_toolbar/panels/request_vars.html:106 229 | msgid "Variable" 230 | msgstr "Variable" 231 | 232 | #: templates/debug_toolbar/panels/request_vars.html:50 233 | msgid "No COOKIE data" 234 | msgstr "Keine COOKIE-Daten" 235 | 236 | #: templates/debug_toolbar/panels/request_vars.html:53 237 | #, fuzzy 238 | msgid "SESSION Variables" 239 | msgstr "Variable" 240 | 241 | #: templates/debug_toolbar/panels/request_vars.html:76 242 | msgid "No SESSION data" 243 | msgstr "Keine SESSION-Daten" 244 | 245 | #: templates/debug_toolbar/panels/request_vars.html:79 246 | #, fuzzy 247 | msgid "GET Variables" 248 | msgstr "Variable" 249 | 250 | #: templates/debug_toolbar/panels/request_vars.html:98 251 | msgid "No GET data" 252 | msgstr "Keine GET-Daten" 253 | 254 | #: templates/debug_toolbar/panels/request_vars.html:101 255 | #, fuzzy 256 | msgid "POST Variables" 257 | msgstr "Variable" 258 | 259 | #: templates/debug_toolbar/panels/request_vars.html:120 260 | msgid "No POST data" 261 | msgstr "Keine POST-Daten" 262 | 263 | #: templates/debug_toolbar/panels/settings_vars.html:5 264 | msgid "Setting" 265 | msgstr "Einstellung" 266 | 267 | #: templates/debug_toolbar/panels/signals.html:5 268 | msgid "Signal" 269 | msgstr "Signal" 270 | 271 | #: templates/debug_toolbar/panels/signals.html:6 272 | msgid "Providing Args" 273 | msgstr "" 274 | 275 | #: templates/debug_toolbar/panels/signals.html:7 276 | msgid "Receivers" 277 | msgstr "" 278 | 279 | #: templates/debug_toolbar/panels/sql.html:6 280 | msgid "Action" 281 | msgstr "Aktion" 282 | 283 | #: templates/debug_toolbar/panels/sql.html:7 284 | msgid "Stacktrace" 285 | msgstr "" 286 | 287 | #: templates/debug_toolbar/panels/sql.html:8 288 | msgid "Query" 289 | msgstr "" 290 | 291 | #: templates/debug_toolbar/panels/sql.html:38 292 | msgid "Line" 293 | msgstr "Zeile" 294 | 295 | #: templates/debug_toolbar/panels/sql.html:39 296 | msgid "Method" 297 | msgstr "Methode" 298 | 299 | #: templates/debug_toolbar/panels/sql.html:40 300 | msgid "File" 301 | msgstr "Datei" 302 | 303 | #: templates/debug_toolbar/panels/sql_explain.html:3 304 | #: templates/debug_toolbar/panels/sql_profile.html:3 305 | #: templates/debug_toolbar/panels/sql_select.html:3 306 | #: templates/debug_toolbar/panels/template_source.html:3 307 | msgid "Back" 308 | msgstr "Zurück" 309 | 310 | #: templates/debug_toolbar/panels/sql_explain.html:4 311 | msgid "SQL Explained" 312 | msgstr "" 313 | 314 | #: templates/debug_toolbar/panels/sql_explain.html:9 315 | #: templates/debug_toolbar/panels/sql_profile.html:10 316 | #: templates/debug_toolbar/panels/sql_select.html:9 317 | msgid "Executed SQL" 318 | msgstr "Ausgeführtes SQL" 319 | 320 | #: templates/debug_toolbar/panels/sql_profile.html:4 321 | msgid "SQL Profiled" 322 | msgstr "" 323 | 324 | #: templates/debug_toolbar/panels/sql_profile.html:35 325 | msgid "Error" 326 | msgstr "Fehler" 327 | 328 | #: templates/debug_toolbar/panels/sql_select.html:4 329 | msgid "SQL Selected" 330 | msgstr "" 331 | 332 | #: templates/debug_toolbar/panels/sql_select.html:34 333 | msgid "Empty set" 334 | msgstr "Leeres Set" 335 | 336 | #: templates/debug_toolbar/panels/template_source.html:4 337 | #, fuzzy 338 | msgid "Template Source" 339 | msgstr "Template" 340 | 341 | #: templates/debug_toolbar/panels/templates.html:2 342 | #, fuzzy 343 | msgid "Template path" 344 | msgstr "Template" 345 | 346 | #: templates/debug_toolbar/panels/templates.html:13 347 | msgid "Template" 348 | msgstr "Template" 349 | 350 | #: templates/debug_toolbar/panels/templates.html:21 351 | #: templates/debug_toolbar/panels/templates.html:37 352 | msgid "Toggle Context" 353 | msgstr "" 354 | 355 | #: templates/debug_toolbar/panels/templates.html:28 356 | #: templates/debug_toolbar/panels/templates.html:43 357 | msgid "None" 358 | msgstr "Nichts" 359 | 360 | #: templates/debug_toolbar/panels/templates.html:31 361 | msgid "Context processor" 362 | msgstr "" 363 | 364 | #: templates/debug_toolbar/panels/timer.html:9 365 | msgid "Resource" 366 | msgstr "Ressource" 367 | 368 | #: templates/debug_toolbar/panels/versions.html:6 369 | msgid "Package" 370 | msgstr "" 371 | 372 | #: templates/debug_toolbar/panels/versions.html:7 373 | #, fuzzy 374 | msgid "Version" 375 | msgstr "Django-Version" 376 | -------------------------------------------------------------------------------- /debug_toolbar/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /debug_toolbar/locale/en/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 2 | # This file is distributed under the same license as the PACKAGE package. 3 | # Percy Pérez-Pinedo, 2009. 4 | # 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PACKAGE VERSION\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2009-11-18 08:06-0800\n" 11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language-Team: LANGUAGE \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #: panels/cache.py:92 19 | #, python-format 20 | msgid "Cache: %.2fms" 21 | msgstr "" 22 | 23 | #: panels/cache.py:95 24 | msgid "Cache Usage" 25 | msgstr "" 26 | 27 | #: panels/headers.py:36 panels/headers.py:39 28 | msgid "HTTP Headers" 29 | msgstr "" 30 | 31 | #: panels/logger.py:56 32 | msgid "Logging" 33 | msgstr "" 34 | 35 | #: panels/logger.py:63 36 | msgid "Log Messages" 37 | msgstr "" 38 | 39 | #: panels/request_vars.py:13 panels/request_vars.py:16 40 | msgid "Request Vars" 41 | msgstr "" 42 | 43 | #: panels/settings_vars.py:16 44 | msgid "Settings" 45 | msgstr "" 46 | 47 | #: panels/settings_vars.py:19 48 | #, python-format 49 | msgid "Settings from %s" 50 | msgstr "" 51 | 52 | #: panels/signals.py:39 panels/signals.py:42 53 | msgid "Signals" 54 | msgstr "" 55 | 56 | #: panels/sql.py:146 57 | msgid "SQL" 58 | msgstr "" 59 | 60 | #: panels/sql.py:160 61 | msgid "SQL Queries" 62 | msgstr "" 63 | 64 | #: panels/template.py:47 65 | msgid "Templates" 66 | msgstr "" 67 | 68 | #: panels/template.py:52 69 | #, python-format 70 | msgid "Templates (%(num_templates)s rendered)" 71 | msgstr "" 72 | 73 | #: panels/timer.py:35 templates/debug_toolbar/panels/cache.html:39 74 | #: templates/debug_toolbar/panels/logger.html:7 75 | #: templates/debug_toolbar/panels/sql.html:5 76 | #: templates/debug_toolbar/panels/sql_explain.html:11 77 | #: templates/debug_toolbar/panels/sql_profile.html:12 78 | #: templates/debug_toolbar/panels/sql_select.html:11 79 | msgid "Time" 80 | msgstr "" 81 | 82 | #: panels/timer.py:47 83 | msgid "Resource Usage" 84 | msgstr "" 85 | 86 | #: panels/timer.py:78 87 | msgid "User CPU time" 88 | msgstr "" 89 | 90 | #: panels/timer.py:79 91 | msgid "System CPU time" 92 | msgstr "" 93 | 94 | #: panels/timer.py:80 95 | msgid "Total CPU time" 96 | msgstr "" 97 | 98 | #: panels/timer.py:81 99 | msgid "Elapsed time" 100 | msgstr "" 101 | 102 | #: panels/timer.py:82 103 | msgid "Context switches" 104 | msgstr "" 105 | 106 | #: panels/version.py:20 panels/version.py:29 107 | msgid "Versions" 108 | msgstr "" 109 | 110 | #: templates/debug_toolbar/base.html:23 111 | msgid "Hide Toolbar" 112 | msgstr "" 113 | 114 | #: templates/debug_toolbar/base.html:23 115 | msgid "Hide" 116 | msgstr "" 117 | 118 | #: templates/debug_toolbar/base.html:48 119 | msgid "Show Toolbar" 120 | msgstr "" 121 | 122 | #: templates/debug_toolbar/base.html:54 123 | msgid "Close" 124 | msgstr "" 125 | 126 | #: templates/debug_toolbar/redirect.html:7 127 | #: templates/debug_toolbar/panels/logger.html:9 128 | msgid "Location" 129 | msgstr "" 130 | 131 | #: templates/debug_toolbar/redirect.html:9 132 | msgid "" 133 | "The Django Debug Toolbar has intercepted a redirect to the above URL for " 134 | "debug viewing purposes. You can click the above link to continue with the " 135 | "redirect as normal. If you'd like to disable this feature, set the " 136 | "DEBUG_TOOLBAR_CONFIG dictionary's key " 137 | "INTERCEPT_REDIRECTS to False." 138 | msgstr "" 139 | 140 | #: templates/debug_toolbar/panels/cache.html:14 141 | msgid "Total Calls" 142 | msgstr "" 143 | 144 | #: templates/debug_toolbar/panels/cache.html:16 145 | msgid "Total Time" 146 | msgstr "" 147 | 148 | #: templates/debug_toolbar/panels/cache.html:18 149 | msgid "Hits" 150 | msgstr "" 151 | 152 | #: templates/debug_toolbar/panels/cache.html:20 153 | msgid "Misses" 154 | msgstr "" 155 | 156 | #: templates/debug_toolbar/panels/cache.html:35 157 | msgid "Breakdown" 158 | msgstr "" 159 | 160 | #: templates/debug_toolbar/panels/cache.html:40 161 | msgid "Type" 162 | msgstr "" 163 | 164 | #: templates/debug_toolbar/panels/cache.html:41 165 | msgid "Parameters" 166 | msgstr "" 167 | 168 | #: templates/debug_toolbar/panels/cache.html:42 169 | msgid "Function" 170 | msgstr "" 171 | 172 | #: templates/debug_toolbar/panels/headers.html:5 173 | msgid "Key" 174 | msgstr "" 175 | 176 | #: templates/debug_toolbar/panels/headers.html:6 177 | #: templates/debug_toolbar/panels/request_vars.html:37 178 | #: templates/debug_toolbar/panels/request_vars.html:63 179 | #: templates/debug_toolbar/panels/request_vars.html:85 180 | #: templates/debug_toolbar/panels/request_vars.html:107 181 | #: templates/debug_toolbar/panels/settings_vars.html:6 182 | #: templates/debug_toolbar/panels/timer.html:10 183 | msgid "Value" 184 | msgstr "" 185 | 186 | #: templates/debug_toolbar/panels/logger.html:6 187 | msgid "Level" 188 | msgstr "" 189 | 190 | #: templates/debug_toolbar/panels/logger.html:8 191 | msgid "Message" 192 | msgstr "" 193 | 194 | #: templates/debug_toolbar/panels/logger.html:24 195 | msgid "No messages logged" 196 | msgstr "" 197 | 198 | #: templates/debug_toolbar/panels/request_vars.html:3 199 | msgid "View information" 200 | msgstr "" 201 | 202 | #: templates/debug_toolbar/panels/request_vars.html:7 203 | msgid "View Function" 204 | msgstr "" 205 | 206 | #: templates/debug_toolbar/panels/request_vars.html:8 207 | msgid "args" 208 | msgstr "" 209 | 210 | #: templates/debug_toolbar/panels/request_vars.html:9 211 | msgid "kwargs" 212 | msgstr "" 213 | 214 | #: templates/debug_toolbar/panels/request_vars.html:27 215 | msgid "COOKIES Variables" 216 | msgstr "" 217 | 218 | #: templates/debug_toolbar/panels/request_vars.html:36 219 | #: templates/debug_toolbar/panels/request_vars.html:62 220 | #: templates/debug_toolbar/panels/request_vars.html:84 221 | #: templates/debug_toolbar/panels/request_vars.html:106 222 | msgid "Variable" 223 | msgstr "" 224 | 225 | #: templates/debug_toolbar/panels/request_vars.html:50 226 | msgid "No COOKIE data" 227 | msgstr "" 228 | 229 | #: templates/debug_toolbar/panels/request_vars.html:53 230 | msgid "SESSION Variables" 231 | msgstr "" 232 | 233 | #: templates/debug_toolbar/panels/request_vars.html:76 234 | msgid "No SESSION data" 235 | msgstr "" 236 | 237 | #: templates/debug_toolbar/panels/request_vars.html:79 238 | msgid "GET Variables" 239 | msgstr "" 240 | 241 | #: templates/debug_toolbar/panels/request_vars.html:98 242 | msgid "No GET data" 243 | msgstr "" 244 | 245 | #: templates/debug_toolbar/panels/request_vars.html:101 246 | msgid "POST Variables" 247 | msgstr "" 248 | 249 | #: templates/debug_toolbar/panels/request_vars.html:120 250 | msgid "No POST data" 251 | msgstr "" 252 | 253 | #: templates/debug_toolbar/panels/settings_vars.html:5 254 | msgid "Setting" 255 | msgstr "" 256 | 257 | #: templates/debug_toolbar/panels/signals.html:5 258 | msgid "Signal" 259 | msgstr "" 260 | 261 | #: templates/debug_toolbar/panels/signals.html:6 262 | msgid "Providing Args" 263 | msgstr "" 264 | 265 | #: templates/debug_toolbar/panels/signals.html:7 266 | msgid "Receivers" 267 | msgstr "" 268 | 269 | #: templates/debug_toolbar/panels/sql.html:6 270 | msgid "Action" 271 | msgstr "" 272 | 273 | #: templates/debug_toolbar/panels/sql.html:7 274 | msgid "Stacktrace" 275 | msgstr "" 276 | 277 | #: templates/debug_toolbar/panels/sql.html:8 278 | msgid "Query" 279 | msgstr "" 280 | 281 | #: templates/debug_toolbar/panels/sql.html:38 282 | msgid "Line" 283 | msgstr "" 284 | 285 | #: templates/debug_toolbar/panels/sql.html:39 286 | msgid "Method" 287 | msgstr "" 288 | 289 | #: templates/debug_toolbar/panels/sql.html:40 290 | msgid "File" 291 | msgstr "" 292 | 293 | #: templates/debug_toolbar/panels/sql_explain.html:3 294 | #: templates/debug_toolbar/panels/sql_profile.html:3 295 | #: templates/debug_toolbar/panels/sql_select.html:3 296 | #: templates/debug_toolbar/panels/template_source.html:3 297 | msgid "Back" 298 | msgstr "" 299 | 300 | #: templates/debug_toolbar/panels/sql_explain.html:4 301 | msgid "SQL Explained" 302 | msgstr "" 303 | 304 | #: templates/debug_toolbar/panels/sql_explain.html:9 305 | #: templates/debug_toolbar/panels/sql_profile.html:10 306 | #: templates/debug_toolbar/panels/sql_select.html:9 307 | msgid "Executed SQL" 308 | msgstr "" 309 | 310 | #: templates/debug_toolbar/panels/sql_profile.html:4 311 | msgid "SQL Profiled" 312 | msgstr "" 313 | 314 | #: templates/debug_toolbar/panels/sql_profile.html:35 315 | msgid "Error" 316 | msgstr "" 317 | 318 | #: templates/debug_toolbar/panels/sql_select.html:4 319 | msgid "SQL Selected" 320 | msgstr "" 321 | 322 | #: templates/debug_toolbar/panels/sql_select.html:34 323 | msgid "Empty set" 324 | msgstr "" 325 | 326 | #: templates/debug_toolbar/panels/template_source.html:4 327 | msgid "Template Source" 328 | msgstr "" 329 | 330 | #: templates/debug_toolbar/panels/templates.html:2 331 | msgid "Template path" 332 | msgstr "" 333 | 334 | #: templates/debug_toolbar/panels/templates.html:13 335 | msgid "Template" 336 | msgstr "" 337 | 338 | #: templates/debug_toolbar/panels/templates.html:21 339 | #: templates/debug_toolbar/panels/templates.html:37 340 | msgid "Toggle Context" 341 | msgstr "" 342 | 343 | #: templates/debug_toolbar/panels/templates.html:28 344 | #: templates/debug_toolbar/panels/templates.html:43 345 | msgid "None" 346 | msgstr "" 347 | 348 | #: templates/debug_toolbar/panels/templates.html:31 349 | msgid "Context processor" 350 | msgstr "" 351 | 352 | #: templates/debug_toolbar/panels/timer.html:9 353 | msgid "Resource" 354 | msgstr "" 355 | 356 | #: templates/debug_toolbar/panels/versions.html:6 357 | msgid "Package" 358 | msgstr "" 359 | 360 | #: templates/debug_toolbar/panels/versions.html:7 361 | msgid "Version" 362 | msgstr "" 363 | -------------------------------------------------------------------------------- /debug_toolbar/locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /debug_toolbar/locale/es/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # Django Debug Toolbar en Español. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # Percy Pérez-Pinedo , 2009. 5 | # 6 | # Caracteres especiales: á, é, í, ó, ú, ñ, 7 | # 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: PACKAGE VERSION\n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2009-11-18 08:06-0800\n" 13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 | "Last-Translator: FULL NAME \n" 15 | "Language-Team: LANGUAGE \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: panels/cache.py:92 21 | #, python-format 22 | msgid "Cache: %.2fms" 23 | msgstr "" 24 | 25 | #: panels/cache.py:95 26 | msgid "Cache Usage" 27 | msgstr "" 28 | 29 | #: panels/headers.py:36 panels/headers.py:39 30 | msgid "HTTP Headers" 31 | msgstr "" 32 | 33 | #: panels/logger.py:56 34 | msgid "Logging" 35 | msgstr "Registros" 36 | 37 | #: panels/logger.py:63 38 | #, fuzzy 39 | msgid "Log Messages" 40 | msgstr "Mensaje" 41 | 42 | #: panels/request_vars.py:13 panels/request_vars.py:16 43 | msgid "Request Vars" 44 | msgstr "" 45 | 46 | #: panels/settings_vars.py:16 47 | msgid "Settings" 48 | msgstr "Configuraciones" 49 | 50 | #: panels/settings_vars.py:19 51 | #, python-format 52 | msgid "Settings from %s" 53 | msgstr "" 54 | 55 | #: panels/signals.py:39 panels/signals.py:42 56 | msgid "Signals" 57 | msgstr "Señales" 58 | 59 | #: panels/sql.py:146 60 | msgid "SQL" 61 | msgstr "" 62 | 63 | #: panels/sql.py:160 64 | msgid "SQL Queries" 65 | msgstr "" 66 | 67 | #: panels/template.py:47 68 | msgid "Templates" 69 | msgstr "Plantillas" 70 | 71 | #: panels/template.py:52 72 | #, python-format 73 | msgid "Templates (%(num_templates)s rendered)" 74 | msgstr "" 75 | 76 | #: panels/timer.py:35 templates/debug_toolbar/panels/cache.html:39 77 | #: templates/debug_toolbar/panels/logger.html:7 78 | #: templates/debug_toolbar/panels/sql.html:5 79 | #: templates/debug_toolbar/panels/sql_explain.html:11 80 | #: templates/debug_toolbar/panels/sql_profile.html:12 81 | #: templates/debug_toolbar/panels/sql_select.html:11 82 | msgid "Time" 83 | msgstr "Tiempo" 84 | 85 | #: panels/timer.py:47 86 | #, fuzzy 87 | msgid "Resource Usage" 88 | msgstr "Recurso" 89 | 90 | #: panels/timer.py:78 91 | msgid "User CPU time" 92 | msgstr "" 93 | 94 | #: panels/timer.py:79 95 | msgid "System CPU time" 96 | msgstr "" 97 | 98 | #: panels/timer.py:80 99 | #, fuzzy 100 | msgid "Total CPU time" 101 | msgstr "Tiempo Total" 102 | 103 | #: panels/timer.py:81 104 | msgid "Elapsed time" 105 | msgstr "" 106 | 107 | #: panels/timer.py:82 108 | msgid "Context switches" 109 | msgstr "" 110 | 111 | #: panels/version.py:20 panels/version.py:29 112 | #, fuzzy 113 | msgid "Versions" 114 | msgstr "Versión Django" 115 | 116 | #: templates/debug_toolbar/base.html:23 117 | msgid "Hide Toolbar" 118 | msgstr "" 119 | 120 | #: templates/debug_toolbar/base.html:23 121 | msgid "Hide" 122 | msgstr "Ocultar" 123 | 124 | #: templates/debug_toolbar/base.html:48 125 | msgid "Show Toolbar" 126 | msgstr "" 127 | 128 | #: templates/debug_toolbar/base.html:54 129 | msgid "Close" 130 | msgstr "Cerrar" 131 | 132 | #: templates/debug_toolbar/redirect.html:7 133 | #: templates/debug_toolbar/panels/logger.html:9 134 | msgid "Location" 135 | msgstr "" 136 | 137 | #: templates/debug_toolbar/redirect.html:9 138 | msgid "" 139 | "The Django Debug Toolbar has intercepted a redirect to the above URL for " 140 | "debug viewing purposes. You can click the above link to continue with the " 141 | "redirect as normal. If you'd like to disable this feature, set the " 142 | "DEBUG_TOOLBAR_CONFIG dictionary's key " 143 | "INTERCEPT_REDIRECTS to False." 144 | msgstr "" 145 | 146 | #: templates/debug_toolbar/panels/cache.html:14 147 | msgid "Total Calls" 148 | msgstr "Total Llamadas" 149 | 150 | #: templates/debug_toolbar/panels/cache.html:16 151 | msgid "Total Time" 152 | msgstr "Tiempo Total" 153 | 154 | #: templates/debug_toolbar/panels/cache.html:18 155 | msgid "Hits" 156 | msgstr "Visitas" 157 | 158 | #: templates/debug_toolbar/panels/cache.html:20 159 | msgid "Misses" 160 | msgstr "" 161 | 162 | #: templates/debug_toolbar/panels/cache.html:35 163 | msgid "Breakdown" 164 | msgstr "" 165 | 166 | #: templates/debug_toolbar/panels/cache.html:40 167 | msgid "Type" 168 | msgstr "Tipo" 169 | 170 | #: templates/debug_toolbar/panels/cache.html:41 171 | msgid "Parameters" 172 | msgstr "Parámetros" 173 | 174 | #: templates/debug_toolbar/panels/cache.html:42 175 | msgid "Function" 176 | msgstr "Función" 177 | 178 | #: templates/debug_toolbar/panels/headers.html:5 179 | msgid "Key" 180 | msgstr "Llave" 181 | 182 | #: templates/debug_toolbar/panels/headers.html:6 183 | #: templates/debug_toolbar/panels/request_vars.html:37 184 | #: templates/debug_toolbar/panels/request_vars.html:63 185 | #: templates/debug_toolbar/panels/request_vars.html:85 186 | #: templates/debug_toolbar/panels/request_vars.html:107 187 | #: templates/debug_toolbar/panels/settings_vars.html:6 188 | #: templates/debug_toolbar/panels/timer.html:10 189 | msgid "Value" 190 | msgstr "Valor" 191 | 192 | #: templates/debug_toolbar/panels/logger.html:6 193 | msgid "Level" 194 | msgstr "Nivel" 195 | 196 | #: templates/debug_toolbar/panels/logger.html:8 197 | msgid "Message" 198 | msgstr "Mensaje" 199 | 200 | #: templates/debug_toolbar/panels/logger.html:24 201 | msgid "No messages logged" 202 | msgstr "No hay mensajes registrados" 203 | 204 | #: templates/debug_toolbar/panels/request_vars.html:3 205 | msgid "View information" 206 | msgstr "" 207 | 208 | #: templates/debug_toolbar/panels/request_vars.html:7 209 | #, fuzzy 210 | msgid "View Function" 211 | msgstr "Función" 212 | 213 | #: templates/debug_toolbar/panels/request_vars.html:8 214 | msgid "args" 215 | msgstr "" 216 | 217 | #: templates/debug_toolbar/panels/request_vars.html:9 218 | msgid "kwargs" 219 | msgstr "" 220 | 221 | #: templates/debug_toolbar/panels/request_vars.html:27 222 | #, fuzzy 223 | msgid "COOKIES Variables" 224 | msgstr "Variable" 225 | 226 | #: templates/debug_toolbar/panels/request_vars.html:36 227 | #: templates/debug_toolbar/panels/request_vars.html:62 228 | #: templates/debug_toolbar/panels/request_vars.html:84 229 | #: templates/debug_toolbar/panels/request_vars.html:106 230 | #, fuzzy 231 | msgid "Variable" 232 | msgstr "Variable" 233 | 234 | #: templates/debug_toolbar/panels/request_vars.html:50 235 | #, fuzzy 236 | msgid "No COOKIE data" 237 | msgstr "No GET datos" 238 | 239 | #: templates/debug_toolbar/panels/request_vars.html:53 240 | #, fuzzy 241 | msgid "SESSION Variables" 242 | msgstr "Variable" 243 | 244 | #: templates/debug_toolbar/panels/request_vars.html:76 245 | msgid "No SESSION data" 246 | msgstr "No SESSION datos" 247 | 248 | #: templates/debug_toolbar/panels/request_vars.html:79 249 | #, fuzzy 250 | msgid "GET Variables" 251 | msgstr "Variable" 252 | 253 | #: templates/debug_toolbar/panels/request_vars.html:98 254 | msgid "No GET data" 255 | msgstr "No GET datos" 256 | 257 | #: templates/debug_toolbar/panels/request_vars.html:101 258 | #, fuzzy 259 | msgid "POST Variables" 260 | msgstr "Variable" 261 | 262 | #: templates/debug_toolbar/panels/request_vars.html:120 263 | msgid "No POST data" 264 | msgstr "No POST datos" 265 | 266 | #: templates/debug_toolbar/panels/settings_vars.html:5 267 | msgid "Setting" 268 | msgstr "Configuración" 269 | 270 | #: templates/debug_toolbar/panels/signals.html:5 271 | msgid "Signal" 272 | msgstr "Señal" 273 | 274 | #: templates/debug_toolbar/panels/signals.html:6 275 | msgid "Providing Args" 276 | msgstr "" 277 | 278 | #: templates/debug_toolbar/panels/signals.html:7 279 | msgid "Receivers" 280 | msgstr "" 281 | 282 | #: templates/debug_toolbar/panels/sql.html:6 283 | msgid "Action" 284 | msgstr "Acción" 285 | 286 | #: templates/debug_toolbar/panels/sql.html:7 287 | msgid "Stacktrace" 288 | msgstr "" 289 | 290 | #: templates/debug_toolbar/panels/sql.html:8 291 | msgid "Query" 292 | msgstr "" 293 | 294 | #: templates/debug_toolbar/panels/sql.html:38 295 | msgid "Line" 296 | msgstr "Línea" 297 | 298 | #: templates/debug_toolbar/panels/sql.html:39 299 | msgid "Method" 300 | msgstr "Método" 301 | 302 | #: templates/debug_toolbar/panels/sql.html:40 303 | msgid "File" 304 | msgstr "Archivo" 305 | 306 | #: templates/debug_toolbar/panels/sql_explain.html:3 307 | #: templates/debug_toolbar/panels/sql_profile.html:3 308 | #: templates/debug_toolbar/panels/sql_select.html:3 309 | #: templates/debug_toolbar/panels/template_source.html:3 310 | msgid "Back" 311 | msgstr "Regresar" 312 | 313 | #: templates/debug_toolbar/panels/sql_explain.html:4 314 | msgid "SQL Explained" 315 | msgstr "" 316 | 317 | #: templates/debug_toolbar/panels/sql_explain.html:9 318 | #: templates/debug_toolbar/panels/sql_profile.html:10 319 | #: templates/debug_toolbar/panels/sql_select.html:9 320 | msgid "Executed SQL" 321 | msgstr "SQL Ejecutado" 322 | 323 | #: templates/debug_toolbar/panels/sql_profile.html:4 324 | msgid "SQL Profiled" 325 | msgstr "" 326 | 327 | #: templates/debug_toolbar/panels/sql_profile.html:35 328 | msgid "Error" 329 | msgstr "" 330 | 331 | #: templates/debug_toolbar/panels/sql_select.html:4 332 | msgid "SQL Selected" 333 | msgstr "" 334 | 335 | #: templates/debug_toolbar/panels/sql_select.html:34 336 | msgid "Empty set" 337 | msgstr "Set Vacío" 338 | 339 | #: templates/debug_toolbar/panels/template_source.html:4 340 | #, fuzzy 341 | msgid "Template Source" 342 | msgstr "Plantilla" 343 | 344 | #: templates/debug_toolbar/panels/templates.html:2 345 | #, fuzzy 346 | msgid "Template path" 347 | msgstr "Plantilla" 348 | 349 | #: templates/debug_toolbar/panels/templates.html:13 350 | msgid "Template" 351 | msgstr "Plantilla" 352 | 353 | #: templates/debug_toolbar/panels/templates.html:21 354 | #: templates/debug_toolbar/panels/templates.html:37 355 | msgid "Toggle Context" 356 | msgstr "" 357 | 358 | #: templates/debug_toolbar/panels/templates.html:28 359 | #: templates/debug_toolbar/panels/templates.html:43 360 | msgid "None" 361 | msgstr "Ninguno" 362 | 363 | #: templates/debug_toolbar/panels/templates.html:31 364 | msgid "Context processor" 365 | msgstr "" 366 | 367 | #: templates/debug_toolbar/panels/timer.html:9 368 | msgid "Resource" 369 | msgstr "Recurso" 370 | 371 | #: templates/debug_toolbar/panels/versions.html:6 372 | msgid "Package" 373 | msgstr "" 374 | 375 | #: templates/debug_toolbar/panels/versions.html:7 376 | #, fuzzy 377 | msgid "Version" 378 | msgstr "Versión Django" 379 | -------------------------------------------------------------------------------- /debug_toolbar/locale/fr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/locale/fr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /debug_toolbar/locale/he/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/locale/he/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /debug_toolbar/locale/he/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PACKAGE VERSION\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2009-11-18 08:06-0800\n" 11 | "PO-Revision-Date: 2009-08-24 23:08-0600\n" 12 | "Last-Translator: Alex \n" 13 | "Language-Team: LANGUAGE \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #: panels/cache.py:92 19 | #, python-format 20 | msgid "Cache: %.2fms" 21 | msgstr "" 22 | 23 | #: panels/cache.py:95 24 | msgid "Cache Usage" 25 | msgstr "" 26 | 27 | #: panels/headers.py:36 panels/headers.py:39 28 | msgid "HTTP Headers" 29 | msgstr "" 30 | 31 | #: panels/logger.py:56 32 | msgid "Logging" 33 | msgstr "רישום יומן" 34 | 35 | #: panels/logger.py:63 36 | #, fuzzy 37 | msgid "Log Messages" 38 | msgstr "הודעה" 39 | 40 | #: panels/request_vars.py:13 panels/request_vars.py:16 41 | msgid "Request Vars" 42 | msgstr "" 43 | 44 | #: panels/settings_vars.py:16 45 | msgid "Settings" 46 | msgstr "" 47 | 48 | #: panels/settings_vars.py:19 49 | #, python-format 50 | msgid "Settings from %s" 51 | msgstr "" 52 | 53 | #: panels/signals.py:39 panels/signals.py:42 54 | msgid "Signals" 55 | msgstr "סימנים" 56 | 57 | #: panels/sql.py:146 58 | msgid "SQL" 59 | msgstr "" 60 | 61 | #: panels/sql.py:160 62 | msgid "SQL Queries" 63 | msgstr "" 64 | 65 | #: panels/template.py:47 66 | msgid "Templates" 67 | msgstr "תבניות" 68 | 69 | #: panels/template.py:52 70 | #, python-format 71 | msgid "Templates (%(num_templates)s rendered)" 72 | msgstr "" 73 | 74 | #: panels/timer.py:35 templates/debug_toolbar/panels/cache.html:39 75 | #: templates/debug_toolbar/panels/logger.html:7 76 | #: templates/debug_toolbar/panels/sql.html:5 77 | #: templates/debug_toolbar/panels/sql_explain.html:11 78 | #: templates/debug_toolbar/panels/sql_profile.html:12 79 | #: templates/debug_toolbar/panels/sql_select.html:11 80 | msgid "Time" 81 | msgstr "זמן" 82 | 83 | #: panels/timer.py:47 84 | msgid "Resource Usage" 85 | msgstr "" 86 | 87 | #: panels/timer.py:78 88 | msgid "User CPU time" 89 | msgstr "" 90 | 91 | #: panels/timer.py:79 92 | msgid "System CPU time" 93 | msgstr "" 94 | 95 | #: panels/timer.py:80 96 | #, fuzzy 97 | msgid "Total CPU time" 98 | msgstr "זמן" 99 | 100 | #: panels/timer.py:81 101 | msgid "Elapsed time" 102 | msgstr "" 103 | 104 | #: panels/timer.py:82 105 | msgid "Context switches" 106 | msgstr "" 107 | 108 | #: panels/version.py:20 panels/version.py:29 109 | #, fuzzy 110 | msgid "Versions" 111 | msgstr "ג 'נגו גירסה" 112 | 113 | #: templates/debug_toolbar/base.html:23 114 | msgid "Hide Toolbar" 115 | msgstr "" 116 | 117 | #: templates/debug_toolbar/base.html:23 118 | msgid "Hide" 119 | msgstr "הסתיר" 120 | 121 | #: templates/debug_toolbar/base.html:48 122 | msgid "Show Toolbar" 123 | msgstr "" 124 | 125 | #: templates/debug_toolbar/base.html:54 126 | msgid "Close" 127 | msgstr "סגור" 128 | 129 | #: templates/debug_toolbar/redirect.html:7 130 | #: templates/debug_toolbar/panels/logger.html:9 131 | msgid "Location" 132 | msgstr "מקום" 133 | 134 | #: templates/debug_toolbar/redirect.html:9 135 | msgid "" 136 | "The Django Debug Toolbar has intercepted a redirect to the above URL for " 137 | "debug viewing purposes. You can click the above link to continue with the " 138 | "redirect as normal. If you'd like to disable this feature, set the " 139 | "DEBUG_TOOLBAR_CONFIG dictionary's key " 140 | "INTERCEPT_REDIRECTS to False." 141 | msgstr "" 142 | 143 | #: templates/debug_toolbar/panels/cache.html:14 144 | msgid "Total Calls" 145 | msgstr "" 146 | 147 | #: templates/debug_toolbar/panels/cache.html:16 148 | msgid "Total Time" 149 | msgstr "זמן" 150 | 151 | #: templates/debug_toolbar/panels/cache.html:18 152 | msgid "Hits" 153 | msgstr "הצלחות" 154 | 155 | #: templates/debug_toolbar/panels/cache.html:20 156 | msgid "Misses" 157 | msgstr "" 158 | 159 | #: templates/debug_toolbar/panels/cache.html:35 160 | msgid "Breakdown" 161 | msgstr "" 162 | 163 | #: templates/debug_toolbar/panels/cache.html:40 164 | msgid "Type" 165 | msgstr "סוג" 166 | 167 | #: templates/debug_toolbar/panels/cache.html:41 168 | msgid "Parameters" 169 | msgstr "" 170 | 171 | #: templates/debug_toolbar/panels/cache.html:42 172 | msgid "Function" 173 | msgstr "" 174 | 175 | #: templates/debug_toolbar/panels/headers.html:5 176 | msgid "Key" 177 | msgstr "מפתח" 178 | 179 | #: templates/debug_toolbar/panels/headers.html:6 180 | #: templates/debug_toolbar/panels/request_vars.html:37 181 | #: templates/debug_toolbar/panels/request_vars.html:63 182 | #: templates/debug_toolbar/panels/request_vars.html:85 183 | #: templates/debug_toolbar/panels/request_vars.html:107 184 | #: templates/debug_toolbar/panels/settings_vars.html:6 185 | #: templates/debug_toolbar/panels/timer.html:10 186 | msgid "Value" 187 | msgstr "ערך" 188 | 189 | #: templates/debug_toolbar/panels/logger.html:6 190 | msgid "Level" 191 | msgstr "רמה" 192 | 193 | #: templates/debug_toolbar/panels/logger.html:8 194 | msgid "Message" 195 | msgstr "הודעה" 196 | 197 | #: templates/debug_toolbar/panels/logger.html:24 198 | msgid "No messages logged" 199 | msgstr "אין הודעות" 200 | 201 | #: templates/debug_toolbar/panels/request_vars.html:3 202 | msgid "View information" 203 | msgstr "" 204 | 205 | #: templates/debug_toolbar/panels/request_vars.html:7 206 | msgid "View Function" 207 | msgstr "" 208 | 209 | #: templates/debug_toolbar/panels/request_vars.html:8 210 | msgid "args" 211 | msgstr "" 212 | 213 | #: templates/debug_toolbar/panels/request_vars.html:9 214 | msgid "kwargs" 215 | msgstr "" 216 | 217 | #: templates/debug_toolbar/panels/request_vars.html:27 218 | #, fuzzy 219 | msgid "COOKIES Variables" 220 | msgstr "מזהה" 221 | 222 | #: templates/debug_toolbar/panels/request_vars.html:36 223 | #: templates/debug_toolbar/panels/request_vars.html:62 224 | #: templates/debug_toolbar/panels/request_vars.html:84 225 | #: templates/debug_toolbar/panels/request_vars.html:106 226 | msgid "Variable" 227 | msgstr "מזהה" 228 | 229 | #: templates/debug_toolbar/panels/request_vars.html:50 230 | msgid "No COOKIE data" 231 | msgstr "אין נתונים לעוגיות" 232 | 233 | #: templates/debug_toolbar/panels/request_vars.html:53 234 | #, fuzzy 235 | msgid "SESSION Variables" 236 | msgstr "מזהה" 237 | 238 | #: templates/debug_toolbar/panels/request_vars.html:76 239 | msgid "No SESSION data" 240 | msgstr "אין נתונים להתחברות" 241 | 242 | #: templates/debug_toolbar/panels/request_vars.html:79 243 | #, fuzzy 244 | msgid "GET Variables" 245 | msgstr "מזהה" 246 | 247 | #: templates/debug_toolbar/panels/request_vars.html:98 248 | msgid "No GET data" 249 | msgstr "שום דבר עבור GET" 250 | 251 | #: templates/debug_toolbar/panels/request_vars.html:101 252 | #, fuzzy 253 | msgid "POST Variables" 254 | msgstr "מזהה" 255 | 256 | #: templates/debug_toolbar/panels/request_vars.html:120 257 | msgid "No POST data" 258 | msgstr "שום דבר עבור POST" 259 | 260 | #: templates/debug_toolbar/panels/settings_vars.html:5 261 | msgid "Setting" 262 | msgstr "" 263 | 264 | #: templates/debug_toolbar/panels/signals.html:5 265 | msgid "Signal" 266 | msgstr "סימן" 267 | 268 | #: templates/debug_toolbar/panels/signals.html:6 269 | msgid "Providing Args" 270 | msgstr "" 271 | 272 | #: templates/debug_toolbar/panels/signals.html:7 273 | msgid "Receivers" 274 | msgstr "" 275 | 276 | #: templates/debug_toolbar/panels/sql.html:6 277 | msgid "Action" 278 | msgstr "פעילות" 279 | 280 | #: templates/debug_toolbar/panels/sql.html:7 281 | msgid "Stacktrace" 282 | msgstr "" 283 | 284 | #: templates/debug_toolbar/panels/sql.html:8 285 | msgid "Query" 286 | msgstr "" 287 | 288 | #: templates/debug_toolbar/panels/sql.html:38 289 | msgid "Line" 290 | msgstr "שורה" 291 | 292 | #: templates/debug_toolbar/panels/sql.html:39 293 | msgid "Method" 294 | msgstr "" 295 | 296 | #: templates/debug_toolbar/panels/sql.html:40 297 | msgid "File" 298 | msgstr "קובץ" 299 | 300 | #: templates/debug_toolbar/panels/sql_explain.html:3 301 | #: templates/debug_toolbar/panels/sql_profile.html:3 302 | #: templates/debug_toolbar/panels/sql_select.html:3 303 | #: templates/debug_toolbar/panels/template_source.html:3 304 | msgid "Back" 305 | msgstr "חזרה" 306 | 307 | #: templates/debug_toolbar/panels/sql_explain.html:4 308 | msgid "SQL Explained" 309 | msgstr "" 310 | 311 | #: templates/debug_toolbar/panels/sql_explain.html:9 312 | #: templates/debug_toolbar/panels/sql_profile.html:10 313 | #: templates/debug_toolbar/panels/sql_select.html:9 314 | msgid "Executed SQL" 315 | msgstr "הסבר עבור SQL" 316 | 317 | #: templates/debug_toolbar/panels/sql_profile.html:4 318 | msgid "SQL Profiled" 319 | msgstr "" 320 | 321 | #: templates/debug_toolbar/panels/sql_profile.html:35 322 | msgid "Error" 323 | msgstr "שגיאה" 324 | 325 | #: templates/debug_toolbar/panels/sql_select.html:4 326 | msgid "SQL Selected" 327 | msgstr "" 328 | 329 | #: templates/debug_toolbar/panels/sql_select.html:34 330 | msgid "Empty set" 331 | msgstr "תוצאות ריק" 332 | 333 | #: templates/debug_toolbar/panels/template_source.html:4 334 | #, fuzzy 335 | msgid "Template Source" 336 | msgstr "תבנית" 337 | 338 | #: templates/debug_toolbar/panels/templates.html:2 339 | #, fuzzy 340 | msgid "Template path" 341 | msgstr "תבנית" 342 | 343 | #: templates/debug_toolbar/panels/templates.html:13 344 | msgid "Template" 345 | msgstr "תבנית" 346 | 347 | #: templates/debug_toolbar/panels/templates.html:21 348 | #: templates/debug_toolbar/panels/templates.html:37 349 | msgid "Toggle Context" 350 | msgstr "" 351 | 352 | #: templates/debug_toolbar/panels/templates.html:28 353 | #: templates/debug_toolbar/panels/templates.html:43 354 | msgid "None" 355 | msgstr "" 356 | 357 | #: templates/debug_toolbar/panels/templates.html:31 358 | msgid "Context processor" 359 | msgstr "" 360 | 361 | #: templates/debug_toolbar/panels/timer.html:9 362 | msgid "Resource" 363 | msgstr "" 364 | 365 | #: templates/debug_toolbar/panels/versions.html:6 366 | msgid "Package" 367 | msgstr "" 368 | 369 | #: templates/debug_toolbar/panels/versions.html:7 370 | #, fuzzy 371 | msgid "Version" 372 | msgstr "ג 'נגו גירסה" 373 | -------------------------------------------------------------------------------- /debug_toolbar/locale/ru/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/locale/ru/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /debug_toolbar/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/management/__init__.py -------------------------------------------------------------------------------- /debug_toolbar/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/management/commands/__init__.py -------------------------------------------------------------------------------- /debug_toolbar/management/commands/debugsqlshell.py: -------------------------------------------------------------------------------- 1 | import os 2 | from optparse import make_option 3 | from datetime import datetime 4 | 5 | from django.core.management.base import NoArgsCommand 6 | from django.db.backends import util 7 | 8 | from debug_toolbar.utils import sqlparse 9 | 10 | class PrintQueryWrapper(util.CursorDebugWrapper): 11 | def execute(self, sql, params=()): 12 | starttime = datetime.today() 13 | try: 14 | return self.cursor.execute(sql, params) 15 | finally: 16 | raw_sql = self.db.ops.last_executed_query(self.cursor, sql, params) 17 | execution_time = datetime.today() - starttime 18 | print sqlparse.format(raw_sql, reindent=True) 19 | print 20 | print 'Execution time: %fs' % execution_time.total_seconds() 21 | print 22 | 23 | util.CursorDebugWrapper = PrintQueryWrapper 24 | 25 | # The rest is copy/paste from django/core/management/commands/shell.py 26 | 27 | class Command(NoArgsCommand): 28 | option_list = NoArgsCommand.option_list + ( 29 | make_option('--plain', action='store_true', dest='plain', 30 | help='Tells Django to use plain Python, not IPython.'), 31 | ) 32 | help = "Runs a Python interactive interpreter. Tries to use IPython, if it's available." 33 | 34 | requires_model_validation = False 35 | 36 | def handle_noargs(self, **options): 37 | # XXX: (Temporary) workaround for ticket #1796: force early loading of all 38 | # models from installed apps. 39 | from django.db.models.loading import get_models 40 | loaded_models = get_models() 41 | 42 | use_plain = options.get('plain', False) 43 | 44 | try: 45 | if use_plain: 46 | # Don't bother loading IPython, because the user wants plain Python. 47 | raise ImportError 48 | import IPython 49 | # Explicitly pass an empty list as arguments, because otherwise IPython 50 | # would use sys.argv from this script. 51 | shell = IPython.Shell.IPShell(argv=[]) 52 | shell.mainloop() 53 | except ImportError: 54 | import code 55 | # Set up a dictionary to serve as the environment for the shell, so 56 | # that tab completion works on objects that are imported at runtime. 57 | # See ticket 5082. 58 | imported_objects = {} 59 | try: # Try activating rlcompleter, because it's handy. 60 | import readline 61 | except ImportError: 62 | pass 63 | else: 64 | # We don't have to wrap the following import in a 'try', because 65 | # we already know 'readline' was imported successfully. 66 | import rlcompleter 67 | readline.set_completer(rlcompleter.Completer(imported_objects).complete) 68 | readline.parse_and_bind("tab:complete") 69 | 70 | # We want to honor both $PYTHONSTARTUP and .pythonrc.py, so follow system 71 | # conventions and get $PYTHONSTARTUP first then import user. 72 | if not use_plain: 73 | pythonrc = os.environ.get("PYTHONSTARTUP") 74 | if pythonrc and os.path.isfile(pythonrc): 75 | try: 76 | execfile(pythonrc) 77 | except NameError: 78 | pass 79 | # This will import .pythonrc.py as a side-effect 80 | import user 81 | code.interact(local=imported_objects) 82 | -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/Makefile: -------------------------------------------------------------------------------- 1 | # Make file to compress and join all JS files 2 | all: compress_js compress_css 3 | 4 | compress_js: 5 | java -jar ~/bin/yuicompressor.jar js/jquery.js > js/toolbar.min.js 6 | java -jar ~/bin/yuicompressor.jar js/toolbar.js >> js/toolbar.min.js 7 | 8 | compress_css: 9 | java -jar ~/bin/yuicompressor.jar --type css css/toolbar.css > css/toolbar.min.css 10 | -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/media/debug_toolbar/img/back.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/back_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/media/debug_toolbar/img/back_hover.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/media/debug_toolbar/img/close.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/close_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/media/debug_toolbar/img/close_hover.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/djdt_vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/media/debug_toolbar/img/djdt_vertical.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/dot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/media/debug_toolbar/img/dot.gif -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/media/debug_toolbar/img/indicator.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/img/panel_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/media/debug_toolbar/img/panel_bg.png -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/js/jquery.cookie.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Cookie plugin 3 | * 4 | * Copyright (c) 2006 Klaus Hartl (stilbuero.de) 5 | * Dual licensed under the MIT and GPL licenses: 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * http://www.gnu.org/licenses/gpl.html 8 | * 9 | */ 10 | 11 | /** 12 | * Create a cookie with the given name and value and other optional parameters. 13 | * 14 | * @example $.cookie('the_cookie', 'the_value'); 15 | * @desc Set the value of a cookie. 16 | * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); 17 | * @desc Create a cookie with all available options. 18 | * @example $.cookie('the_cookie', 'the_value'); 19 | * @desc Create a session cookie. 20 | * @example $.cookie('the_cookie', null); 21 | * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain 22 | * used when the cookie was set. 23 | * 24 | * @param String name The name of the cookie. 25 | * @param String value The value of the cookie. 26 | * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. 27 | * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. 28 | * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. 29 | * If set to null or omitted, the cookie will be a session cookie and will not be retained 30 | * when the the browser exits. 31 | * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). 32 | * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). 33 | * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will 34 | * require a secure protocol (like HTTPS). 35 | * @type undefined 36 | * 37 | * @name $.cookie 38 | * @cat Plugins/Cookie 39 | * @author Klaus Hartl/klaus.hartl@stilbuero.de 40 | */ 41 | 42 | /** 43 | * Get the value of a cookie with the given name. 44 | * 45 | * @example $.cookie('the_cookie'); 46 | * @desc Get the value of a cookie. 47 | * 48 | * @param String name The name of the cookie. 49 | * @return The value of the cookie. 50 | * @type String 51 | * 52 | * @name $.cookie 53 | * @cat Plugins/Cookie 54 | * @author Klaus Hartl/klaus.hartl@stilbuero.de 55 | */ 56 | jQuery.cookie = function(name, value, options) { 57 | if (typeof value != 'undefined') { // name and value given, set cookie 58 | options = options || {}; 59 | if (value === null) { 60 | value = ''; 61 | options.expires = -1; 62 | } 63 | var expires = ''; 64 | if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { 65 | var date; 66 | if (typeof options.expires == 'number') { 67 | date = new Date(); 68 | date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); 69 | } else { 70 | date = options.expires; 71 | } 72 | expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE 73 | } 74 | // CAUTION: Needed to parenthesize options.path and options.domain 75 | // in the following expressions, otherwise they evaluate to undefined 76 | // in the packed version for some reason... 77 | var path = options.path ? '; path=' + (options.path) : ''; 78 | var domain = options.domain ? '; domain=' + (options.domain) : ''; 79 | var secure = options.secure ? '; secure' : ''; 80 | document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); 81 | } else { // only name given, get cookie 82 | var cookieValue = null; 83 | if (document.cookie && document.cookie != '') { 84 | var cookies = document.cookie.split(';'); 85 | for (var i = 0; i < cookies.length; i++) { 86 | var cookie = jQuery.trim(cookies[i]); 87 | // Does this cookie string begin with the name we want? 88 | if (cookie.substring(0, name.length + 1) == (name + '=')) { 89 | cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 90 | break; 91 | } 92 | } 93 | } 94 | return cookieValue; 95 | } 96 | }; -------------------------------------------------------------------------------- /debug_toolbar/media/debug_toolbar/js/toolbar.js: -------------------------------------------------------------------------------- 1 | window.djdt = (function(window, document, jQuery) { 2 | jQuery.cookie = function(name, value, options) { if (typeof value != 'undefined') { options = options || {}; if (value === null) { value = ''; options.expires = -1; } var expires = ''; if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { var date; if (typeof options.expires == 'number') { date = new Date(); date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); } else { date = options.expires; } expires = '; expires=' + date.toUTCString(); } var path = options.path ? '; path=' + (options.path) : ''; var domain = options.domain ? '; domain=' + (options.domain) : ''; var secure = options.secure ? '; secure' : ''; document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); } else { var cookieValue = null; if (document.cookie && document.cookie != '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = $.trim(cookies[i]); if (cookie.substring(0, name.length + 1) == (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } }; 3 | var $ = jQuery; 4 | var COOKIE_NAME = 'djdt'; 5 | var djdt = { 6 | jQuery: jQuery, 7 | events: { 8 | ready: [] 9 | }, 10 | isReady: false, 11 | init: function() { 12 | $('#djDebug').show(); 13 | var current = null; 14 | $('#djDebugPanelList li a').click(function() { 15 | if (!this.className) { 16 | return false; 17 | } 18 | current = $('#djDebug #' + this.className); 19 | if (current.is(':visible')) { 20 | $(document).trigger('close.djDebug'); 21 | $(this).parent().removeClass('active'); 22 | } else { 23 | $('.panelContent').hide(); // Hide any that are already open 24 | current.show(); 25 | $('#djDebugToolbar li').removeClass('active'); 26 | $(this).parent().addClass('active'); 27 | } 28 | return false; 29 | }); 30 | $('#djDebug a.djDebugClose').click(function() { 31 | $(document).trigger('close.djDebug'); 32 | $('#djDebugToolbar li').removeClass('active'); 33 | return false; 34 | }); 35 | $('#djDebug a.remoteCall').click(function() { 36 | $('#djDebugWindow').load(this.href, function(response, status, xhr) { 37 | if (status == "error") { 38 | var message = '
Back

'+xhr.status+': '+xhr.statusText+'

'; 39 | $('#djDebugWindow').html(message); 40 | } 41 | $('#djDebugWindow a.djDebugBack').click(function() { 42 | $(this).parent().parent().hide(); 43 | return false; 44 | }); 45 | }); 46 | $('#djDebugWindow').show(); 47 | return false; 48 | }); 49 | $('#djDebugTemplatePanel a.djTemplateShowContext').click(function() { 50 | djdt.toggle_arrow($(this).children('.toggleArrow')); 51 | djdt.toggle_content($(this).parent().next()); 52 | return false; 53 | }); 54 | $('#djDebug a.djToggleSwitch').click(function(e) { 55 | e.preventDefault(); 56 | var btn = $(this); 57 | var id = btn.attr('data-toggle-id'); 58 | var open_me = btn.text() == btn.attr('data-toggle-open'); 59 | if (id == '' || !id) { 60 | return; 61 | } 62 | 63 | $(this).parents('.djDebugPanelContent').find('.djToggleDetails_' + id).each(function(){ 64 | var $this = $(this); 65 | if (open_me) { 66 | $this.addClass('djSelected'); 67 | $this.removeClass('djUnselected'); 68 | btn.text(btn.attr('data-toggle-close')); 69 | $this.find('.djToggleSwitch').text(btn.text()); 70 | } else { 71 | $this.removeClass('djSelected'); 72 | $this.addClass('djUnselected'); 73 | btn.text(btn.attr('data-toggle-open')); 74 | $this.find('.djToggleSwitch').text(btn.text()); 75 | } 76 | }); 77 | return; 78 | }); 79 | function getSubcalls(row) { 80 | id = row.attr('id'); 81 | return $('.djDebugProfileRow[id^="'+id+'_"]'); 82 | } 83 | function getDirectSubcalls(row) { 84 | subcalls = getSubcalls(row); 85 | depth = parseInt(row.attr('depth')) + 1; 86 | return subcalls.filter('[depth='+depth+']'); 87 | } 88 | $('.djDebugProfileRow .djDebugProfileToggle').click(function(){ 89 | row = $(this).closest('.djDebugProfileRow') 90 | subcalls = getSubcalls(row); 91 | if (subcalls.css('display')=='none') { 92 | getDirectSubcalls(row).show(); 93 | } else { 94 | subcalls.hide(); 95 | } 96 | }); 97 | 98 | $('#djDebug-htmlvalidator .handle-position').click(function(){ 99 | $('#djDebug-htmlvalidator .repr-info-sel').removeClass('repr-info-sel'); 100 | $(this).parent().parent().addClass('repr-info-sel') 101 | var text = $(this).text(); 102 | var re = new RegExp('line\\s+([0-9]+)'); 103 | var result = text.match(re); 104 | 105 | try{ 106 | var lineno = result[1]; 107 | }catch(e){return;} 108 | // 109 | var prevPos = $(document).data('reprlineselpos') || null; 110 | if(prevPos){ 111 | prevPos.removeClass('repr-line-sel'); 112 | } 113 | $('#djDebug-htmlvalidator .repr-line-' + lineno).addClass('repr-line-sel'); 114 | $(document).data('reprlineselpos', $('.repr-line-' + lineno)); 115 | // skip pervious link and add new one 116 | var locationPrefix = location; 117 | if(location.href.indexOf('#repr-line-') > -1){ 118 | var newLocation = location.href.substring(0, location.href.indexOf('#repr')); 119 | locationPrefix = newLocation; 120 | } 121 | location = locationPrefix + '#' + 'repr-line-' + lineno; 122 | }); 123 | $('#djDebug-htmlvalidator .tidy-msg').click(function(e){ 124 | $('.handle-position:first', $(this).prev()).click(); 125 | }); 126 | $('#djHideToolBarButton').click(function() { 127 | djdt.hide_toolbar(true); 128 | return false; 129 | }); 130 | $('#djShowToolBarButton').click(function() { 131 | djdt.show_toolbar(); 132 | return false; 133 | }); 134 | $(document).bind('close.djDebug', function() { 135 | // If a sub-panel is open, close that 136 | if ($('#djDebugWindow').is(':visible')) { 137 | $('#djDebugWindow').hide(); 138 | return; 139 | } 140 | // If a panel is open, close that 141 | if ($('.panelContent').is(':visible')) { 142 | $('.panelContent').hide(); 143 | return; 144 | } 145 | // Otherwise, just minimize the toolbar 146 | if ($('#djDebugToolbar').is(':visible')) { 147 | djdt.hide_toolbar(true); 148 | return; 149 | } 150 | }); 151 | if ($.cookie(COOKIE_NAME)) { 152 | djdt.hide_toolbar(false); 153 | } else { 154 | djdt.show_toolbar(false); 155 | } 156 | $('#djDebug .djDebugHoverable').hover(function(){ 157 | $(this).addClass('djDebugHover'); 158 | }, function(){ 159 | $(this).removeClass('djDebugHover'); 160 | }); 161 | djdt.isReady = true; 162 | $.each(djdt.events.ready, function(_, callback){ 163 | callback(djdt); 164 | }); 165 | }, 166 | toggle_content: function(elem) { 167 | if (elem.is(':visible')) { 168 | elem.hide(); 169 | } else { 170 | elem.show(); 171 | } 172 | }, 173 | close: function() { 174 | $(document).trigger('close.djDebug'); 175 | return false; 176 | }, 177 | hide_toolbar: function(setCookie) { 178 | // close any sub panels 179 | $('#djDebugWindow').hide(); 180 | // close all panels 181 | $('.panelContent').hide(); 182 | $('#djDebugToolbar li').removeClass('active'); 183 | // finally close toolbar 184 | $('#djDebugToolbar').hide('fast'); 185 | $('#djDebugToolbarHandle').show(); 186 | // Unbind keydown 187 | $(document).unbind('keydown.djDebug'); 188 | if (setCookie) { 189 | $.cookie(COOKIE_NAME, 'hide', { 190 | path: '/', 191 | expires: 10 192 | }); 193 | } 194 | }, 195 | show_toolbar: function(animate) { 196 | // Set up keybindings 197 | $(document).bind('keydown.djDebug', function(e) { 198 | if (e.keyCode == 27) { 199 | djdt.close(); 200 | } 201 | }); 202 | $('#djDebugToolbarHandle').hide(); 203 | if (animate) { 204 | $('#djDebugToolbar').show('fast'); 205 | } else { 206 | $('#djDebugToolbar').show(); 207 | } 208 | $.cookie(COOKIE_NAME, null, { 209 | path: '/', 210 | expires: -1 211 | }); 212 | }, 213 | toggle_arrow: function(elem) { 214 | var uarr = String.fromCharCode(0x25b6); 215 | var darr = String.fromCharCode(0x25bc); 216 | elem.html(elem.html() == uarr ? darr : uarr); 217 | }, 218 | ready: function(callback){ 219 | if (djdt.isReady) { 220 | callback(djdt); 221 | } else { 222 | djdt.events.ready.push(callback); 223 | } 224 | } 225 | }; 226 | $(document).ready(function() { 227 | djdt.init(); 228 | }); 229 | return djdt; 230 | }(window, document, jQuery.noConflict())); 231 | -------------------------------------------------------------------------------- /debug_toolbar/middleware.py: -------------------------------------------------------------------------------- 1 | """ 2 | Debug Toolbar middleware 3 | """ 4 | import imp 5 | import thread 6 | 7 | from django.conf import settings 8 | from django.conf.urls.defaults import include, patterns 9 | from django.http import HttpResponseRedirect 10 | from django.shortcuts import render_to_response 11 | from django.utils.encoding import smart_unicode 12 | 13 | import debug_toolbar.urls 14 | from debug_toolbar.toolbar.loader import DebugToolbar 15 | 16 | _HTML_TYPES = ('text/html', 'application/xhtml+xml') 17 | 18 | def replace_insensitive(string, target, replacement): 19 | """ 20 | Similar to string.replace() but is case insensitive 21 | Code borrowed from: http://forums.devshed.com/python-programming-11/case-insensitive-string-replace-490921.html 22 | """ 23 | no_case = string.lower() 24 | index = no_case.rfind(target.lower()) 25 | if index >= 0: 26 | return string[:index] + replacement + string[index + len(target):] 27 | else: # no results so return the original string 28 | return string 29 | 30 | class DebugToolbarMiddleware(object): 31 | """ 32 | Middleware to set up Debug Toolbar on incoming request and render toolbar 33 | on outgoing response. 34 | """ 35 | debug_toolbars = {} 36 | 37 | @classmethod 38 | def get_current(cls): 39 | return cls.debug_toolbars.get(thread.get_ident()) 40 | 41 | def __init__(self): 42 | self._urlconfs = {} 43 | 44 | # Set method to use to decide to show toolbar 45 | self.show_toolbar = self._show_toolbar # default 46 | 47 | # The tag to attach the toolbar to 48 | self.tag= u'' 49 | 50 | if hasattr(settings, 'DEBUG_TOOLBAR_CONFIG'): 51 | show_toolbar_callback = settings.DEBUG_TOOLBAR_CONFIG.get( 52 | 'SHOW_TOOLBAR_CALLBACK', None) 53 | if show_toolbar_callback: 54 | self.show_toolbar = show_toolbar_callback 55 | 56 | tag = settings.DEBUG_TOOLBAR_CONFIG.get('TAG', None) 57 | if tag: 58 | self.tag = u'' 59 | 60 | def _show_toolbar(self, request): 61 | if getattr(settings, 'TEST', False): 62 | return False 63 | 64 | x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', None) 65 | if x_forwarded_for: 66 | remote_addr = x_forwarded_for.split(',')[0].strip() 67 | else: 68 | remote_addr = request.META.get('REMOTE_ADDR', None) 69 | 70 | # if not internal ip, and not DEBUG 71 | if not (remote_addr in settings.INTERNAL_IPS or settings.DEBUG): 72 | return False 73 | 74 | return True 75 | 76 | def process_request(self, request): 77 | __traceback_hide__ = True 78 | if self.show_toolbar(request): 79 | 80 | urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF) 81 | if isinstance(urlconf, basestring): 82 | urlconf = __import__(getattr(request, 'urlconf', settings.ROOT_URLCONF), {}, {}, ['*']) 83 | 84 | if urlconf not in self._urlconfs: 85 | new_urlconf = imp.new_module('urlconf') 86 | new_urlconf.urlpatterns = debug_toolbar.urls.urlpatterns + \ 87 | patterns('', 88 | ('', include(urlconf)), 89 | ) 90 | 91 | if hasattr(urlconf, 'handler404'): 92 | new_urlconf.handler404 = urlconf.handler404 93 | if hasattr(urlconf, 'handler500'): 94 | new_urlconf.handler500 = urlconf.handler500 95 | 96 | self._urlconfs[urlconf] = new_urlconf 97 | 98 | request.urlconf = self._urlconfs[urlconf] 99 | 100 | toolbar = DebugToolbar(request) 101 | for panel in toolbar.panels: 102 | panel.process_request(request) 103 | self.__class__.debug_toolbars[thread.get_ident()] = toolbar 104 | 105 | def process_view(self, request, view_func, view_args, view_kwargs): 106 | __traceback_hide__ = True 107 | toolbar = self.__class__.debug_toolbars.get(thread.get_ident()) 108 | if not toolbar: 109 | return 110 | for panel in toolbar.panels: 111 | panel.process_view(request, view_func, view_args, view_kwargs) 112 | 113 | def process_response(self, request, response): 114 | __traceback_hide__ = True 115 | ident = thread.get_ident() 116 | toolbar = self.__class__.debug_toolbars.get(ident) 117 | if not toolbar: 118 | return response 119 | if isinstance(response, HttpResponseRedirect): 120 | if not toolbar.config['INTERCEPT_REDIRECTS']: 121 | return response 122 | redirect_to = response.get('Location', None) 123 | if redirect_to: 124 | cookies = response.cookies 125 | response = render_to_response( 126 | 'debug_toolbar/redirect.html', 127 | {'redirect_to': redirect_to} 128 | ) 129 | response.cookies = cookies 130 | if 'gzip' not in response.get('Content-Encoding', '') and \ 131 | response.get('Content-Type', '').split(';')[0] in _HTML_TYPES: 132 | for panel in toolbar.panels: 133 | panel.process_response(request, response) 134 | response.content = replace_insensitive( 135 | smart_unicode(response.content), 136 | self.tag, 137 | smart_unicode(toolbar.render_toolbar() + self.tag)) 138 | if response.get('Content-Length', None): 139 | response['Content-Length'] = len(response.content) 140 | del self.__class__.debug_toolbars[ident] 141 | return response 142 | -------------------------------------------------------------------------------- /debug_toolbar/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/models.py -------------------------------------------------------------------------------- /debug_toolbar/panels/__init__.py: -------------------------------------------------------------------------------- 1 | """Base DebugPanel class""" 2 | 3 | class DebugPanel(object): 4 | """ 5 | Base class for debug panels. 6 | """ 7 | # name = Base 8 | has_content = False # If content returns something, set to true in subclass 9 | 10 | # We'll maintain a local context instance so we can expose our template 11 | # context variables to panels which need them: 12 | context = {} 13 | 14 | # Panel methods 15 | def __init__(self, context={}): 16 | self.context.update(context) 17 | 18 | def dom_id(self): 19 | return 'djDebug%sPanel' % (self.name.replace(' ', '')) 20 | 21 | def nav_title(self): 22 | """Title showing in toolbar""" 23 | raise NotImplementedError 24 | 25 | def nav_subtitle(self): 26 | """Subtitle showing until title in toolbar""" 27 | return '' 28 | 29 | def title(self): 30 | """Title showing in panel""" 31 | raise NotImplementedError 32 | 33 | def url(self): 34 | raise NotImplementedError 35 | 36 | def content(self): 37 | raise NotImplementedError 38 | 39 | # Standard middleware methods 40 | def process_request(self, request): 41 | pass 42 | 43 | def process_view(self, request, view_func, view_args, view_kwargs): 44 | pass 45 | 46 | def process_response(self, request, response): 47 | pass 48 | 49 | -------------------------------------------------------------------------------- /debug_toolbar/panels/cache.py: -------------------------------------------------------------------------------- 1 | import time 2 | import inspect 3 | 4 | from django.core import cache 5 | from django.core.cache.backends.base import BaseCache 6 | from django.template.loader import render_to_string 7 | from django.utils.translation import ugettext_lazy as _ 8 | from debug_toolbar.panels import DebugPanel 9 | 10 | class CacheStatTracker(BaseCache): 11 | """A small class used to track cache calls.""" 12 | def __init__(self, cache): 13 | self.cache = cache 14 | self.reset() 15 | 16 | def reset(self): 17 | self.calls = [] 18 | self.hits = 0 19 | self.misses = 0 20 | self.sets = 0 21 | self.gets = 0 22 | self.get_many = 0 23 | self.deletes = 0 24 | self.total_time = 0 25 | 26 | def _get_func_info(self): 27 | stack = inspect.stack()[2] 28 | return (stack[1], stack[2], stack[3], stack[4]) 29 | 30 | def get(self, key, default=None): 31 | t = time.time() 32 | value = self.cache.get(key, default) 33 | this_time = time.time() - t 34 | self.total_time += this_time * 1000 35 | if value is None: 36 | self.misses += 1 37 | else: 38 | self.hits += 1 39 | self.gets += 1 40 | self.calls.append((this_time, 'get', (key,), self._get_func_info())) 41 | return value 42 | 43 | def set(self, key, value, timeout=None): 44 | t = time.time() 45 | self.cache.set(key, value, timeout) 46 | this_time = time.time() - t 47 | self.total_time += this_time * 1000 48 | self.sets += 1 49 | self.calls.append((this_time, 'set', (key, value, timeout), self._get_func_info())) 50 | 51 | def delete(self, key): 52 | t = time.time() 53 | self.cache.delete(key) 54 | this_time = time.time() - t 55 | self.total_time += this_time * 1000 56 | self.deletes += 1 57 | self.calls.append((this_time, 'delete', (key,), self._get_func_info())) 58 | 59 | def get_many(self, keys): 60 | t = time.time() 61 | results = self.cache.get_many(keys) 62 | this_time = time.time() - t 63 | self.total_time += this_time * 1000 64 | self.get_many += 1 65 | for key, value in results.iteritems(): 66 | if value is None: 67 | self.misses += 1 68 | else: 69 | self.hits += 1 70 | self.calls.append((this_time, 'get_many', (keys,), self._get_func_info())) 71 | 72 | class CacheDebugPanel(DebugPanel): 73 | """ 74 | Panel that displays the cache statistics. 75 | """ 76 | name = 'Cache' 77 | has_content = True 78 | 79 | def __init__(self, *args, **kwargs): 80 | super(self.__class__, self).__init__(*args, **kwargs) 81 | # This is hackish but to prevent threading issues is somewhat needed 82 | if isinstance(cache.cache, CacheStatTracker): 83 | cache.cache.reset() 84 | self.cache = cache.cache 85 | else: 86 | self.cache = CacheStatTracker(cache.cache) 87 | cache.cache = self.cache 88 | 89 | def nav_title(self): 90 | return _('Cache: %.2fms') % self.cache.total_time 91 | 92 | def title(self): 93 | return _('Cache Usage') 94 | 95 | def url(self): 96 | return '' 97 | 98 | def content(self): 99 | context = self.context.copy() 100 | context.update({ 101 | 'cache_calls': len(self.cache.calls), 102 | 'cache_time': self.cache.total_time, 103 | 'cache': self.cache, 104 | }) 105 | return render_to_string('debug_toolbar/panels/cache.html', context) 106 | -------------------------------------------------------------------------------- /debug_toolbar/panels/headers.py: -------------------------------------------------------------------------------- 1 | from django.template.loader import render_to_string 2 | from django.utils.translation import ugettext_lazy as _ 3 | from debug_toolbar.panels import DebugPanel 4 | 5 | class HeaderDebugPanel(DebugPanel): 6 | """ 7 | A panel to display HTTP headers. 8 | """ 9 | name = 'Header' 10 | has_content = True 11 | # List of headers we want to display 12 | header_filter = ( 13 | 'CONTENT_TYPE', 14 | 'HTTP_ACCEPT', 15 | 'HTTP_ACCEPT_CHARSET', 16 | 'HTTP_ACCEPT_ENCODING', 17 | 'HTTP_ACCEPT_LANGUAGE', 18 | 'HTTP_CACHE_CONTROL', 19 | 'HTTP_CONNECTION', 20 | 'HTTP_HOST', 21 | 'HTTP_KEEP_ALIVE', 22 | 'HTTP_REFERER', 23 | 'HTTP_USER_AGENT', 24 | 'QUERY_STRING', 25 | 'REMOTE_ADDR', 26 | 'REMOTE_HOST', 27 | 'REQUEST_METHOD', 28 | 'SCRIPT_NAME', 29 | 'SERVER_NAME', 30 | 'SERVER_PORT', 31 | 'SERVER_PROTOCOL', 32 | 'SERVER_SOFTWARE', 33 | ) 34 | 35 | def nav_title(self): 36 | return _('HTTP Headers') 37 | 38 | def title(self): 39 | return _('HTTP Headers') 40 | 41 | def url(self): 42 | return '' 43 | 44 | def process_request(self, request): 45 | self.headers = dict( 46 | [(k, request.META[k]) for k in self.header_filter if k in request.META] 47 | ) 48 | 49 | def content(self): 50 | context = self.context.copy() 51 | context.update({ 52 | 'headers': self.headers 53 | }) 54 | return render_to_string('debug_toolbar/panels/headers.html', context) 55 | -------------------------------------------------------------------------------- /debug_toolbar/panels/htmlvalidator.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | try: 4 | from tidylib import tidy_document 5 | except ImportError: 6 | raise ImportError("""Please, make sure that PyTidyLib 7 | module installed - it's required for HTMLValidationDebugPanel""") 8 | 9 | from django.template.loader import render_to_string 10 | from django.utils.translation import ugettext_lazy as _ 11 | from django.utils.safestring import mark_safe 12 | 13 | from debug_toolbar.panels import DebugPanel 14 | 15 | 16 | class HTMLValidationDebugPanel(DebugPanel): 17 | name = "HTMLValidator" 18 | has_content = True 19 | 20 | log_data = None 21 | errors_count = 0 22 | warns_count = 0 23 | src_content = '' 24 | 25 | def nav_title(self): 26 | return _("HTML Validator") 27 | 28 | def nav_subtitle(self): 29 | return mark_safe(_(u"Tidy Errors: %(errors_cnt)d "\ 30 | u"Warnings: %(warns_cnt)d") % { 31 | 'errors_cnt': self.errors_count, 32 | 'warns_cnt': self.warns_count, 33 | }) 34 | 35 | def title(self): 36 | return _("HTML Validator") 37 | 38 | def url(self): 39 | return '' 40 | 41 | def process_response(self, request, response): 42 | document, errors = tidy_document(response.content, 43 | options={'numeric-entities': 1}) 44 | self.log_data = (document, errors) 45 | self.src_content = response.content 46 | errors_list = errors.split('\n') 47 | self.errors_count = len([err for err in errors_list \ 48 | if 'error:' in err.lower()]) 49 | self.warns_count = len([err for err in errors_list \ 50 | if 'warning:' in err.lower()]) 51 | 52 | return response 53 | 54 | def appearance(self, errors): 55 | replacements = [ 56 | (re.compile(r'\<([^\>]*)\>'), \ 57 | '<\\1>'), 58 | (re.compile(r'(line[^\-]*)(.*)'), \ 59 | u'
\\1
\\2'), 60 | (re.compile(r'\s*\-\s+(Error\:|Warning\:)', re.I), \ 61 | u'\\1'), 62 | ] 63 | 64 | for rx, rp in replacements: 65 | errors = re.sub(rx, rp, errors) 66 | 67 | errors_list = errors.split('\n') 68 | errors_rt = [] 69 | # mark lines with error with validation-error class 70 | for err in errors_list: 71 | if 'error:' in err.lower(): 72 | err = err.replace('', '') 73 | errors_rt.append(err) 74 | continue 75 | errors_rt.append(err) 76 | 77 | return errors_rt 78 | 79 | def content(self): 80 | context = self.context.copy() 81 | 82 | document, errors = self.log_data 83 | lines = self.src_content.split("\n") 84 | 85 | context.update({ 86 | 'document': document, 87 | 'lines': zip(range(1, len(lines) + 1), lines), 88 | 'errors': self.appearance(errors), 89 | }) 90 | 91 | return render_to_string(\ 92 | 'debug_toolbar/panels/htmlvalidator.html', context) 93 | -------------------------------------------------------------------------------- /debug_toolbar/panels/logger.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import logging 3 | try: 4 | import threading 5 | except ImportError: 6 | threading = None 7 | from django.template.loader import render_to_string 8 | from django.utils.translation import ugettext_lazy as _ 9 | from debug_toolbar.panels import DebugPanel 10 | 11 | 12 | class LogCollector(object): 13 | def __init__(self): 14 | if threading is None: 15 | raise NotImplementedError("threading module is not available, \ 16 | the logging panel cannot be used without it") 17 | self.records = {} # a dictionary that maps threads to log records 18 | 19 | def add_record(self, record, thread=None): 20 | # Avoid logging SQL queries since they are already in the SQL panel 21 | # TODO: Make this check whether SQL panel is enabled 22 | if record.get('channel', '') == 'django.db.backends': 23 | return 24 | 25 | self.get_records(thread).append(record) 26 | 27 | def get_records(self, thread=None): 28 | """ 29 | Returns a list of records for the provided thread, of if none is provided, 30 | returns a list for the current thread. 31 | """ 32 | if thread is None: 33 | thread = threading.currentThread() 34 | if thread not in self.records: 35 | self.records[thread] = [] 36 | return self.records[thread] 37 | 38 | def clear_records(self, thread=None): 39 | if thread is None: 40 | thread = threading.currentThread() 41 | if thread in self.records: 42 | del self.records[thread] 43 | 44 | 45 | class ThreadTrackingHandler(logging.Handler): 46 | def __init__(self, collector): 47 | logging.Handler.__init__(self) 48 | self.collector = collector 49 | 50 | def emit(self, record): 51 | record = { 52 | 'message': record.getMessage(), 53 | 'time': datetime.datetime.fromtimestamp(record.created), 54 | 'level': record.levelname, 55 | 'file': record.pathname, 56 | 'line': record.lineno, 57 | 'channel': record.name, 58 | } 59 | self.collector.add_record(record) 60 | 61 | 62 | collector = LogCollector() 63 | logging_handler = ThreadTrackingHandler(collector) 64 | logging.root.setLevel(logging.NOTSET) 65 | logging.root.addHandler(logging_handler) # register with logging 66 | 67 | try: 68 | import logbook 69 | logbook_supported = True 70 | except ImportError: 71 | # logbook support is optional, so fail silently 72 | logbook_supported = False 73 | 74 | if logbook_supported: 75 | class LogbookThreadTrackingHandler(logbook.handlers.Handler): 76 | def __init__(self, collector): 77 | logbook.handlers.Handler.__init__(self, bubble=True) 78 | self.collector = collector 79 | 80 | def emit(self, record): 81 | record = { 82 | 'message': record.message, 83 | 'time': record.time, 84 | 'level': record.level_name, 85 | 'file': record.filename, 86 | 'line': record.lineno, 87 | 'channel': record.channel, 88 | } 89 | self.collector.add_record(record) 90 | 91 | 92 | logbook_handler = LogbookThreadTrackingHandler(collector) 93 | logbook_handler.push_application() # register with logbook 94 | 95 | class LoggingPanel(DebugPanel): 96 | name = 'Logging' 97 | has_content = True 98 | 99 | def process_request(self, request): 100 | collector.clear_records() 101 | 102 | def get_and_delete(self): 103 | records = collector.get_records() 104 | collector.clear_records() 105 | return records 106 | 107 | def nav_title(self): 108 | return _("Logging") 109 | 110 | def nav_subtitle(self): 111 | # FIXME l10n: use ngettext 112 | return "%s message%s" % (len(collector.get_records()), (len(collector.get_records()) == 1) and '' or 's') 113 | 114 | def title(self): 115 | return _('Log Messages') 116 | 117 | def url(self): 118 | return '' 119 | 120 | def content(self): 121 | records = self.get_and_delete() 122 | context = self.context.copy() 123 | context.update({'records': records}) 124 | 125 | return render_to_string('debug_toolbar/panels/logger.html', context) 126 | 127 | -------------------------------------------------------------------------------- /debug_toolbar/panels/profiling.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | 3 | from django.template.loader import render_to_string 4 | from django.utils.translation import ugettext_lazy as _ 5 | from django.utils.safestring import mark_safe 6 | from debug_toolbar.panels import DebugPanel 7 | 8 | import cProfile 9 | from pstats import Stats 10 | from colorsys import hsv_to_rgb 11 | 12 | class DjangoDebugToolbarStats(Stats): 13 | __root = None 14 | 15 | def get_root_func(self): 16 | if self.__root is None: 17 | for func, (cc, nc, tt, ct, callers) in self.stats.iteritems(): 18 | if len(callers) == 0: 19 | self.__root = func 20 | break 21 | return self.__root 22 | 23 | def print_call_tree_node(self, function, depth, max_depth, cum_filter=0.1): 24 | self.print_line(function, depth=depth) 25 | if depth < max_depth: 26 | for called in self.all_callees[function].keys(): 27 | if self.stats[called][3] >= cum_filter: 28 | self.print_call_tree_node(called, depth+1, max_depth, cum_filter=cum_filter) 29 | 30 | class FunctionCall(object): 31 | def __init__(self, statobj, func, depth=0, stats=None, id=0, parent_ids=[], hsv=(0,0.5,1)): 32 | self.statobj = statobj 33 | self.func = func 34 | if stats: 35 | self.stats = stats 36 | else: 37 | self.stats = statobj.stats[func][:4] 38 | self.depth = depth 39 | self.id = id 40 | self.parent_ids = parent_ids 41 | self.hsv = hsv 42 | 43 | def parent_classes(self): 44 | return self.parent_classes 45 | 46 | def background(self): 47 | r,g,b = hsv_to_rgb(*self.hsv) 48 | return 'rgb(%f%%,%f%%,%f%%)' %(r*100, g*100, b*100) 49 | 50 | def func_std_string(self): # match what old profile produced 51 | func_name = self.func 52 | if func_name[:2] == ('~', 0): 53 | # special case for built-in functions 54 | name = func_name[2] 55 | if name.startswith('<') and name.endswith('>'): 56 | return '{%s}' % name[1:-1] 57 | else: 58 | return name 59 | else: 60 | file_name, line_num, method = self.func 61 | idx = file_name.find('/site-packages/') 62 | if idx > -1: 63 | file_name=file_name[idx+14:] 64 | 65 | file_path, file_name = file_name.rsplit('/', 1) 66 | 67 | return mark_safe('{0}/{1} in {3}({2})'.format( 68 | file_path, 69 | file_name, 70 | line_num, 71 | method, 72 | )) 73 | 74 | def subfuncs(self): 75 | i=0 76 | h,s,v = self.hsv 77 | count = len(self.statobj.all_callees[self.func]) 78 | for func, stats in self.statobj.all_callees[self.func].iteritems(): 79 | i += 1 80 | h1 = h + (i/count)/(self.depth+1) 81 | if stats[3] == 0: 82 | s1 = 0 83 | else: 84 | s1 = s*(stats[3]/self.stats[3]) 85 | yield FunctionCall(self.statobj, 86 | func, 87 | self.depth+1, 88 | stats=stats, 89 | id=str(self.id) + '_' + str(i), 90 | parent_ids=self.parent_ids + [self.id], 91 | hsv=(h1,s1,1)) 92 | 93 | def count(self): 94 | return self.stats[1] 95 | 96 | def tottime(self): 97 | return self.stats[2] 98 | 99 | def cumtime(self): 100 | cc, nc, tt, ct = self.stats 101 | return self.stats[3] 102 | 103 | def tottime_per_call(self): 104 | cc, nc, tt, ct = self.stats 105 | 106 | if nc == 0: 107 | return 0 108 | 109 | return tt/nc 110 | 111 | def cumtime_per_call(self): 112 | cc, nc, tt, ct = self.stats 113 | 114 | if cc == 0: 115 | return 0 116 | 117 | return ct/cc 118 | 119 | def indent(self): 120 | return 16 * self.depth 121 | 122 | class ProfilingDebugPanel(DebugPanel): 123 | """ 124 | Panel that displays the Django version. 125 | """ 126 | name = 'Profiling' 127 | has_content = True 128 | 129 | def nav_title(self): 130 | return _('Profiling') 131 | 132 | def url(self): 133 | return '' 134 | 135 | def title(self): 136 | return _('Profiling') 137 | 138 | def process_view(self, request, view_func, view_args, view_kwargs): 139 | __traceback_hide__ = True 140 | self.profiler = cProfile.Profile() 141 | args = (request,) + view_args 142 | return self.profiler.runcall(view_func, *args, **view_kwargs) 143 | 144 | def process_response(self, request, response): 145 | self.profiler.create_stats() 146 | self.stats = DjangoDebugToolbarStats(self.profiler) 147 | return response 148 | 149 | def add_node(self, func_list, func, max_depth, cum_time=0.1): 150 | func_list.append(func) 151 | func.has_subfuncs = False 152 | if func.depth < max_depth: 153 | for subfunc in func.subfuncs(): 154 | if subfunc.stats[3] >= cum_time: 155 | func.has_subfuncs = True 156 | self.add_node(func_list, subfunc, max_depth, cum_time=cum_time) 157 | 158 | def content(self): 159 | 160 | self.stats.calc_callees() 161 | root = FunctionCall(self.stats, self.stats.get_root_func(), depth=0) 162 | 163 | func_list = [] 164 | self.add_node(func_list, root, 10, root.stats[3]/8) 165 | context = self.context.copy() 166 | context.update({ 167 | 'func_list': func_list, 168 | }) 169 | 170 | return render_to_string('debug_toolbar/panels/profiling.html', context) 171 | -------------------------------------------------------------------------------- /debug_toolbar/panels/request_vars.py: -------------------------------------------------------------------------------- 1 | from django.template.loader import render_to_string 2 | from django.utils.translation import ugettext_lazy as _ 3 | from debug_toolbar.panels import DebugPanel 4 | 5 | class RequestVarsDebugPanel(DebugPanel): 6 | """ 7 | A panel to display request variables (POST/GET, session, cookies). 8 | """ 9 | name = 'RequestVars' 10 | has_content = True 11 | 12 | def nav_title(self): 13 | return _('Request Vars') 14 | 15 | def title(self): 16 | return _('Request Vars') 17 | 18 | def url(self): 19 | return '' 20 | 21 | def process_request(self, request): 22 | self.request = request 23 | 24 | def process_view(self, request, view_func, view_args, view_kwargs): 25 | self.view_func = view_func 26 | self.view_args = view_args 27 | self.view_kwargs = view_kwargs 28 | 29 | def content(self): 30 | context = self.context.copy() 31 | 32 | if hasattr(self.view_func, '__name__'): 33 | view_name = self.view_func.__name__ 34 | elif hasattr(self.view_func, '__class__'): 35 | view_name = self.view_func.__class__.__name__ 36 | else: 37 | view_name = '' 38 | 39 | context.update({ 40 | 'get': [(k, self.request.GET.getlist(k)) for k in self.request.GET], 41 | 'post': [(k, self.request.POST.getlist(k)) for k in self.request.POST], 42 | 'cookies': [(k, self.request.COOKIES.get(k)) for k in self.request.COOKIES], 43 | 'view_func': '%s.%s' % (self.view_func.__module__, view_name), 44 | 'view_args': self.view_args, 45 | 'view_kwargs': self.view_kwargs 46 | }) 47 | if hasattr(self.request, 'session'): 48 | context.update({ 49 | 'session': [(k, self.request.session.get(k)) for k in self.request.session.iterkeys()] 50 | }) 51 | 52 | return render_to_string('debug_toolbar/panels/request_vars.html', context) 53 | -------------------------------------------------------------------------------- /debug_toolbar/panels/settings_vars.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.template.loader import render_to_string 3 | from django.views.debug import get_safe_settings 4 | from django.utils.translation import ugettext_lazy as _ 5 | from debug_toolbar.panels import DebugPanel 6 | 7 | 8 | class SettingsVarsDebugPanel(DebugPanel): 9 | """ 10 | A panel to display all variables in django.conf.settings 11 | """ 12 | name = 'SettingsVars' 13 | has_content = True 14 | 15 | def nav_title(self): 16 | return _('Settings') 17 | 18 | def title(self): 19 | return _('Settings from %s') % settings.SETTINGS_MODULE 20 | 21 | def url(self): 22 | return '' 23 | 24 | def content(self): 25 | context = self.context.copy() 26 | context.update({ 27 | 'settings': get_safe_settings(), 28 | }) 29 | return render_to_string('debug_toolbar/panels/settings_vars.html', context) 30 | -------------------------------------------------------------------------------- /debug_toolbar/panels/signals.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from django.conf import settings 4 | from django.core.signals import request_started, request_finished, \ 5 | got_request_exception 6 | from django.db.models.signals import class_prepared, pre_init, post_init, \ 7 | pre_save, post_save, pre_delete, post_delete, post_syncdb 8 | from django.dispatch.dispatcher import WEAKREF_TYPES 9 | from django.template.loader import render_to_string 10 | from django.utils.translation import ugettext_lazy as _ 11 | 12 | try: 13 | from django.db.backends.signals import connection_created 14 | except ImportError: 15 | connection_created = None 16 | 17 | from debug_toolbar.panels import DebugPanel 18 | 19 | class SignalDebugPanel(DebugPanel): 20 | name = "Signals" 21 | has_content = True 22 | 23 | SIGNALS = { 24 | 'request_started': request_started, 25 | 'request_finished': request_finished, 26 | 'got_request_exception': got_request_exception, 27 | 'connection_created': connection_created, 28 | 'class_prepared': class_prepared, 29 | 'pre_init': pre_init, 30 | 'post_init': post_init, 31 | 'pre_save': pre_save, 32 | 'post_save': post_save, 33 | 'pre_delete': pre_delete, 34 | 'post_delete': post_delete, 35 | 'post_syncdb': post_syncdb, 36 | } 37 | 38 | def nav_title(self): 39 | return _("Signals") 40 | 41 | def title(self): 42 | return _("Signals") 43 | 44 | def url(self): 45 | return '' 46 | 47 | def signals(self): 48 | signals = self.SIGNALS.copy() 49 | if hasattr(settings, 'DEBUG_TOOLBAR_CONFIG'): 50 | extra_signals = settings.DEBUG_TOOLBAR_CONFIG.get('EXTRA_SIGNALS', []) 51 | else: 52 | extra_signals = [] 53 | for signal in extra_signals: 54 | parts = signal.split('.') 55 | path = '.'.join(parts[:-1]) 56 | __import__(path) 57 | signals[parts[-1]] = getattr(sys.modules[path], parts[-1]) 58 | return signals 59 | signals = property(signals) 60 | 61 | def content(self): 62 | signals = [] 63 | keys = self.signals.keys() 64 | keys.sort() 65 | for name in keys: 66 | signal = self.signals[name] 67 | if signal is None: 68 | continue 69 | receivers = [] 70 | for (receiverkey, r_senderkey), receiver in signal.receivers: 71 | if isinstance(receiver, WEAKREF_TYPES): 72 | receiver = receiver() 73 | if receiver is None: 74 | continue 75 | if getattr(receiver, 'im_self', None) is not None: 76 | text = "method %s on %s object" % (receiver.__name__, receiver.im_self.__class__.__name__) 77 | elif getattr(receiver, 'im_class', None) is not None: 78 | text = "method %s on %s" % (receiver.__name__, receiver.im_class.__name__) 79 | else: 80 | text = "function %s" % receiver.__name__ 81 | receivers.append(text) 82 | signals.append((name, signal, receivers)) 83 | 84 | context = self.context.copy() 85 | context.update({'signals': signals}) 86 | 87 | return render_to_string('debug_toolbar/panels/signals.html', context) 88 | -------------------------------------------------------------------------------- /debug_toolbar/panels/sql.py: -------------------------------------------------------------------------------- 1 | import re 2 | import uuid 3 | 4 | from django.db.backends import BaseDatabaseWrapper 5 | from django.template.loader import render_to_string 6 | from django.utils.html import escape 7 | from django.utils.safestring import mark_safe 8 | from django.utils.translation import ugettext_lazy as _, ungettext_lazy as __ 9 | 10 | from debug_toolbar.utils.compat.db import connections 11 | from debug_toolbar.middleware import DebugToolbarMiddleware 12 | from debug_toolbar.panels import DebugPanel 13 | from debug_toolbar.utils import sqlparse 14 | from debug_toolbar.utils.tracking.db import CursorWrapper 15 | from debug_toolbar.utils.tracking import replace_call 16 | 17 | # Inject our tracking cursor 18 | @replace_call(BaseDatabaseWrapper.cursor) 19 | def cursor(func, self): 20 | result = func(self) 21 | 22 | djdt = DebugToolbarMiddleware.get_current() 23 | if not djdt: 24 | return result 25 | logger = djdt.get_panel(SQLDebugPanel) 26 | 27 | return CursorWrapper(result, self, logger=logger) 28 | 29 | def get_isolation_level_display(engine, level): 30 | if engine == 'psycopg2': 31 | import psycopg2.extensions 32 | choices = { 33 | psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT: 'Autocommit', 34 | psycopg2.extensions.ISOLATION_LEVEL_READ_UNCOMMITTED: 'Read uncommitted', 35 | psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED: 'Read committed', 36 | psycopg2.extensions.ISOLATION_LEVEL_REPEATABLE_READ: 'Repeatable read', 37 | psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE: 'Serializable', 38 | } 39 | else: 40 | raise ValueError(engine) 41 | 42 | return choices.get(level) 43 | 44 | def get_transaction_status_display(engine, level): 45 | if engine == 'psycopg2': 46 | import psycopg2.extensions 47 | choices = { 48 | psycopg2.extensions.TRANSACTION_STATUS_IDLE: 'Idle', 49 | psycopg2.extensions.TRANSACTION_STATUS_ACTIVE: 'Active', 50 | psycopg2.extensions.TRANSACTION_STATUS_INTRANS: 'In transaction', 51 | psycopg2.extensions.TRANSACTION_STATUS_INERROR: 'In error', 52 | psycopg2.extensions.TRANSACTION_STATUS_UNKNOWN: 'Unknown', 53 | } 54 | else: 55 | raise ValueError(engine) 56 | 57 | return choices.get(level) 58 | 59 | class SQLDebugPanel(DebugPanel): 60 | """ 61 | Panel that displays information about the SQL queries run while processing 62 | the request. 63 | """ 64 | name = 'SQL' 65 | has_content = True 66 | 67 | def __init__(self, *args, **kwargs): 68 | super(self.__class__, self).__init__(*args, **kwargs) 69 | self._offset = dict((k, len(connections[k].queries)) for k in connections) 70 | self._sql_time = 0 71 | self._num_queries = 0 72 | self._queries = [] 73 | self._databases = {} 74 | self._transaction_status = {} 75 | self._transaction_ids = {} 76 | 77 | def get_transaction_id(self, alias): 78 | conn = connections[alias].connection 79 | if not conn: 80 | return None 81 | 82 | engine = conn.__class__.__module__.split('.', 1)[0] 83 | if engine == 'psycopg2': 84 | cur_status = conn.get_transaction_status() 85 | else: 86 | raise ValueError(engine) 87 | 88 | last_status = self._transaction_status.get(alias) 89 | self._transaction_status[alias] = cur_status 90 | 91 | if not cur_status: 92 | # No available state 93 | return None 94 | 95 | if cur_status != last_status: 96 | if cur_status: 97 | self._transaction_ids[alias] = uuid.uuid4().hex 98 | else: 99 | self._transaction_ids[alias] = None 100 | 101 | return self._transaction_ids[alias] 102 | 103 | def record(self, alias, **kwargs): 104 | self._queries.append((alias, kwargs)) 105 | if alias not in self._databases: 106 | self._databases[alias] = { 107 | 'time_spent': kwargs['duration'], 108 | 'num_queries': 1, 109 | } 110 | else: 111 | self._databases[alias]['time_spent'] += kwargs['duration'] 112 | self._databases[alias]['num_queries'] += 1 113 | self._sql_time += kwargs['duration'] 114 | self._num_queries += 1 115 | 116 | def nav_title(self): 117 | return _('SQL') 118 | 119 | def nav_subtitle(self): 120 | # TODO l10n: use ngettext 121 | return "%d %s in %.2fms" % ( 122 | self._num_queries, 123 | (self._num_queries == 1) and 'query' or 'queries', 124 | self._sql_time 125 | ) 126 | 127 | def title(self): 128 | count = len(self._databases) 129 | 130 | return __('SQL Queries from %(count)d connection', 'SQL Queries from %(count)d connections', count) % dict( 131 | count=count, 132 | ) 133 | 134 | def url(self): 135 | return '' 136 | 137 | def content(self): 138 | if self._queries: 139 | width_ratio_tally = 0 140 | colors = [ 141 | (256, 0, 0), # red 142 | (0, 256, 0), # blue 143 | (0, 0, 256), # green 144 | ] 145 | factor = int(256.0/(len(self._databases)*2.5)) 146 | for n, db in enumerate(self._databases.itervalues()): 147 | rgb = [0, 0, 0] 148 | color = n % 3 149 | rgb[color] = 256 - n/3*factor 150 | nn = color 151 | # XXX: pretty sure this is horrible after so many aliases 152 | while rgb[color] < factor: 153 | nc = min(256 - rgb[color], 256) 154 | rgb[color] += nc 155 | nn += 1 156 | if nn > 2: 157 | nn = 0 158 | rgb[nn] = nc 159 | db['rgb_color'] = rgb 160 | 161 | trans_ids = {} 162 | trans_id = None 163 | i = 0 164 | for alias, query in self._queries: 165 | trans_id = query.get('trans_id') 166 | last_trans_id = trans_ids.get(alias) 167 | 168 | if trans_id != last_trans_id: 169 | if last_trans_id: 170 | self._queries[i-1][1]['ends_trans'] = True 171 | trans_ids[alias] = trans_id 172 | if trans_id: 173 | query['starts_trans'] = True 174 | if trans_id: 175 | query['in_trans'] = True 176 | 177 | query['alias'] = alias 178 | if 'iso_level' in query: 179 | query['iso_level'] = get_isolation_level_display(query['engine'], query['iso_level']) 180 | if 'trans_status' in query: 181 | query['trans_status'] = get_transaction_status_display(query['engine'], query['trans_status']) 182 | query['sql'] = reformat_sql(query['sql']) 183 | query['rgb_color'] = self._databases[alias]['rgb_color'] 184 | try: 185 | query['width_ratio'] = (query['duration'] / self._sql_time) * 100 186 | except ZeroDivisionError: 187 | query['width_ratio'] = 0 188 | query['start_offset'] = width_ratio_tally 189 | query['end_offset'] = query['width_ratio'] + query['start_offset'] 190 | width_ratio_tally += query['width_ratio'] 191 | 192 | stacktrace = [] 193 | for frame in query['stacktrace']: 194 | params = map(escape, frame[0].rsplit('/', 1) + list(frame[1:])) 195 | stacktrace.append('{0}/{1} in {3}({2})\n {4}'.format(*params)) 196 | query['stacktrace'] = mark_safe('\n'.join(stacktrace)) 197 | i += 1 198 | 199 | if trans_id: 200 | self._queries[i-1][1]['ends_trans'] = True 201 | 202 | context = self.context.copy() 203 | context.update({ 204 | 'databases': sorted(self._databases.items(), key=lambda x: -x[1]['time_spent']), 205 | 'queries': [q for a, q in self._queries], 206 | 'sql_time': self._sql_time, 207 | }) 208 | 209 | return render_to_string('debug_toolbar/panels/sql.html', context) 210 | 211 | class BoldKeywordFilter(sqlparse.filters.Filter): 212 | """sqlparse filter to bold SQL keywords""" 213 | def process(self, stack, stream): 214 | """Process the token stream""" 215 | for token_type, value in stream: 216 | is_keyword = token_type in sqlparse.tokens.Keyword 217 | if is_keyword: 218 | yield sqlparse.tokens.Text, '' 219 | yield token_type, escape(value) 220 | if is_keyword: 221 | yield sqlparse.tokens.Text, '' 222 | 223 | def swap_fields(sql): 224 | return re.sub('SELECT (.*) FROM', 'SELECT \g<1> FROM', sql) 225 | 226 | def reformat_sql(sql): 227 | stack = sqlparse.engine.FilterStack() 228 | stack.preprocess.append(BoldKeywordFilter()) # add our custom filter 229 | stack.postprocess.append(sqlparse.filters.SerializerUnicode()) # tokens -> strings 230 | return swap_fields(''.join(stack.run(sql))) 231 | -------------------------------------------------------------------------------- /debug_toolbar/panels/state.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from django.db import models 4 | from django.db.models.signals import post_save, post_delete 5 | from django.template.loader import render_to_string 6 | from django.utils.translation import ugettext_lazy as _ 7 | from django.utils.safestring import mark_safe 8 | 9 | from debug_toolbar.panels import DebugPanel 10 | 11 | 12 | class StateDebugPanel(DebugPanel): 13 | name = "State" 14 | has_content = True 15 | 16 | ADD = 1 17 | UPDATE = 2 18 | DELETE = 3 19 | 20 | objs_created = 0 21 | objs_deleted = 0 22 | objs_updated = 0 23 | 24 | objects_state = {} 25 | prev_objects_state = {} 26 | 27 | log_data = [] 28 | 29 | keys = {ADD: 'created', UPDATE: 'updated', DELETE: 'deleted'} 30 | 31 | def nav_title(self): 32 | return _("State") 33 | 34 | def nav_subtitle(self): 35 | return mark_safe(_("%(created)d created, "\ 36 | "%(updated)d changed, %(deleted)d deleted") % { 37 | 'created': self.objs_created, 38 | 'deleted': self.objs_deleted, 39 | 'updated': self.objs_updated, 40 | }) 41 | 42 | def title(self): 43 | return _("Objects State") 44 | 45 | def url(self): 46 | return '' 47 | 48 | def _track_save(cls, *args, **kwargs): 49 | """Method to track every post_save signal and increase amount of 50 | create/change action for corresponding object""" 51 | is_created = False 52 | action = cls.UPDATE 53 | if 'created' in kwargs and kwargs['created']: 54 | cls.objs_created += 1 55 | is_created = True 56 | action = cls.ADD 57 | else: 58 | cls.objs_updated += 1 59 | 60 | cls.log_data.append({ 61 | 'action': action, 62 | 'sender': kwargs['sender'], 63 | 'pk': kwargs['instance'].pk, 64 | 'is_created': is_created, 65 | }) 66 | track_save = classmethod(_track_save) 67 | 68 | def _track_delete(cls, *args, **kwargs): 69 | cls.objs_deleted += 1 70 | cls.log_data.append({ 71 | 'action': cls.DELETE, 72 | 'pk': kwargs['instance'].pk, 73 | 'sender': kwargs['sender'], 74 | }) 75 | track_delete = classmethod(_track_delete) 76 | 77 | def _connect(cls): 78 | post_save.connect(cls.track_save) 79 | post_delete.connect(cls.track_delete) 80 | cls.update_objects_state() 81 | connect = classmethod(_connect) 82 | 83 | def _update_objects_state(cls): 84 | for md in models.get_models(): 85 | model_name = cls.prepare_model_name(md) 86 | try: 87 | cls.objects_state[model_name] = md.objects.count() 88 | except Exception: 89 | pass 90 | update_objects_state = classmethod(_update_objects_state) 91 | 92 | def renew_state(self): 93 | cls = self.__class__ 94 | 95 | cls.prev_objects_state = cls.objects_state.copy() 96 | self.update_objects_state() 97 | 98 | cls.objs_created = 0 99 | cls.objs_updated = 0 100 | cls.objs_deleted = 0 101 | cls.log_data = [] 102 | 103 | def _prepare_model_name(cls, mdl): 104 | return re.sub(r'(\\']*)', '', str(mdl)).strip() 105 | prepare_model_name = classmethod(_prepare_model_name) 106 | 107 | def _statistic(self): 108 | cls = self.__class__ 109 | data = self.log_data 110 | stat = {} 111 | for item in data: 112 | sender = cls.prepare_model_name(item['sender']) 113 | action = item['action'] 114 | if not sender in stat: 115 | stat[sender] = dict((key, 0) for key in self.keys.values()) 116 | 117 | stat[sender][self.keys[action]] += 1 118 | 119 | return stat 120 | statistic = property(_statistic) 121 | 122 | def merge_states(self, stat, cur, prev): 123 | rv = [] 124 | keys = self.keys.values() 125 | for md, cur in cur.iteritems(): 126 | prev_amt = prev.get(md, -1) 127 | md_stat = stat.get(md, None) 128 | 129 | md_data = { 130 | 'prev': prev_amt, 131 | 'cur': cur, 132 | 'model': md, 133 | } 134 | 135 | if md_stat: 136 | [md_data.update({ 137 | 'have_%s' % key: True, 138 | '%s_amount' % key: md_stat[key], 139 | }) for key in keys if md_stat[key] > 0] 140 | 141 | rv.append(md_data) 142 | 143 | # sort by C/U/D 144 | [rv.sort(reverse=True, key=lambda obj: obj.get(key, 0)) \ 145 | for key in ["%s_amount" % c_key for c_key in keys]] 146 | 147 | return rv 148 | 149 | def content(self): 150 | context = self.context.copy() 151 | statistic = self.statistic.copy() 152 | context.update({ 153 | 'objs_created': self.objs_created, 154 | 'objs_updated': self.objs_updated, 155 | 'objs_deleted': self.objs_deleted, 156 | 'stat': statistic, 157 | 'objects_state': self.merge_states(statistic, self.objects_state, \ 158 | self.prev_objects_state), 159 | }) 160 | 161 | # we should do it because we save state to 162 | # class, not to particular object instance 163 | self.renew_state() 164 | 165 | return render_to_string('debug_toolbar/panels/state.html', context) 166 | 167 | # initialize tracking signals 168 | StateDebugPanel.connect() 169 | -------------------------------------------------------------------------------- /debug_toolbar/panels/template.py: -------------------------------------------------------------------------------- 1 | from os.path import normpath 2 | from pprint import pformat 3 | 4 | from django import http 5 | from django.conf import settings 6 | from django.template.context import get_standard_processors 7 | from django.template.loader import render_to_string 8 | from django.test.signals import template_rendered 9 | from django.utils.translation import ugettext_lazy as _ 10 | from debug_toolbar.panels import DebugPanel 11 | 12 | # Code taken and adapted from Simon Willison and Django Snippets: 13 | # http://www.djangosnippets.org/snippets/766/ 14 | 15 | # Monkeypatch instrumented test renderer from django.test.utils - we could use 16 | # django.test.utils.setup_test_environment for this but that would also set up 17 | # e-mail interception, which we don't want 18 | from django.test.utils import instrumented_test_render 19 | from django.template import Template 20 | 21 | if not hasattr(Template, '_render'): # Django < 1.2 22 | if Template.render != instrumented_test_render: 23 | Template.original_render = Template.render 24 | Template.render = instrumented_test_render 25 | else: 26 | if Template._render != instrumented_test_render: 27 | Template.original_render = Template._render 28 | Template._render = instrumented_test_render 29 | 30 | # MONSTER monkey-patch 31 | old_template_init = Template.__init__ 32 | def new_template_init(self, template_string, origin=None, name=''): 33 | old_template_init(self, template_string, origin, name) 34 | self.origin = origin 35 | Template.__init__ = new_template_init 36 | 37 | class TemplateDebugPanel(DebugPanel): 38 | """ 39 | A panel that lists all templates used during processing of a response. 40 | """ 41 | name = 'Template' 42 | has_content = True 43 | 44 | def __init__(self, *args, **kwargs): 45 | super(self.__class__, self).__init__(*args, **kwargs) 46 | self.templates = [] 47 | template_rendered.connect(self._store_template_info) 48 | 49 | def _store_template_info(self, sender, **kwargs): 50 | self.templates.append(kwargs) 51 | 52 | def nav_title(self): 53 | return _('Templates') 54 | 55 | def title(self): 56 | num_templates = len([t for t in self.templates 57 | if not (t['template'].name and t['template'].name.startswith('debug_toolbar/'))]) 58 | return _('Templates (%(num_templates)s rendered)') % {'num_templates': num_templates} 59 | 60 | def url(self): 61 | return '' 62 | 63 | def process_request(self, request): 64 | self.request = request 65 | 66 | def content(self): 67 | context_processors = dict( 68 | [ 69 | ("%s.%s" % (k.__module__, k.__name__), 70 | pformat(k(self.request))) for k in get_standard_processors() 71 | ] 72 | ) 73 | template_context = [] 74 | for template_data in self.templates: 75 | info = {} 76 | # Clean up some info about templates 77 | template = template_data.get('template', None) 78 | # Skip templates that we are generating through the debug toolbar. 79 | if template.name and template.name.startswith('debug_toolbar/'): 80 | continue 81 | if template.origin and template.origin.name: 82 | template.origin_name = template.origin.name 83 | else: 84 | template.origin_name = 'No origin' 85 | info['template'] = template 86 | # Clean up context for better readability 87 | if getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}).get('SHOW_TEMPLATE_CONTEXT', True): 88 | context_data = template_data.get('context', None) 89 | 90 | context_list = [] 91 | for context_layer in context_data.dicts: 92 | if hasattr(context_layer, 'items'): 93 | for key, value in context_layer.items(): 94 | # Replace any request elements - they have a large 95 | # unicode representation and the request data is 96 | # already made available from the Request Vars panel. 97 | if isinstance(value, http.HttpRequest): 98 | context_layer[key] = '<>' 99 | # Replace the debugging sql_queries element. The SQL 100 | # data is already made available from the SQL panel. 101 | elif key == 'sql_queries' and isinstance(value, list): 102 | context_layer[key] = '<>' 103 | # Replace LANGUAGES, which is available in i18n context processor 104 | elif key == 'LANGUAGES' and isinstance(value, tuple): 105 | context_layer[key] = '<>' 106 | try: 107 | context_list.append(pformat(context_layer)) 108 | except UnicodeEncodeError: 109 | pass 110 | info['context'] = '\n'.join(context_list) 111 | template_context.append(info) 112 | 113 | context = self.context.copy() 114 | context.update({ 115 | 'templates': template_context, 116 | 'template_dirs': [normpath(x) for x in settings.TEMPLATE_DIRS], 117 | 'context_processors': context_processors, 118 | }) 119 | 120 | return render_to_string('debug_toolbar/panels/templates.html', context) 121 | -------------------------------------------------------------------------------- /debug_toolbar/panels/timer.py: -------------------------------------------------------------------------------- 1 | try: 2 | import resource 3 | except ImportError: 4 | pass # Will fail on Win32 systems 5 | import time 6 | from django.template.loader import render_to_string 7 | from django.utils.translation import ugettext_lazy as _ 8 | from debug_toolbar.panels import DebugPanel 9 | 10 | class TimerDebugPanel(DebugPanel): 11 | """ 12 | Panel that displays the time a response took in milliseconds. 13 | """ 14 | name = 'Timer' 15 | try: # if resource module not available, don't show content panel 16 | resource 17 | except NameError: 18 | has_content = False 19 | has_resource = False 20 | else: 21 | has_content = True 22 | has_resource = True 23 | 24 | def process_request(self, request): 25 | self._start_time = time.time() 26 | if self.has_resource: 27 | self._start_rusage = resource.getrusage(resource.RUSAGE_SELF) 28 | 29 | def process_response(self, request, response): 30 | self.total_time = (time.time() - self._start_time) * 1000 31 | if self.has_resource: 32 | self._end_rusage = resource.getrusage(resource.RUSAGE_SELF) 33 | 34 | def nav_title(self): 35 | return _('Time') 36 | 37 | def nav_subtitle(self): 38 | # TODO l10n 39 | if self.has_resource: 40 | utime = self._end_rusage.ru_utime - self._start_rusage.ru_utime 41 | stime = self._end_rusage.ru_stime - self._start_rusage.ru_stime 42 | return 'CPU: %0.2fms (%0.2fms)' % ((utime + stime) * 1000.0, self.total_time) 43 | else: 44 | return 'TOTAL: %0.2fms' % (self.total_time) 45 | 46 | def title(self): 47 | return _('Resource Usage') 48 | 49 | def url(self): 50 | return '' 51 | 52 | def _elapsed_ru(self, name): 53 | return getattr(self._end_rusage, name) - getattr(self._start_rusage, name) 54 | 55 | def content(self): 56 | 57 | utime = 1000 * self._elapsed_ru('ru_utime') 58 | stime = 1000 * self._elapsed_ru('ru_stime') 59 | vcsw = self._elapsed_ru('ru_nvcsw') 60 | ivcsw = self._elapsed_ru('ru_nivcsw') 61 | minflt = self._elapsed_ru('ru_minflt') 62 | majflt = self._elapsed_ru('ru_majflt') 63 | 64 | # these are documented as not meaningful under Linux. If you're running BSD 65 | # feel free to enable them, and add any others that I hadn't gotten to before 66 | # I noticed that I was getting nothing but zeroes and that the docs agreed. :-( 67 | # 68 | # blkin = self._elapsed_ru('ru_inblock') 69 | # blkout = self._elapsed_ru('ru_oublock') 70 | # swap = self._elapsed_ru('ru_nswap') 71 | # rss = self._end_rusage.ru_maxrss 72 | # srss = self._end_rusage.ru_ixrss 73 | # urss = self._end_rusage.ru_idrss 74 | # usrss = self._end_rusage.ru_isrss 75 | 76 | # TODO l10n on values 77 | rows = ( 78 | (_('User CPU time'), '%0.3f msec' % utime), 79 | (_('System CPU time'), '%0.3f msec' % stime), 80 | (_('Total CPU time'), '%0.3f msec' % (utime + stime)), 81 | (_('Elapsed time'), '%0.3f msec' % self.total_time), 82 | (_('Context switches'), '%d voluntary, %d involuntary' % (vcsw, ivcsw)), 83 | # ('Memory use', '%d max RSS, %d shared, %d unshared' % (rss, srss, urss + usrss)), 84 | # ('Page faults', '%d no i/o, %d requiring i/o' % (minflt, majflt)), 85 | # ('Disk operations', '%d in, %d out, %d swapout' % (blkin, blkout, swap)), 86 | ) 87 | 88 | context = self.context.copy() 89 | context.update({ 90 | 'rows': rows, 91 | }) 92 | 93 | return render_to_string('debug_toolbar/panels/timer.html', context) 94 | -------------------------------------------------------------------------------- /debug_toolbar/panels/version.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import django 4 | from django.conf import settings 5 | from django.template.loader import render_to_string 6 | from django.utils.translation import ugettext_lazy as _ 7 | 8 | import debug_toolbar 9 | from debug_toolbar.panels import DebugPanel 10 | 11 | 12 | class VersionDebugPanel(DebugPanel): 13 | """ 14 | Panel that displays the Django version. 15 | """ 16 | name = 'Version' 17 | has_content = True 18 | 19 | def nav_title(self): 20 | return _('Versions') 21 | 22 | def nav_subtitle(self): 23 | return 'Django %s' % django.get_version() 24 | 25 | def url(self): 26 | return '' 27 | 28 | def title(self): 29 | return _('Versions') 30 | 31 | def content(self): 32 | versions = {} 33 | versions['Python'] = '%d.%d.%d' % sys.version_info[:3] 34 | for app in settings.INSTALLED_APPS + ['django']: 35 | name = app.split('.')[-1].replace('_', ' ').capitalize() 36 | __import__(app) 37 | app = sys.modules[app] 38 | if hasattr(app, 'get_version'): 39 | get_version = app.get_version 40 | if callable(get_version): 41 | version = get_version() 42 | else: 43 | version = get_version 44 | elif hasattr(app, 'VERSION'): 45 | version = app.VERSION 46 | elif hasattr(app, '__version__'): 47 | version = app.__version__ 48 | else: 49 | continue 50 | if isinstance(version, (list, tuple)): 51 | version = '.'.join(str(o) for o in version) 52 | versions[name] = version 53 | 54 | context = self.context.copy() 55 | context.update({ 56 | 'versions': versions, 57 | 'paths': sys.path, 58 | }) 59 | 60 | return render_to_string('debug_toolbar/panels/versions.html', context) 61 | -------------------------------------------------------------------------------- /debug_toolbar/runtests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | from os.path import dirname, abspath 4 | 5 | from django.conf import settings 6 | 7 | if not settings.configured: 8 | settings.configure( 9 | DATABASE_ENGINE='sqlite3', 10 | # HACK: this fixes our threaded runserver remote tests 11 | # DATABASE_NAME='test_sentry', 12 | # TEST_DATABASE_NAME='test_sentry', 13 | INSTALLED_APPS=[ 14 | 'django.contrib.auth', 15 | 'django.contrib.admin', 16 | 'django.contrib.contenttypes', 17 | 'django.contrib.sessions', 18 | 'django.contrib.sites', 19 | 20 | 'debug_toolbar', 21 | 22 | 'debug_toolbar.tests', 23 | ], 24 | ROOT_URLCONF='', 25 | DEBUG=False, 26 | SITE_ID=1, 27 | ) 28 | import djcelery 29 | djcelery.setup_loader() 30 | 31 | from django.test.simple import run_tests 32 | 33 | def runtests(*test_args): 34 | if 'south' in settings.INSTALLED_APPS: 35 | from south.management.commands import patch_for_test_db_setup 36 | patch_for_test_db_setup() 37 | 38 | if not test_args: 39 | test_args = ['debug_toolbar'] 40 | parent = dirname(abspath(__file__)) 41 | sys.path.insert(0, parent) 42 | failures = run_tests(test_args, verbosity=1, interactive=True) 43 | sys.exit(failures) 44 | 45 | 46 | if __name__ == '__main__': 47 | runtests(*sys.argv[1:]) -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/base.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 6 | 7 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/cache.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
{% trans "Total Calls" %}{{ cache_calls }}{% trans "Total Time" %}{{ cache_time }}ms{% trans "Hits" %}{{ cache.hits }}{% trans "Misses" %}{{ cache.misses }}
gets{{ cache.gets }}sets{{ cache.sets }}deletes{{ cache.deletes }}get_many{{ cache.get_many }}
34 | {% if cache.calls %} 35 |

{% trans "Breakdown" %}

36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | {% for query in cache.calls %} 47 | 48 | 49 | 50 | 51 | 52 | 53 | {% endfor %} 54 | 55 |
{% trans "Time" %} (ms){% trans "Type" %}{% trans "Parameters" %}{% trans "Function" %}
{{ query.0|floatformat:"4" }}{{ query.1|escape }}{{ query.2|escape }}{{ query.3.2|escape }}: {{ query.3.3.0|escape }}
56 | {% endif %} 57 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/headers.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | {% for key, value in headers.iteritems %} 11 | 12 | 13 | 14 | 15 | {% endfor %} 16 | 17 |
{% trans "Key" %}{% trans "Value" %}
{{ key|escape }}{{ value|escape }}
18 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/htmlvalidator.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |

3 |
4 | {% trans "Current page have following errors" %}: 5 | 6 | 7 | 8 | 9 | 10 | {% for err in errors %} 11 | 12 | {{ err|safe }} 13 | 14 | {% endfor %} 15 |
PositionError or Warning
16 | 17 |

Content:

18 |
19 | {% for lineno, line in lines %} 20 |
21 | {{ lineno }} 22 |
{{ line }}
23 |
24 |
25 | {% endfor %} 26 |
27 | 28 |
29 |
30 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/logger.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% if records %} 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% for record in records %} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | {% endfor %} 23 | 24 |
{% trans "Level" %}{% trans "Time" %}{% trans "Channel" %}{% trans "Message" %}{% trans "Location" %}
{{ record.level }}{{ record.time|date:"h:i:s m/d/Y" }}{{ record.channel|default:"-" }}{{ record.message }}{{ record.file }}:{{ record.line }}
25 | {% else %} 26 |

{% trans "No messages logged" %}.

27 | {% endif %} 28 | 29 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/profiling.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {% for call in func_list %} 16 | 17 | 18 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | {% endfor %} 35 | 36 |
{% trans "Call" %}{% trans "TotTime" %}{% trans "Per" %}{% trans "CumTime" %}{% trans "Per" %}{% trans "Count" %}
19 |
20 | {% if call.has_subfuncs %} 21 | - 22 | {% else %} 23 | 24 | {% endif %} 25 | {{ call.func_std_string }} 26 |
27 |
{{ call.tottime|floatformat:3 }}{{ call.tottime_per_call|floatformat:3 }}{{ call.cumtime|floatformat:3 }}{{ call.cumtime_per_call|floatformat:3 }}{{ call.count }}
37 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/request_vars.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 |

{% trans 'View information' %}

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 25 | 26 | 27 |
{% trans 'View Function' %}{% trans 'args' %}{% trans 'kwargs' %}
{{ view_func }}{{ view_args|default:"None" }} 17 | {% if view_kwargs.items %} 18 | {% for k, v in view_kwargs.items %} 19 | {{ k }}={{ v }}{% if not forloop.last %}, {% endif %} 20 | {% endfor %} 21 | {% else %} 22 | None 23 | {% endif %} 24 |
28 | 29 |

{% trans 'COOKIES Variables' %}

30 | {% if cookies %} 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | {% for key, value in cookies %} 44 | 45 | 46 | 47 | 48 | {% endfor %} 49 | 50 |
{% trans "Variable" %}{% trans "Value" %}
{{ key|escape }}{{ value|escape }}
51 | {% else %} 52 |

{% trans "No COOKIE data" %}

53 | {% endif %} 54 | 55 |

{% trans 'SESSION Variables' %}

56 | {% if session %} 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | {% for key, value in session %} 70 | 71 | 72 | 73 | 74 | {% endfor %} 75 | 76 |
{% trans "Variable" %}{% trans "Value" %}
{{ key|escape }}{{ value|escape }}
77 | {% else %} 78 |

{% trans "No SESSION data" %}

79 | {% endif %} 80 | 81 |

{% trans 'GET Variables' %}

82 | {% if get %} 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | {% for key, value in get %} 92 | 93 | 94 | 95 | 96 | {% endfor %} 97 | 98 |
{% trans "Variable" %}{% trans "Value" %}
{{ key|escape }}{{ value|join:", "|escape }}
99 | {% else %} 100 |

{% trans "No GET data" %}

101 | {% endif %} 102 | 103 |

{% trans 'POST Variables' %}

104 | {% if post %} 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | {% for key, value in post %} 114 | 115 | 116 | 117 | 118 | {% endfor %} 119 | 120 |
{% trans "Variable" %}{% trans "Value" %}
{{ key|escape }}{{ value|join:", "|escape }}
121 | {% else %} 122 |

{% trans "No POST data" %}

123 | {% endif %} 124 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/settings_vars.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | {% for var in settings.items|dictsort:"0" %} 11 | 12 | 13 | 14 | 15 | {% endfor %} 16 | 17 |
{% trans "Setting" %}{% trans "Value" %}
{{ var.0 }}{{ var.1|pprint }}
18 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/signals.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | {% for name, signal, receivers in signals %} 12 | 13 | 14 | 15 | 16 | 17 | {% endfor %} 18 | 19 |
{% trans "Signal" %}{% trans 'Providing Args' %}{% trans 'Receivers' %}
{{ name|escape }}{{ signal.providing_args|join:", " }}{{ receivers|join:", " }}
20 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/sql.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
3 |
    4 | {% for alias, info in databases %} 5 |
  • 6 |   {{ alias }} 7 | {{ info.time_spent|floatformat:"2" }} ms ({% blocktrans count info.num_queries as num %}{{ num }} query{% plural %}{{ num }} queries{% endblocktrans %}) 8 |
  • 9 | {% endfor %} 10 |
11 |
12 | 13 | {% if queries %} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {% for query in queries %} 26 | 27 | 28 | 31 | 36 | 39 | 42 | 53 | 54 | 55 | 56 | 81 | 82 | {% endfor %} 83 | 84 |
 {% trans 'Query' %}{% trans 'Timeline' %}{% trans 'Time (ms)' %}{% trans "Action" %}
  29 | + 30 | 32 |
33 |
{{ query.sql|safe }}
34 |
35 |
37 |
{{ query.width_ratio }}%
38 |
40 | {{ query.duration|floatformat:"2" }} 41 | 43 | {% if query.params %} 44 | {% if query.is_select %} 45 | Sel 46 | Expl 47 | {% ifequal query.engine 'mysql' %} 48 | Prof 49 | {% endifequal %} 50 | {% endif %} 51 | {% endif %} 52 |
57 |
58 |

Connection: {{ query.alias }}

59 | {% if query.iso_level %} 60 |

Isolation Level: {{ query.iso_level }}

61 | {% endif %} 62 | {% if query.trans_status %} 63 |

Transaction Status: {{ query.trans_status }}

64 | {% endif %} 65 | {% if query.stacktrace %} 66 |
{{ query.stacktrace }}
67 | {% endif %} 68 | {% if query.template_info %} 69 | 70 | {% for line in query.template_info.context %} 71 | 72 | 73 | 74 | 75 | {% endfor %} 76 |
{{ line.num }}{{ line.content }}
77 |

{{ query.template_info.name|default:"(unknown)" }}

78 | {% endif %} 79 |
80 |
85 | {% else %} 86 |

No SQL queries were recorded during this request.

87 | {% endif %} 88 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/sql_explain.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
3 | {% trans "Back" %} 4 |

{% trans "SQL Explained" %}

5 |
6 |
7 |
8 |
9 |
{% trans "Executed SQL" %}
10 |
{{ sql|safe }}
11 |
{% trans "Time" %}
12 |
{{ duration }} ms
13 |
{% trans "Database" %}
14 |
{{ alias }}
15 |
16 | 17 | 18 | 19 | {% for h in headers %} 20 | 21 | {% endfor %} 22 | 23 | 24 | 25 | {% for row in result %} 26 | 27 | {% for column in row %} 28 | 29 | {% endfor %} 30 | 31 | {% endfor %} 32 | 33 |
{{ h|upper }}
{{ column|escape }}
34 |
35 |
36 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/sql_profile.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
3 | {% trans "Back" %} 4 |

{% trans "SQL Profiled" %}

5 |
6 |
7 |
8 | {% if result %} 9 |
10 |
{% trans "Executed SQL" %}
11 |
{{ sql|safe }}
12 |
{% trans "Time" %}
13 |
{{ duration }} ms
14 |
{% trans "Database" %}
15 |
{{ alias }}
16 |
17 | 18 | 19 | 20 | {% for h in headers %} 21 | 22 | {% endfor %} 23 | 24 | 25 | 26 | {% for row in result %} 27 | 28 | {% for column in row %} 29 | 30 | {% endfor %} 31 | 32 | {% endfor %} 33 | 34 |
{{ h|upper }}
{{ column|escape }}
35 | {% else %} 36 |
37 |
{% trans 'Error' %}
38 |
{{ result_error }}
39 |
40 | {% endif %} 41 |
42 |
43 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/sql_select.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
3 | {% trans "Back" %} 4 |

{% trans "SQL Selected" %}

5 |
6 |
7 |
8 |
9 |
{% trans "Executed SQL" %}
10 |
{{ sql|safe }}
11 |
{% trans "Time" %}
12 |
{{ duration }} ms
13 |
{% trans "Database" %}
14 |
{{ alias }}
15 |
16 | {% if result %} 17 | 18 | 19 | 20 | {% for h in headers %} 21 | 22 | {% endfor %} 23 | 24 | 25 | 26 | {% for row in result %} 27 | 28 | {% for column in row %} 29 | 30 | {% endfor %} 31 | 32 | {% endfor %} 33 | 34 |
{{ h|upper }}
{{ column|escape }}
35 | {% else %} 36 |

{% trans "Empty set" %}

37 | {% endif %} 38 |
39 |
40 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/state.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
3 | {% trans "Summary" %}: 4 |
5 |
{% trans "Created" %}:
6 |
{{ objs_created }}
7 |
{% trans "Updated" %}:
8 |
{{ objs_updated }}
9 |
{% trans "Deleted" %}:
10 |
{{ objs_deleted }}
11 |
12 |
13 |
14 | 15 | {% ifequal stat|length 0 %} 16 |

{% trans "No objects was created, updated or deleted" %}

17 | {% else %} 18 |

{% trans "Objects manipulations statistic" %}

19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {% for sender, s in stat.iteritems %} 30 | 31 | 32 | 33 | 34 | 35 | 36 | {% endfor %} 37 | 38 |
{% trans "Model" %}{% trans 'Created' %}{% trans 'Changed' %}{% trans 'Deleted' %}
{{ sender }}{{ s.created }}{{ s.updated }}{{ s.deleted }}
39 | {% endifequal %} 40 | 41 |

{% trans "Objects state" %}

42 |

43 | {% trans "C" %} — {% trans "Created" %} 44 |     45 | {% trans "U" %} — {% trans "Updated" %} 46 |     47 | {% trans "D" %} — {% trans "Deleted" %} 48 |

49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | {% for item in objects_state %} 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | {% endfor %} 71 | 72 |
{% trans "C" %}{% trans "U" %}{% trans "D" %}{% trans "Model" %}{% trans 'Objects amount' %}{% trans 'Previous objects amount' %}
{{ item.created_amount }}{{ item.updated_amount }}{{ item.deleted_amount }}{{ item.model }}{{ item.cur }}{{ item.prev }}
73 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/template_source.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
3 | {% trans "Back" %} 4 |

{% trans 'Template Source' %}: {{ template_name }}

5 |
6 |
7 |
8 | {% if not source.pygmentized %} 9 | {{ source }} 10 | {% else %} 11 | {{ source }} 12 | {% endif %} 13 |
14 |
15 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/templates.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |

{% trans 'Template path' %}{{ template_dirs|length|pluralize }}

3 | {% if template_dirs %} 4 |
    5 | {% for template in template_dirs %} 6 |
  1. {{ template }}
  2. 7 | {% endfor %} 8 |
9 | {% else %} 10 |

None

11 | {% endif %} 12 | 13 |

{% trans "Template" %}{{ templates|length|pluralize }}

14 | {% if templates %} 15 |
16 | {% for template in templates %} 17 |
{{ template.template.name|addslashes }}
18 |
{{ template.template.origin_name|addslashes }}
19 | {% if template.context %} 20 |
21 | 22 | 23 |
24 | {% endif %} 25 | {% endfor %} 26 |
27 | {% else %} 28 |

{% trans 'None' %}

29 | {% endif %} 30 | 31 |

{% trans 'Context processor' %}{{ context_processors|length|pluralize }}

32 | {% if context_processors %} 33 |
34 | {% for key, value in context_processors.iteritems %} 35 |
{{ key|escape }}
36 |
37 | 38 | 39 |
40 | {% endfor %} 41 |
42 | {% else %} 43 |

{% trans 'None' %}

44 | {% endif %} 45 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/timer.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% for key, value in rows %} 15 | 16 | 17 | 18 | 19 | {% endfor %} 20 | 21 |
{% trans "Resource" %}{% trans "Value" %}
{{ key|escape }}{{ value|escape }}
22 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/panels/versions.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | {% for package, version in versions.iteritems %} 12 | 13 | 14 | 15 | 16 | {% endfor %} 17 | 18 |
{% trans "Package" %}{% trans "Version" %}
{{ package }}{{ version }}
19 | -------------------------------------------------------------------------------- /debug_toolbar/templates/debug_toolbar/redirect.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | 5 | 6 |

HttpResponseRedirect

7 |

{% trans 'Location' %}: {{ redirect_to }}

8 |

9 | {% trans "The Django Debug Toolbar has intercepted a redirect to the above URL for debug viewing purposes. You can click the above link to continue with the redirect as normal. If you'd like to disable this feature, set the DEBUG_TOOLBAR_CONFIG dictionary's key INTERCEPT_REDIRECTS to False." %} 10 |

11 | 12 | 13 | -------------------------------------------------------------------------------- /debug_toolbar/tests/__init__.py: -------------------------------------------------------------------------------- 1 | from tests import * -------------------------------------------------------------------------------- /debug_toolbar/tests/templates/404.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/tests/templates/404.html -------------------------------------------------------------------------------- /debug_toolbar/tests/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | URLpatterns for the debug toolbar. 3 | 4 | These should not be loaded explicitly; the debug toolbar middleware will patch 5 | this into the urlconf for the request. 6 | """ 7 | from django.conf.urls.defaults import * 8 | from django.contrib import admin 9 | 10 | admin.autodiscover() 11 | 12 | urlpatterns = patterns('', 13 | url(r'^execute_sql/$', 'debug_toolbar.tests.views.execute_sql'), 14 | ) 15 | -------------------------------------------------------------------------------- /debug_toolbar/tests/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.http import HttpResponse 3 | 4 | def execute_sql(request): 5 | list(User.objects.all()) 6 | 7 | return HttpResponse() -------------------------------------------------------------------------------- /debug_toolbar/toolbar/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/toolbar/__init__.py -------------------------------------------------------------------------------- /debug_toolbar/toolbar/loader.py: -------------------------------------------------------------------------------- 1 | """ 2 | The main DebugToolbar class that loads and renders the Toolbar. 3 | """ 4 | import os.path, os 5 | 6 | from django.conf import settings 7 | from django.template.loader import render_to_string 8 | from django.utils.datastructures import SortedDict 9 | from django.utils.safestring import mark_safe 10 | 11 | class DebugToolbar(object): 12 | 13 | def __init__(self, request): 14 | self.request = request 15 | self._panels = SortedDict() 16 | base_url = self.request.META.get('SCRIPT_NAME', '') 17 | self.config = { 18 | 'INTERCEPT_REDIRECTS': True, 19 | 'MEDIA_URL': u'%s/__debug__/m/' % base_url, 20 | 'DEBUG_TOOLBAR_DEV': False, 21 | } 22 | # Check if settings has a DEBUG_TOOLBAR_CONFIG and updated config 23 | self.config.update(getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {})) 24 | self.template_context = { 25 | 'BASE_URL': base_url, # for backwards compatibility 26 | 'DEBUG_TOOLBAR_MEDIA_URL': self.config.get('MEDIA_URL'), 27 | 'DEBUG_TOOLBAR_DEV': self.config.get('DEBUG_TOOLBAR_DEV', False), 28 | } 29 | # Override this tuple by copying to settings.py as `DEBUG_TOOLBAR_PANELS` 30 | self.default_panels = ( 31 | 'debug_toolbar.panels.version.VersionDebugPanel', 32 | 'debug_toolbar.panels.timer.TimerDebugPanel', 33 | 'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel', 34 | 'debug_toolbar.panels.headers.HeaderDebugPanel', 35 | 'debug_toolbar.panels.request_vars.RequestVarsDebugPanel', 36 | 'debug_toolbar.panels.sql.SQLDebugPanel', 37 | 'debug_toolbar.panels.template.TemplateDebugPanel', 38 | #'debug_toolbar.panels.cache.CacheDebugPanel', 39 | 'debug_toolbar.panels.signals.SignalDebugPanel', 40 | 'debug_toolbar.panels.logger.LoggingPanel', 41 | 'debug_toolbar.panels.state.StateDebugPanel', 42 | 'debug_toolbar.panels.htmlvalidator.HTMLValidationDebugPanel', 43 | ) 44 | self.load_panels() 45 | 46 | def _get_panels(self): 47 | return self._panels.values() 48 | panels = property(_get_panels) 49 | 50 | def get_panel(self, cls): 51 | return self._panels[cls] 52 | 53 | def load_panels(self): 54 | """ 55 | Populate debug panels 56 | """ 57 | from django.conf import settings 58 | from django.core import exceptions 59 | 60 | # Check if settings has a DEBUG_TOOLBAR_PANELS, otherwise use default 61 | if hasattr(settings, 'DEBUG_TOOLBAR_PANELS'): 62 | self.default_panels = settings.DEBUG_TOOLBAR_PANELS 63 | 64 | for panel_path in self.default_panels: 65 | try: 66 | dot = panel_path.rindex('.') 67 | except ValueError: 68 | raise exceptions.ImproperlyConfigured, '%s isn\'t a debug panel module' % panel_path 69 | panel_module, panel_classname = panel_path[:dot], panel_path[dot+1:] 70 | try: 71 | mod = __import__(panel_module, {}, {}, ['']) 72 | except ImportError, e: 73 | raise exceptions.ImproperlyConfigured, 'Error importing debug panel %s: "%s"' % (panel_module, e) 74 | try: 75 | panel_class = getattr(mod, panel_classname) 76 | except AttributeError: 77 | raise exceptions.ImproperlyConfigured, 'Toolbar Panel module "%s" does not define a "%s" class' % (panel_module, panel_classname) 78 | 79 | try: 80 | panel_instance = panel_class(context=self.template_context) 81 | except: 82 | raise # Bubble up problem loading panel 83 | 84 | self._panels[panel_class] = panel_instance 85 | 86 | def render_toolbar(self): 87 | """ 88 | Renders the overall Toolbar with panels inside. 89 | """ 90 | media_path = os.path.join(os.path.dirname(__file__), os.pardir, 'media', 'debug_toolbar') 91 | 92 | context = self.template_context.copy() 93 | load_media = lambda file: mark_safe(open(os.path.join(media_path, file), 'r').read()) 94 | 95 | context.update({ 96 | 'panels': self.panels, 97 | }) 98 | if not getattr(settings, 'DEBUG_TOOLBAR_DEV_MODE', False): 99 | context.update({ 100 | 'js': load_media('js/toolbar.min.js'), 101 | 'css': load_media('css/toolbar.min.css'), 102 | }) 103 | else: 104 | context.update({ 105 | 'js': mark_safe("\n\n".join([load_media('js/jquery.js'), 106 | load_media('js/toolbar.js')])), 107 | 'css': load_media('css/toolbar.css'), 108 | }) 109 | 110 | return render_to_string('debug_toolbar/base.html', context) 111 | -------------------------------------------------------------------------------- /debug_toolbar/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | URLpatterns for the debug toolbar. 3 | 4 | These should not be loaded explicitly; the debug toolbar middleware will patch 5 | this into the urlconf for the request. 6 | """ 7 | from django.conf.urls.defaults import * 8 | from django.conf import settings 9 | 10 | _PREFIX = '__debug__' 11 | 12 | urlpatterns = patterns('', 13 | url(r'^%s/m/(.*)$' % _PREFIX, 'debug_toolbar.views.debug_media'), 14 | url(r'^%s/sql_select/$' % _PREFIX, 'debug_toolbar.views.sql_select', name='sql_select'), 15 | url(r'^%s/sql_explain/$' % _PREFIX, 'debug_toolbar.views.sql_explain', name='sql_explain'), 16 | url(r'^%s/sql_profile/$' % _PREFIX, 'debug_toolbar.views.sql_profile', name='sql_profile'), 17 | url(r'^%s/template_source/$' % _PREFIX, 'debug_toolbar.views.template_source', name='template_source'), 18 | ) 19 | -------------------------------------------------------------------------------- /debug_toolbar/utils/__init__.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import django 3 | import SocketServer 4 | 5 | from django.conf import settings 6 | from django.views.debug import linebreak_iter 7 | 8 | # Figure out some paths 9 | django_path = os.path.realpath(os.path.dirname(django.__file__)) 10 | socketserver_path = os.path.realpath(os.path.dirname(SocketServer.__file__)) 11 | 12 | def ms_from_timedelta(td): 13 | """ 14 | Given a timedelta object, returns a float representing milliseconds 15 | """ 16 | return (td.seconds * 1000) + (td.microseconds / 1000.0) 17 | 18 | def tidy_stacktrace(stack): 19 | """ 20 | Clean up stacktrace and remove all entries that: 21 | 1. Are part of Django (except contrib apps) 22 | 2. Are part of SocketServer (used by Django's dev server) 23 | 3. Are the last entry (which is part of our stacktracing code) 24 | 25 | ``stack`` should be a list of frame tuples from ``inspect.stack()`` 26 | """ 27 | trace = [] 28 | for frame, path, line_no, func_name, text in (f[:5] for f in stack): 29 | s_path = os.path.realpath(path) 30 | # Support hiding of frames -- used in various utilities that provide 31 | # inspection. 32 | if '__traceback_hide__' in frame.f_locals: 33 | continue 34 | if getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}).get('HIDE_DJANGO_SQL', True) \ 35 | and django_path in s_path and not 'django/contrib' in s_path: 36 | continue 37 | if socketserver_path in s_path: 38 | continue 39 | if not text: 40 | text = '' 41 | else: 42 | text = (''.join(text)).strip() 43 | trace.append((path, line_no, func_name, text)) 44 | return trace 45 | 46 | def get_template_info(source, context_lines=3): 47 | line = 0 48 | upto = 0 49 | source_lines = [] 50 | before = during = after = "" 51 | 52 | origin, (start, end) = source 53 | template_source = origin.reload() 54 | 55 | for num, next in enumerate(linebreak_iter(template_source)): 56 | if start >= upto and end <= next: 57 | line = num 58 | before = template_source[upto:start] 59 | during = template_source[start:end] 60 | after = template_source[end:next] 61 | source_lines.append((num, template_source[upto:next])) 62 | upto = next 63 | 64 | top = max(1, line - context_lines) 65 | bottom = min(len(source_lines), line + 1 + context_lines) 66 | 67 | context = [] 68 | for num, content in source_lines[top:bottom]: 69 | context.append({ 70 | 'num': num, 71 | 'content': content, 72 | 'highlight': (num == line), 73 | }) 74 | 75 | return { 76 | 'name': origin.name, 77 | 'context': context, 78 | } -------------------------------------------------------------------------------- /debug_toolbar/utils/compat/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/debug_toolbar/utils/compat/__init__.py -------------------------------------------------------------------------------- /debug_toolbar/utils/compat/db.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | try: 3 | from django.db import connections 4 | dbconf = settings.DATABASES 5 | except ImportError: 6 | # Compat with < Django 1.2 7 | from django.db import connection 8 | connections = {'default': connection} 9 | dbconf = { 10 | 'default': { 11 | 'ENGINE': settings.DATABASE_ENGINE, 12 | } 13 | } -------------------------------------------------------------------------------- /debug_toolbar/utils/sqlparse/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2008 Andi Albrecht, albrecht.andi@gmail.com 2 | # 3 | # This module is part of python-sqlparse and is released under 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php. 5 | 6 | """Parse SQL statements.""" 7 | 8 | 9 | __version__ = '0.1.1' 10 | 11 | 12 | import os 13 | 14 | 15 | class SQLParseError(Exception): 16 | """Base class for exceptions in this module.""" 17 | 18 | 19 | # Setup namespace 20 | from debug_toolbar.utils.sqlparse import engine 21 | from debug_toolbar.utils.sqlparse import filters 22 | from debug_toolbar.utils.sqlparse import formatter 23 | 24 | 25 | def parse(sql): 26 | """Parse sql and return a list of statements. 27 | 28 | *sql* is a single string containting one or more SQL statements. 29 | 30 | Returns a tuple of :class:`~sqlparse.sql.Statement` instances. 31 | """ 32 | stack = engine.FilterStack() 33 | stack.full_analyze() 34 | return tuple(stack.run(sql)) 35 | 36 | 37 | def format(sql, **options): 38 | """Format *sql* according to *options*. 39 | 40 | Available options are documented in :ref:`formatting`. 41 | 42 | Returns the formatted SQL statement as string. 43 | """ 44 | stack = engine.FilterStack() 45 | options = formatter.validate_options(options) 46 | stack = formatter.build_filter_stack(stack, options) 47 | stack.postprocess.append(filters.SerializerUnicode()) 48 | return ''.join(stack.run(sql)) 49 | 50 | 51 | def split(sql): 52 | """Split *sql* into single statements. 53 | 54 | Returns a list of strings. 55 | """ 56 | stack = engine.FilterStack() 57 | stack.split_statements = True 58 | return [unicode(stmt) for stmt in stack.run(sql)] 59 | 60 | -------------------------------------------------------------------------------- /debug_toolbar/utils/sqlparse/engine/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2008 Andi Albrecht, albrecht.andi@gmail.com 2 | # 3 | # This module is part of python-sqlparse and is released under 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php. 5 | 6 | """filter""" 7 | 8 | import re 9 | 10 | from debug_toolbar.utils.sqlparse import lexer, SQLParseError 11 | from debug_toolbar.utils.sqlparse.engine import grouping 12 | from debug_toolbar.utils.sqlparse.engine.filter import StatementFilter 13 | 14 | # XXX remove this when cleanup is complete 15 | Filter = object 16 | 17 | 18 | class FilterStack(object): 19 | 20 | def __init__(self): 21 | self.preprocess = [] 22 | self.stmtprocess = [] 23 | self.postprocess = [] 24 | self.split_statements = False 25 | self._grouping = False 26 | 27 | def _flatten(self, stream): 28 | for token in stream: 29 | if token.is_group(): 30 | for t in self._flatten(token.tokens): 31 | yield t 32 | else: 33 | yield token 34 | 35 | def enable_grouping(self): 36 | self._grouping = True 37 | 38 | def full_analyze(self): 39 | self.enable_grouping() 40 | 41 | def run(self, sql): 42 | stream = lexer.tokenize(sql) 43 | # Process token stream 44 | if self.preprocess: 45 | for filter_ in self.preprocess: 46 | stream = filter_.process(self, stream) 47 | 48 | if (self.stmtprocess or self.postprocess or self.split_statements 49 | or self._grouping): 50 | splitter = StatementFilter() 51 | stream = splitter.process(self, stream) 52 | 53 | if self._grouping: 54 | def _group(stream): 55 | for stmt in stream: 56 | grouping.group(stmt) 57 | yield stmt 58 | stream = _group(stream) 59 | 60 | if self.stmtprocess: 61 | def _run(stream): 62 | ret = [] 63 | for stmt in stream: 64 | for filter_ in self.stmtprocess: 65 | filter_.process(self, stmt) 66 | ret.append(stmt) 67 | return ret 68 | stream = _run(stream) 69 | 70 | if self.postprocess: 71 | def _run(stream): 72 | for stmt in stream: 73 | stmt.tokens = list(self._flatten(stmt.tokens)) 74 | for filter_ in self.postprocess: 75 | stmt = filter_.process(self, stmt) 76 | yield stmt 77 | stream = _run(stream) 78 | 79 | return stream 80 | 81 | -------------------------------------------------------------------------------- /debug_toolbar/utils/sqlparse/engine/filter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from debug_toolbar.utils.sqlparse import tokens as T 4 | from debug_toolbar.utils.sqlparse.engine.grouping import Statement, Token 5 | 6 | 7 | class TokenFilter(object): 8 | 9 | def __init__(self, **options): 10 | self.options = options 11 | 12 | def process(self, stack, stream): 13 | """Process token stream.""" 14 | raise NotImplementedError 15 | 16 | 17 | class StatementFilter(TokenFilter): 18 | 19 | def __init__(self): 20 | TokenFilter.__init__(self) 21 | self._in_declare = False 22 | self._in_dbldollar = False 23 | self._is_create = False 24 | 25 | def _reset(self): 26 | self._in_declare = False 27 | self._in_dbldollar = False 28 | self._is_create = False 29 | 30 | def _change_splitlevel(self, ttype, value): 31 | # PostgreSQL 32 | if (ttype == T.Name.Builtin 33 | and value.startswith('$') and value.endswith('$')): 34 | if self._in_dbldollar: 35 | self._in_dbldollar = False 36 | return -1 37 | else: 38 | self._in_dbldollar = True 39 | return 1 40 | elif self._in_dbldollar: 41 | return 0 42 | 43 | # ANSI 44 | if ttype is not T.Keyword: 45 | return 0 46 | 47 | unified = value.upper() 48 | 49 | if unified == 'DECLARE': 50 | self._in_declare = True 51 | return 1 52 | 53 | if unified == 'BEGIN': 54 | if self._in_declare: 55 | return 0 56 | return 0 57 | 58 | if unified == 'END': 59 | # Should this respect a preceeding BEGIN? 60 | # In CASE ... WHEN ... END this results in a split level -1. 61 | return -1 62 | 63 | if ttype is T.Keyword.DDL and unified.startswith('CREATE'): 64 | self._is_create = True 65 | 66 | if unified in ('IF', 'FOR') and self._is_create: 67 | return 1 68 | 69 | # Default 70 | return 0 71 | 72 | def process(self, stack, stream): 73 | splitlevel = 0 74 | stmt = None 75 | consume_ws = False 76 | stmt_tokens = [] 77 | for ttype, value in stream: 78 | # Before appending the token 79 | if (consume_ws and ttype is not T.Whitespace 80 | and ttype is not T.Comment.Single): 81 | consume_ws = False 82 | stmt.tokens = stmt_tokens 83 | yield stmt 84 | self._reset() 85 | stmt = None 86 | splitlevel = 0 87 | if stmt is None: 88 | stmt = Statement() 89 | stmt_tokens = [] 90 | splitlevel += self._change_splitlevel(ttype, value) 91 | # Append the token 92 | stmt_tokens.append(Token(ttype, value)) 93 | # After appending the token 94 | if (splitlevel <= 0 and ttype is T.Punctuation 95 | and value == ';'): 96 | consume_ws = True 97 | if stmt is not None: 98 | stmt.tokens = stmt_tokens 99 | yield stmt 100 | -------------------------------------------------------------------------------- /debug_toolbar/utils/sqlparse/formatter.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2008 Andi Albrecht, albrecht.andi@gmail.com 2 | # 3 | # This module is part of python-sqlparse and is released under 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php. 5 | 6 | """SQL formatter""" 7 | 8 | from debug_toolbar.utils.sqlparse import SQLParseError 9 | from debug_toolbar.utils.sqlparse import filters 10 | 11 | 12 | def validate_options(options): 13 | """Validates options.""" 14 | kwcase = options.get('keyword_case', None) 15 | if kwcase not in [None, 'upper', 'lower', 'capitalize']: 16 | raise SQLParseError('Invalid value for keyword_case: %r' % kwcase) 17 | 18 | idcase = options.get('identifier_case', None) 19 | if idcase not in [None, 'upper', 'lower', 'capitalize']: 20 | raise SQLParseError('Invalid value for identifier_case: %r' % idcase) 21 | 22 | ofrmt = options.get('output_format', None) 23 | if ofrmt not in [None, 'sql', 'python', 'php']: 24 | raise SQLParseError('Unknown output format: %r' % ofrmt) 25 | 26 | strip_comments = options.get('strip_comments', False) 27 | if strip_comments not in [True, False]: 28 | raise SQLParseError('Invalid value for strip_comments: %r' 29 | % strip_comments) 30 | 31 | strip_ws = options.get('strip_whitespace', False) 32 | if strip_ws not in [True, False]: 33 | raise SQLParseError('Invalid value for strip_whitespace: %r' 34 | % strip_ws) 35 | 36 | reindent = options.get('reindent', False) 37 | if reindent not in [True, False]: 38 | raise SQLParseError('Invalid value for reindent: %r' 39 | % reindent) 40 | elif reindent: 41 | options['strip_whitespace'] = True 42 | indent_tabs = options.get('indent_tabs', False) 43 | if indent_tabs not in [True, False]: 44 | raise SQLParseError('Invalid value for indent_tabs: %r' % indent_tabs) 45 | elif indent_tabs: 46 | options['indent_char'] = '\t' 47 | else: 48 | options['indent_char'] = ' ' 49 | indent_width = options.get('indent_width', 2) 50 | try: 51 | indent_width = int(indent_width) 52 | except (TypeError, ValueError): 53 | raise SQLParseError('indent_width requires an integer') 54 | if indent_width < 1: 55 | raise SQLParseError('indent_width requires an positive integer') 56 | options['indent_width'] = indent_width 57 | 58 | right_margin = options.get('right_margin', None) 59 | if right_margin is not None: 60 | try: 61 | right_margin = int(right_margin) 62 | except (TypeError, ValueError): 63 | raise SQLParseError('right_margin requires an integer') 64 | if right_margin < 10: 65 | raise SQLParseError('right_margin requires an integer > 10') 66 | options['right_margin'] = right_margin 67 | 68 | return options 69 | 70 | 71 | def build_filter_stack(stack, options): 72 | """Setup and return a filter stack. 73 | 74 | Args: 75 | stack: :class:`~sqlparse.filters.FilterStack` instance 76 | options: Dictionary with options validated by validate_options. 77 | """ 78 | # Token filter 79 | if 'keyword_case' in options: 80 | stack.preprocess.append( 81 | filters.KeywordCaseFilter(options['keyword_case'])) 82 | 83 | if 'identifier_case' in options: 84 | stack.preprocess.append( 85 | filters.IdentifierCaseFilter(options['identifier_case'])) 86 | 87 | # After grouping 88 | if options.get('strip_comments', False): 89 | stack.enable_grouping() 90 | stack.stmtprocess.append(filters.StripCommentsFilter()) 91 | 92 | if (options.get('strip_whitespace', False) 93 | or options.get('reindent', False)): 94 | stack.enable_grouping() 95 | stack.stmtprocess.append(filters.StripWhitespaceFilter()) 96 | 97 | if options.get('reindent', False): 98 | stack.enable_grouping() 99 | stack.stmtprocess.append( 100 | filters.ReindentFilter(char=options['indent_char'], 101 | width=options['indent_width'])) 102 | 103 | if options.get('right_margin', False): 104 | stack.enable_grouping() 105 | stack.stmtprocess.append( 106 | filters.RightMarginFilter(width=options['right_margin'])) 107 | 108 | # Serializer 109 | if options.get('output_format'): 110 | frmt = options['output_format'] 111 | if frmt.lower() == 'php': 112 | fltr = filters.OutputPHPFilter() 113 | elif frmt.lower() == 'python': 114 | fltr = filters.OutputPythonFilter() 115 | else: 116 | fltr = None 117 | if fltr is not None: 118 | stack.postprocess.append(fltr) 119 | 120 | return stack 121 | 122 | 123 | -------------------------------------------------------------------------------- /debug_toolbar/utils/sqlparse/tokens.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2008 Andi Albrecht, albrecht.andi@gmail.com 2 | # 3 | # This module is part of python-sqlparse and is released under 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php. 5 | 6 | # The Token implementation is based on pygment's token system written 7 | # by Georg Brandl. 8 | # http://pygments.org/ 9 | 10 | """Tokens""" 11 | 12 | try: 13 | set 14 | except NameError: 15 | from sets import Set as set 16 | 17 | 18 | class _TokenType(tuple): 19 | parent = None 20 | 21 | def split(self): 22 | buf = [] 23 | node = self 24 | while node is not None: 25 | buf.append(node) 26 | node = node.parent 27 | buf.reverse() 28 | return buf 29 | 30 | def __init__(self, *args): 31 | # no need to call super.__init__ 32 | self.subtypes = set() 33 | 34 | def __contains__(self, val): 35 | return self is val or ( 36 | type(val) is self.__class__ and 37 | val[:len(self)] == self 38 | ) 39 | 40 | def __getattr__(self, val): 41 | if not val or not val[0].isupper(): 42 | return tuple.__getattribute__(self, val) 43 | new = _TokenType(self + (val,)) 44 | setattr(self, val, new) 45 | self.subtypes.add(new) 46 | new.parent = self 47 | return new 48 | 49 | def __hash__(self): 50 | return hash(tuple(self)) 51 | 52 | def __repr__(self): 53 | return 'Token' + (self and '.' or '') + '.'.join(self) 54 | 55 | 56 | Token = _TokenType() 57 | 58 | # Special token types 59 | Text = Token.Text 60 | Whitespace = Text.Whitespace 61 | Newline = Whitespace.Newline 62 | Error = Token.Error 63 | # Text that doesn't belong to this lexer (e.g. HTML in PHP) 64 | Other = Token.Other 65 | 66 | # Common token types for source code 67 | Keyword = Token.Keyword 68 | Name = Token.Name 69 | Literal = Token.Literal 70 | String = Literal.String 71 | Number = Literal.Number 72 | Punctuation = Token.Punctuation 73 | Operator = Token.Operator 74 | Wildcard = Token.Wildcard 75 | Comment = Token.Comment 76 | Assignment = Token.Assignement 77 | 78 | # Generic types for non-source code 79 | Generic = Token.Generic 80 | 81 | # String and some others are not direct childs of Token. 82 | # alias them: 83 | Token.Token = Token 84 | Token.String = String 85 | Token.Number = Number 86 | 87 | # SQL specific tokens 88 | DML = Keyword.DML 89 | DDL = Keyword.DDL 90 | Command = Keyword.Command 91 | 92 | Group = Token.Group 93 | Group.Parenthesis = Token.Group.Parenthesis 94 | Group.Comment = Token.Group.Comment 95 | Group.Where = Token.Group.Where 96 | 97 | 98 | def is_token_subtype(ttype, other): 99 | """ 100 | Return True if ``ttype`` is a subtype of ``other``. 101 | 102 | exists for backwards compatibility. use ``ttype in other`` now. 103 | """ 104 | return ttype in other 105 | 106 | 107 | def string_to_tokentype(s): 108 | """ 109 | Convert a string into a token type:: 110 | 111 | >>> string_to_token('String.Double') 112 | Token.Literal.String.Double 113 | >>> string_to_token('Token.Literal.Number') 114 | Token.Literal.Number 115 | >>> string_to_token('') 116 | Token 117 | 118 | Tokens that are already tokens are returned unchanged: 119 | 120 | >>> string_to_token(String) 121 | Token.Literal.String 122 | """ 123 | if isinstance(s, _TokenType): 124 | return s 125 | if not s: 126 | return Token 127 | node = Token 128 | for item in s.split('.'): 129 | node = getattr(node, item) 130 | return node 131 | 132 | -------------------------------------------------------------------------------- /debug_toolbar/utils/tracking/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import time 3 | import types 4 | 5 | def post_dispatch(func): 6 | def wrapped(callback): 7 | register_hook(func, 'after', callback) 8 | return callback 9 | return wrapped 10 | 11 | def pre_dispatch(func): 12 | def wrapped(callback): 13 | register_hook(func, 'before', callback) 14 | return callback 15 | return wrapped 16 | 17 | def replace_call(func): 18 | def inner(callback): 19 | def wrapped(*args, **kwargs): 20 | return callback(func, *args, **kwargs) 21 | 22 | actual = getattr(func, '__wrapped__', func) 23 | wrapped.__wrapped__ = actual 24 | wrapped.__doc__ = getattr(actual, '__doc__', None) 25 | wrapped.__name__ = actual.__name__ 26 | 27 | _replace_function(func, wrapped) 28 | return wrapped 29 | return inner 30 | 31 | def fire_hook(hook, sender, **kwargs): 32 | try: 33 | for callback in callbacks[hook].get(id(sender), []): 34 | callback(sender=sender, **kwargs) 35 | except Exception, e: 36 | # Log the exception, dont mess w/ the underlying function 37 | logging.exception(e) 38 | 39 | def _replace_function(func, wrapped): 40 | if isinstance(func, types.FunctionType): 41 | if func.__module__ == '__builtin__': 42 | # oh shit 43 | __builtins__[func] = wrapped 44 | else: 45 | module = __import__(func.__module__, {}, {}, [func.__module__], 0) 46 | setattr(module, func.__name__, wrapped) 47 | elif getattr(func, 'im_self', None): 48 | # TODO: classmethods 49 | raise NotImplementedError 50 | elif hasattr(func, 'im_class'): 51 | # for unbound methods 52 | setattr(func.im_class, func.__name__, wrapped) 53 | else: 54 | raise NotImplementedError 55 | 56 | callbacks = { 57 | 'before': {}, 58 | 'after': {}, 59 | } 60 | 61 | def register_hook(func, hook, callback): 62 | """ 63 | def myhook(sender, args, kwargs): 64 | print func, "executed 65 | print "args:", args 66 | print "kwargs:", kwargs 67 | register_hook(BaseDatabaseWrapper.cursor, 'before', myhook) 68 | """ 69 | 70 | assert hook in ('before', 'after') 71 | 72 | def wrapped(*args, **kwargs): 73 | start = time.time() 74 | fire_hook('before', sender=wrapped.__wrapped__, args=args, kwargs=kwargs, 75 | start=start) 76 | result = wrapped.__wrapped__(*args, **kwargs) 77 | stop = time.time() 78 | fire_hook('after', sender=wrapped.__wrapped__, args=args, kwargs=kwargs, 79 | result=result, start=start, stop=stop) 80 | actual = getattr(func, '__wrapped__', func) 81 | wrapped.__wrapped__ = actual 82 | wrapped.__doc__ = getattr(actual, '__doc__', None) 83 | wrapped.__name__ = actual.__name__ 84 | 85 | id_ = id(actual) 86 | if id_ not in callbacks[hook]: 87 | callbacks[hook][id_] = [] 88 | callbacks[hook][id_].append(callback) 89 | 90 | _replace_function(func, wrapped) -------------------------------------------------------------------------------- /debug_toolbar/utils/tracking/db.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import sys 3 | 4 | from datetime import datetime 5 | 6 | from django.conf import settings 7 | from django.template import Node 8 | from django.utils import simplejson 9 | from django.utils.encoding import force_unicode 10 | from django.utils.hashcompat import sha_constructor 11 | 12 | from debug_toolbar.utils import ms_from_timedelta, tidy_stacktrace, get_template_info 13 | from debug_toolbar.utils.compat.db import connections 14 | # TODO:This should be set in the toolbar loader as a default and panels should 15 | # get a copy of the toolbar object with access to its config dictionary 16 | SQL_WARNING_THRESHOLD = getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}) \ 17 | .get('SQL_WARNING_THRESHOLD', 500) 18 | 19 | class CursorWrapper(object): 20 | """ 21 | Wraps a cursor and logs queries. 22 | """ 23 | 24 | def __init__(self, cursor, db, logger): 25 | self.cursor = cursor 26 | # Instance of a BaseDatabaseWrapper subclass 27 | self.db = db 28 | # logger must implement a ``record`` method 29 | self.logger = logger 30 | 31 | def execute(self, sql, params=()): 32 | __traceback_hide__ = True 33 | start = datetime.now() 34 | try: 35 | return self.cursor.execute(sql, params) 36 | finally: 37 | stop = datetime.now() 38 | duration = ms_from_timedelta(stop - start) 39 | stacktrace = tidy_stacktrace(reversed(inspect.stack())) 40 | _params = '' 41 | try: 42 | _params = simplejson.dumps([force_unicode(x, strings_only=True) for x in params]) 43 | except TypeError: 44 | pass # object not JSON serializable 45 | 46 | template_info = None 47 | cur_frame = sys._getframe().f_back 48 | try: 49 | while cur_frame is not None: 50 | if cur_frame.f_code.co_name == 'render': 51 | node = cur_frame.f_locals['self'] 52 | if isinstance(node, Node): 53 | template_info = get_template_info(node.source) 54 | break 55 | cur_frame = cur_frame.f_back 56 | except: 57 | pass 58 | del cur_frame 59 | 60 | alias = getattr(self.db, 'alias', 'default') 61 | conn = connections[alias].connection 62 | # HACK: avoid imports 63 | if conn: 64 | engine = conn.__class__.__module__.split('.', 1)[0] 65 | else: 66 | engine = 'unknown' 67 | 68 | params = { 69 | 'engine': engine, 70 | 'alias': alias, 71 | 'sql': self.db.ops.last_executed_query(self.cursor, sql, params), 72 | 'duration': duration, 73 | 'raw_sql': sql, 74 | 'params': _params, 75 | 'hash': sha_constructor(settings.SECRET_KEY + sql + _params).hexdigest(), 76 | 'stacktrace': stacktrace, 77 | 'start_time': start, 78 | 'stop_time': stop, 79 | 'is_slow': (duration > SQL_WARNING_THRESHOLD), 80 | 'is_select': sql.lower().strip().startswith('select'), 81 | 'template_info': template_info, 82 | } 83 | 84 | if engine == 'psycopg2': 85 | params.update({ 86 | 'trans_id': self.logger.get_transaction_id(alias), 87 | 'trans_status': conn.get_transaction_status(), 88 | 'iso_level': conn.isolation_level, 89 | 'encoding': conn.encoding, 90 | }) 91 | 92 | 93 | # We keep `sql` to maintain backwards compatibility 94 | self.logger.record(**params) 95 | 96 | def executemany(self, sql, param_list): 97 | return self.cursor.executemany(sql, param_list) 98 | 99 | def __getattr__(self, attr): 100 | if attr in self.__dict__: 101 | return self.__dict__[attr] 102 | else: 103 | return getattr(self.cursor, attr) 104 | 105 | def __iter__(self): 106 | return iter(self.cursor) -------------------------------------------------------------------------------- /debug_toolbar/views.py: -------------------------------------------------------------------------------- 1 | """ 2 | Helper views for the debug toolbar. These are dynamically installed when the 3 | debug toolbar is displayed, and typically can do Bad Things, so hooking up these 4 | views in any other way is generally not advised. 5 | """ 6 | 7 | import os 8 | import django.views.static 9 | from django.conf import settings 10 | from django.http import HttpResponseBadRequest 11 | from django.shortcuts import render_to_response 12 | from django.utils import simplejson 13 | from django.utils.hashcompat import sha_constructor 14 | 15 | from debug_toolbar.utils.compat.db import connections 16 | 17 | class InvalidSQLError(Exception): 18 | def __init__(self, value): 19 | self.value = value 20 | def __str__(self): 21 | return repr(self.value) 22 | 23 | def debug_media(request, path): 24 | root = getattr(settings, 'DEBUG_TOOLBAR_MEDIA_ROOT', None) 25 | if root is None: 26 | parent = os.path.abspath(os.path.dirname(__file__)) 27 | root = os.path.join(parent, 'media', 'debug_toolbar') 28 | return django.views.static.serve(request, path, root) 29 | 30 | def sql_select(request): 31 | """ 32 | Returns the output of the SQL SELECT statement. 33 | 34 | Expected GET variables: 35 | sql: urlencoded sql with positional arguments 36 | params: JSON encoded parameter values 37 | duration: time for SQL to execute passed in from toolbar just for redisplay 38 | hash: the hash of (secret + sql + params) for tamper checking 39 | """ 40 | from debug_toolbar.panels.sql import reformat_sql 41 | sql = request.GET.get('sql', '') 42 | params = request.GET.get('params', '') 43 | alias = request.GET.get('alias', 'default') 44 | hash = sha_constructor(settings.SECRET_KEY + sql + params).hexdigest() 45 | if hash != request.GET.get('hash', ''): 46 | return HttpResponseBadRequest('Tamper alert') # SQL Tampering alert 47 | if sql.lower().strip().startswith('select'): 48 | params = simplejson.loads(params) 49 | cursor = connections[alias].cursor() 50 | cursor.execute(sql, params) 51 | headers = [d[0] for d in cursor.description] 52 | result = cursor.fetchall() 53 | cursor.close() 54 | context = { 55 | 'result': result, 56 | 'sql': reformat_sql(cursor.db.ops.last_executed_query(cursor, sql, params)), 57 | 'duration': request.GET.get('duration', 0.0), 58 | 'headers': headers, 59 | 'alias': alias, 60 | } 61 | return render_to_response('debug_toolbar/panels/sql_select.html', context) 62 | raise InvalidSQLError("Only 'select' queries are allowed.") 63 | 64 | def sql_explain(request): 65 | """ 66 | Returns the output of the SQL EXPLAIN on the given query. 67 | 68 | Expected GET variables: 69 | sql: urlencoded sql with positional arguments 70 | params: JSON encoded parameter values 71 | duration: time for SQL to execute passed in from toolbar just for redisplay 72 | hash: the hash of (secret + sql + params) for tamper checking 73 | """ 74 | from debug_toolbar.panels.sql import reformat_sql 75 | sql = request.GET.get('sql', '') 76 | params = request.GET.get('params', '') 77 | alias = request.GET.get('alias', 'default') 78 | hash = sha_constructor(settings.SECRET_KEY + sql + params).hexdigest() 79 | if hash != request.GET.get('hash', ''): 80 | return HttpResponseBadRequest('Tamper alert') # SQL Tampering alert 81 | if sql.lower().strip().startswith('select'): 82 | params = simplejson.loads(params) 83 | cursor = connections[alias].cursor() 84 | 85 | if settings.DATABASE_ENGINE == "sqlite3": 86 | # SQLite's EXPLAIN dumps the low-level opcodes generated for a query; 87 | # EXPLAIN QUERY PLAN dumps a more human-readable summary 88 | # See http://www.sqlite.org/lang_explain.html for details 89 | cursor.execute("EXPLAIN QUERY PLAN %s" % (sql,), params) 90 | else: 91 | cursor.execute("EXPLAIN %s" % (sql,), params) 92 | 93 | headers = [d[0] for d in cursor.description] 94 | result = cursor.fetchall() 95 | cursor.close() 96 | context = { 97 | 'result': result, 98 | 'sql': reformat_sql(cursor.db.ops.last_executed_query(cursor, sql, params)), 99 | 'duration': request.GET.get('duration', 0.0), 100 | 'headers': headers, 101 | 'alias': alias, 102 | } 103 | return render_to_response('debug_toolbar/panels/sql_explain.html', context) 104 | raise InvalidSQLError("Only 'select' queries are allowed.") 105 | 106 | def sql_profile(request): 107 | """ 108 | Returns the output of running the SQL and getting the profiling statistics. 109 | 110 | Expected GET variables: 111 | sql: urlencoded sql with positional arguments 112 | params: JSON encoded parameter values 113 | duration: time for SQL to execute passed in from toolbar just for redisplay 114 | hash: the hash of (secret + sql + params) for tamper checking 115 | """ 116 | from debug_toolbar.panels.sql import reformat_sql 117 | sql = request.GET.get('sql', '') 118 | params = request.GET.get('params', '') 119 | alias = request.GET.get('alias', 'default') 120 | hash = sha_constructor(settings.SECRET_KEY + sql + params).hexdigest() 121 | if hash != request.GET.get('hash', ''): 122 | return HttpResponseBadRequest('Tamper alert') # SQL Tampering alert 123 | if sql.lower().strip().startswith('select'): 124 | params = simplejson.loads(params) 125 | cursor = connections[alias].cursor() 126 | result = None 127 | headers = None 128 | result_error = None 129 | try: 130 | cursor.execute("SET PROFILING=1") # Enable profiling 131 | cursor.execute(sql, params) # Execute SELECT 132 | cursor.execute("SET PROFILING=0") # Disable profiling 133 | # The Query ID should always be 1 here but I'll subselect to get the last one just in case... 134 | cursor.execute("SELECT * FROM information_schema.profiling WHERE query_id=(SELECT query_id FROM information_schema.profiling ORDER BY query_id DESC LIMIT 1)") 135 | headers = [d[0] for d in cursor.description] 136 | result = cursor.fetchall() 137 | except: 138 | result_error = "Profiling is either not available or not supported by your database." 139 | cursor.close() 140 | context = { 141 | 'result': result, 142 | 'result_error': result_error, 143 | 'sql': reformat_sql(cursor.db.ops.last_executed_query(cursor, sql, params)), 144 | 'duration': request.GET.get('duration', 0.0), 145 | 'headers': headers, 146 | 'alias': alias, 147 | } 148 | return render_to_response('debug_toolbar/panels/sql_profile.html', context) 149 | raise InvalidSQLError("Only 'select' queries are allowed.") 150 | 151 | def template_source(request): 152 | """ 153 | Return the source of a template, syntax-highlighted by Pygments if 154 | it's available. 155 | """ 156 | from django.template import TemplateDoesNotExist 157 | from django.utils.safestring import mark_safe 158 | from django.conf import settings 159 | 160 | template_name = request.GET.get('template', None) 161 | if template_name is None: 162 | return HttpResponseBadRequest('"template" key is required') 163 | 164 | try: # Django 1.2 ... 165 | from django.template.loader import find_template_loader, make_origin 166 | loaders = [] 167 | for loader_name in settings.TEMPLATE_LOADERS: 168 | loader = find_template_loader(loader_name) 169 | if loader is not None: 170 | loaders.append(loader) 171 | for loader in loaders: 172 | try: 173 | source, display_name = loader.load_template_source(template_name) 174 | origin = make_origin(display_name, loader, template_name, settings.TEMPLATE_DIRS) 175 | break 176 | except TemplateDoesNotExist: 177 | source = "Template Does Not Exist: %s" % (template_name,) 178 | except (ImportError, AttributeError): # Django 1.1 ... 179 | from django.template.loader import find_template_source 180 | source, origin = find_template_source(template_name) 181 | 182 | try: 183 | from pygments import highlight 184 | from pygments.lexers import HtmlDjangoLexer 185 | from pygments.formatters import HtmlFormatter 186 | 187 | source = highlight(source, HtmlDjangoLexer(), HtmlFormatter()) 188 | source = mark_safe(source) 189 | source.pygmentized = True 190 | except ImportError: 191 | pass 192 | 193 | return render_to_response('debug_toolbar/panels/template_source.html', { 194 | 'source': source, 195 | 'template_name': template_name 196 | }) 197 | -------------------------------------------------------------------------------- /example/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/example/__init__.py -------------------------------------------------------------------------------- /example/example.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mklymyshyn/django-debug-toolbar/40aa4cf779c2448fd2ae0e24c91ce68ae36340f2/example/example.db -------------------------------------------------------------------------------- /example/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from django.core.management import execute_manager 3 | try: 4 | import settings # Assumed to be in the same directory. 5 | except ImportError: 6 | import sys 7 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) 8 | sys.exit(1) 9 | 10 | if __name__ == "__main__": 11 | execute_manager(settings) 12 | -------------------------------------------------------------------------------- /example/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Sample(models.Model): 5 | name = models.CharField(max_length=255) 6 | 7 | def __unicode__(self): 8 | return self.name 9 | -------------------------------------------------------------------------------- /example/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | PROJECT_PATH = os.path.realpath(os.path.dirname(__file__)) 5 | 6 | sys.path.append(os.path.join(PROJECT_PATH, '..')) 7 | 8 | ADMIN_MEDIA_PREFIX = '/admin_media/' 9 | DATABASE_ENGINE = 'sqlite3' 10 | DATABASE_NAME = 'example.db' 11 | DEBUG = True 12 | INSTALLED_APPS = ( 13 | 'django.contrib.auth', 14 | 'django.contrib.admin', 15 | 'django.contrib.contenttypes', 16 | 'django.contrib.sessions', 17 | 'django.contrib.sites', 18 | 'debug_toolbar', 19 | 'example', 20 | ) 21 | INTERNAL_IPS = ('127.0.0.1',) 22 | MEDIA_ROOT = os.path.join(PROJECT_PATH, 'media') 23 | MEDIA_URL = '/media' 24 | MIDDLEWARE_CLASSES = ( 25 | 'django.middleware.common.CommonMiddleware', 26 | 'django.contrib.sessions.middleware.SessionMiddleware', 27 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 28 | 'debug_toolbar.middleware.DebugToolbarMiddleware', 29 | ) 30 | ROOT_URLCONF = 'example.urls' 31 | SECRET_KEY = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcd' 32 | SITE_ID = 1 33 | TEMPLATE_CONTEXT_PROCESSORS = ( 34 | 'django.core.context_processors.auth', 35 | 'django.core.context_processors.media', 36 | 'django.core.context_processors.request', 37 | ) 38 | TEMPLATE_DEBUG = DEBUG 39 | TEMPLATE_DIRS = (os.path.join(PROJECT_PATH, 'templates')) 40 | 41 | DEBUG_TOOLBAR_DEV_MODE = False -------------------------------------------------------------------------------- /example/templates/admin/login.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n %} 3 | 4 | {% block extrastyle %}{% load adminmedia %}{{ block.super }}{% endblock %} 5 | 6 | {% block bodyclass %}login{% endblock %} 7 | 8 | {% block content_title %}{% endblock %} 9 | 10 | {% block breadcrumbs %}{% endblock %} 11 | 12 | {% block content %} 13 | {% if error_message %} 14 |

{{ error_message }}

15 | {% endif %} 16 |
17 |
18 |
19 | 20 |
21 |
22 | 23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 | 33 |
34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /example/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Index of Tests 5 | 6 | 7 | 8 |

Index of Tests

9 | 14 |

15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /example/templates/jquery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Old jQuery Test 5 | 9 | 10 | 16 | 17 | 18 |

jQuery Test

19 |

If you see this, jQuery is working.

20 | 21 | 22 | -------------------------------------------------------------------------------- /example/templates/mootools/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MooTools Test 5 | 8 | 9 | 14 | 15 | 16 |

MooTools Test

17 |

If you see this, MooTools is working.

18 | 19 | 20 | -------------------------------------------------------------------------------- /example/templates/prototype/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Prototype Test 5 | 8 | 9 | 14 | 15 | 16 |

Prototype Test

17 |

If you see this, Prototype is working.

18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /example/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls.defaults import * 3 | from django.contrib import admin 4 | from django.views.generic.simple import direct_to_template 5 | 6 | admin.autodiscover() 7 | 8 | urlpatterns = patterns('', 9 | (r'^$', 'example.views.update_object', {'template': 'index.html'}), 10 | (r'^jquery/index/$', direct_to_template, {'template': 'jquery/index.html'}), 11 | (r'^mootools/index/$', direct_to_template, {'template': 'mootools/index.html'}), 12 | (r'^prototype/index/$', direct_to_template, {'template': 'prototype/index.html'}), 13 | (r'^admin/', include(admin.site.urls)), 14 | ) 15 | 16 | if settings.DEBUG: 17 | urlpatterns += patterns('', 18 | (r'^media/(.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}) 19 | ) 20 | 21 | -------------------------------------------------------------------------------- /example/views.py: -------------------------------------------------------------------------------- 1 | from django.views.generic.simple import direct_to_template 2 | from django.contrib.auth.models import User 3 | 4 | from models import Sample 5 | 6 | 7 | def update_object(request, template=''): 8 | # create object 9 | obj = Sample.objects.create(name='test') 10 | obj = Sample.objects.all().order_by('?')[0] 11 | 12 | # update objec 13 | obj.name = 'test1' 14 | obj.save() 15 | 16 | # update objec 17 | obj.name = 'test2' 18 | obj.save() 19 | 20 | # delete object 21 | obj.delete() 22 | 23 | obj2 = Sample.objects.create(name='test2') 24 | 25 | user, created = User.objects.get_or_create(username='admin', defaults={ 26 | 'username': 'admin', 27 | 'email': 'test@test.com', 28 | 'first_name': 'admin', 29 | 'last_name': 'admin', 30 | }) 31 | user.last_name = 'test' 32 | user.save() 33 | return direct_to_template(request, template=template) 34 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [egg_info] 2 | tag_svn_revision = false 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='django-debug-toolbar', 5 | version='0.8.6-dev', 6 | description='A configurable set of panels that display various debug information about the current request/response.', 7 | long_description=open('README.rst').read(), 8 | # Get more strings from http://www.python.org/pypi?:action=list_classifiers 9 | author='Rob Hudson', 10 | author_email='rob@cogit8.org', 11 | url='https://github.com/django-debug-toolbar/django-debug-toolbar', 12 | download_url='https://github.com/django-debug-toolbar/django-debug-toolbar/downloads', 13 | license='BSD', 14 | packages=find_packages(exclude=['ez_setup']), 15 | tests_require=[ 16 | 'django', 17 | 'dingus', 18 | ], 19 | install_requires=[ 20 | 'pytidylib', 21 | ], 22 | test_suite='debug_toolbar.runtests.runtests', 23 | include_package_data=True, 24 | zip_safe=False, # because we're including media that Django needs 25 | classifiers=[ 26 | 'Development Status :: 4 - Beta', 27 | 'Environment :: Web Environment', 28 | 'Framework :: Django', 29 | 'Intended Audience :: Developers', 30 | 'License :: OSI Approved :: BSD License', 31 | 'Operating System :: OS Independent', 32 | 'Programming Language :: Python', 33 | 'Topic :: Software Development :: Libraries :: Python Modules', 34 | ], 35 | ) 36 | --------------------------------------------------------------------------------