Hello community,

here is the log from the commit of package python-django-debug-toolbar for 
openSUSE:Factory checked in at 2020-02-20 14:58:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-django-debug-toolbar (Old)
 and      /work/SRC/openSUSE:Factory/.python-django-debug-toolbar.new.26092 
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-django-debug-toolbar"

Thu Feb 20 14:58:16 2020 rev:16 rq:777579 version:2.2

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-django-debug-toolbar/python-django-debug-toolbar.changes
  2020-01-07 23:54:46.956075822 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-django-debug-toolbar.new.26092/python-django-debug-toolbar.changes
       2020-02-20 14:58:23.298642186 +0100
@@ -1,0 +2,9 @@
+Thu Feb 20 07:57:47 UTC 2020 - Tomáš Chvátal <[email protected]>
+
+- Update to 2.2:
+  * Removed support for end of life Django 2.0 and 2.1.
+  * Added support for Python 3.8.
+  * Add locals() option for sql panel.
+  * Added support for Django 3.0
+
+-------------------------------------------------------------------

Old:
----
  2.1.tar.gz

New:
----
  2.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-django-debug-toolbar.spec ++++++
--- /var/tmp/diff_new_pack.Z5Ac6N/_old  2020-02-20 14:58:24.474644494 +0100
+++ /var/tmp/diff_new_pack.Z5Ac6N/_new  2020-02-20 14:58:24.478644502 +0100
@@ -19,20 +19,20 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-django-debug-toolbar
-Version:        2.1
+Version:        2.2
 Release:        0
 Summary:        A configurable set of panels that display various debug 
information
 License:        BSD-3-Clause
 URL:            https://github.com/jazzband/django-debug-toolbar
 Source:         
https://github.com/jazzband/django-debug-toolbar/archive/%{version}.tar.gz
-BuildRequires:  %{python_module Django >= 2.0}
+BuildRequires:  %{python_module Django >= 2.2}
 BuildRequires:  %{python_module django-jinja}
 BuildRequires:  %{python_module html5lib}
 BuildRequires:  %{python_module isort}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  %{python_module sqlparse >= 0.2.0}
 BuildRequires:  fdupes
-Requires:       python-Django >= 2.0
+Requires:       python-Django >= 2.2
 Requires:       python-django-jinja
 Requires:       python-sqlparse >= 0.2.0
 BuildArch:      noarch

++++++ 2.1.tar.gz -> 2.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/.travis.yml 
new/django-debug-toolbar-2.2/.travis.yml
--- old/django-debug-toolbar-2.1/.travis.yml    2019-11-12 09:17:34.000000000 
+0100
+++ new/django-debug-toolbar-2.2/.travis.yml    2020-01-31 20:53:40.000000000 
+0100
@@ -1,52 +1,73 @@
-dist: xenial
 language: python
 cache: pip
 matrix:
   fast_finish: true
   include:
     - env: TOXENV=flake8
-    - python: 3.7
-      env: TOXENV=style
-    - python: 3.7
-      env: TOXENV=readme
-    - python: 3.5
-      env: TOXENV=py35-dj111
-    - python: 3.6
-      env: TOXENV=py36-dj111
-    - python: 3.7
-      env: TOXENV=py37-dj111
-    - python: 3.5
-      env: TOXENV=py35-dj20
-    - python: 3.6
-      env: TOXENV=py36-dj20
-    - python: 3.7
-      env: TOXENV=py37-dj20
+    - env: TOXENV=style
+    - env: TOXENV=readme
     - python: 3.5
-      env: TOXENV=py35-dj21
+      env: TOXENV=py35-dj111-sqlite
     - python: 3.6
-      env: TOXENV=py36-dj21
+      env: TOXENV=py36-dj111-sqlite
     - python: 3.7
-      env: TOXENV=py37-dj21
+      env: TOXENV=py37-dj111-sqlite
     - python: 3.5
-      env: TOXENV=py35-dj22
+      env: TOXENV=py35-dj22-sqlite
     - python: 3.6
-      env: TOXENV=py36-dj22
+      env: TOXENV=py36-dj22-sqlite
     - python: 3.7
-      env: TOXENV=py37-dj22
+      env: TOXENV=py37-dj22-sqlite
+    - python: 3.8
+      env: TOXENV=py38-dj22-sqlite
     - python: 3.6
-      env: TOXENV=py36-dj30
+      env: TOXENV=py36-dj30-sqlite
     - python: 3.7
-      env: TOXENV=py37-dj30
+      env: TOXENV=py37-dj30-sqlite
+    - python: 3.8
+      env: TOXENV=py38-dj30-sqlite
     - python: 3.6
-      env: TOXENV=py36-djmaster
+      env: TOXENV=py36-djmaster-sqlite
     - python: 3.7
-      env: TOXENV=py37-djmaster
+      env: TOXENV=py37-djmaster-sqlite
+    - python: 3.8
+      env: TOXENV=py38-djmaster-sqlite
     - python: 3.7
-      env: TOXENV=postgresql
+      env: TOXENV=py37-dj111-postgresql
+      addons:
+        postgresql: "9.5"
+    - python: 3.8
+      env: TOXENV=py38-dj22-postgresql
+      addons:
+        postgresql: "9.5"
+    - python: 3.8
+      env: TOXENV=py38-dj30-postgresql
       addons:
         postgresql: "9.5"
     - python: 3.7
-      env: TOXENV=mariadb
+      env: TOXENV=py37-dj111-mariadb
+      addons:
+        mariadb: "10.3"
+      script:
+        # working around 
https://travis-ci.community/t/mariadb-build-error-with-xenial/3160
+        - mysql -u root -e "DROP USER IF EXISTS 'travis'@'%';"
+        - mysql -u root -e "CREATE USER 'travis'@'%';"
+        - mysql -u root -e "CREATE DATABASE debug_toolbar;"
+        - mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'travis'@'%';";
+        - tox -v
+    - python: 3.8
+      env: TOXENV=py38-dj22-mariadb
+      addons:
+        mariadb: "10.3"
+      script:
+        # working around 
https://travis-ci.community/t/mariadb-build-error-with-xenial/3160
+        - mysql -u root -e "DROP USER IF EXISTS 'travis'@'%';"
+        - mysql -u root -e "CREATE USER 'travis'@'%';"
+        - mysql -u root -e "CREATE DATABASE debug_toolbar;"
+        - mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'travis'@'%';";
+        - tox -v
+    - python: 3.8
+      env: TOXENV=py38-dj30-mariadb
       addons:
         mariadb: "10.3"
       script:
@@ -57,8 +78,11 @@
         - mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'travis'@'%';";
         - tox -v
   allow_failures:
-    - env: TOXENV=py36-djmaster
-    - env: TOXENV=py37-djmaster
+    - env: TOXENV=py36-djmaster-sqlite
+    - env: TOXENV=py37-djmaster-sqlite
+    - env: TOXENV=py38-djmaster-sqlite
+    - env: TOXENV=py38-djmaster-postgresql
+    - env: TOXENV=py38-djmaster-mariadb
 
 install:
   - pip install tox codecov
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/README.rst 
new/django-debug-toolbar-2.2/README.rst
--- old/django-debug-toolbar-2.1/README.rst     2019-11-12 09:17:34.000000000 
+0100
+++ new/django-debug-toolbar-2.2/README.rst     2020-01-31 20:53:40.000000000 
+0100
@@ -31,7 +31,7 @@
 In addition to the built-in panels, a number of third-party panels are
 contributed by the community.
 
-The current stable version of the Debug Toolbar is 2.1. It works on
+The current stable version of the Debug Toolbar is 2.2. It works on
 Django ≥ 1.11.
 
 Documentation, including installation and configuration instructions, is
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/debug_toolbar/apps.py 
new/django-debug-toolbar-2.2/debug_toolbar/apps.py
--- old/django-debug-toolbar-2.1/debug_toolbar/apps.py  2019-11-12 
09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/debug_toolbar/apps.py  2020-01-31 
20:53:40.000000000 +0100
@@ -21,6 +21,17 @@
     gzip_index = None
     debug_toolbar_indexes = []
 
+    # If old style MIDDLEWARE_CLASSES is being used, report an error.
+    if settings.is_overridden("MIDDLEWARE_CLASSES"):
+        errors.append(
+            Warning(
+                "debug_toolbar is incompatible with MIDDLEWARE_CLASSES 
setting.",
+                hint="Use MIDDLEWARE instead of MIDDLEWARE_CLASSES",
+                id="debug_toolbar.W004",
+            )
+        )
+        return errors
+
     # Determine the indexes which gzip and/or the toolbar are installed at
     for i, middleware in enumerate(settings.MIDDLEWARE):
         if is_middleware_class(GZipMiddleware, middleware):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/management/commands/debugsqlshell.py 
new/django-debug-toolbar-2.2/debug_toolbar/management/commands/debugsqlshell.py
--- 
old/django-debug-toolbar-2.1/debug_toolbar/management/commands/debugsqlshell.py 
    2019-11-12 09:17:34.000000000 +0100
+++ 
new/django-debug-toolbar-2.2/debug_toolbar/management/commands/debugsqlshell.py 
    2020-01-31 20:53:40.000000000 +0100
@@ -1,13 +1,19 @@
 from time import time
 
+import django
 import sqlparse
 from django.core.management.commands.shell import Command  # noqa
-from django.db.backends import utils as db_backends_utils
+from django.db import connection
+
+if connection.vendor == "postgresql" and django.VERSION >= (3, 0, 0):
+    from django.db.backends.postgresql import base as base_module
+else:
+    from django.db.backends import utils as base_module
 
 # 'debugsqlshell' is the same as the 'shell'.
 
 
-class PrintQueryWrapper(db_backends_utils.CursorDebugWrapper):
+class PrintQueryWrapper(base_module.CursorDebugWrapper):
     def execute(self, sql, params=()):
         start_time = time()
         try:
@@ -20,4 +26,4 @@
             print("{} [{:.2f}ms]".format(formatted_sql, duration))
 
 
-db_backends_utils.CursorDebugWrapper = PrintQueryWrapper
+base_module.CursorDebugWrapper = PrintQueryWrapper
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/debug_toolbar/middleware.py 
new/django-debug-toolbar-2.2/debug_toolbar/middleware.py
--- old/django-debug-toolbar-2.1/debug_toolbar/middleware.py    2019-11-12 
09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/debug_toolbar/middleware.py    2020-01-31 
20:53:40.000000000 +0100
@@ -112,9 +112,9 @@
                 continue
 
             for key, record in stats.items():
-                # example: `SQLPanel_sql_time=0; "SQL 0 queries"`
+                # example: `SQLPanel_sql_time;dur=0;desc="SQL 0 queries"`
                 data.append(
-                    '{}_{}={}; "{}"'.format(
+                    '{}_{};dur={};desc="{}"'.format(
                         panel.panel_id, key, record.get("value"), 
record.get("title")
                     )
                 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/panels/redirects.py 
new/django-debug-toolbar-2.2/debug_toolbar/panels/redirects.py
--- old/django-debug-toolbar-2.1/debug_toolbar/panels/redirects.py      
2019-11-12 09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/debug_toolbar/panels/redirects.py      
2020-01-31 20:53:40.000000000 +0100
@@ -15,7 +15,7 @@
 
     def process_request(self, request):
         response = super().process_request(request)
-        if 300 <= int(response.status_code) < 400:
+        if 300 <= response.status_code < 400:
             redirect_to = response.get("Location", None)
             if redirect_to:
                 status_line = "{} {}".format(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/panels/settings.py 
new/django-debug-toolbar-2.2/debug_toolbar/panels/settings.py
--- old/django-debug-toolbar-2.1/debug_toolbar/panels/settings.py       
2019-11-12 09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/debug_toolbar/panels/settings.py       
2020-01-31 20:53:40.000000000 +0100
@@ -1,11 +1,18 @@
 from collections import OrderedDict
 
+import django
 from django.conf import settings
 from django.utils.translation import gettext_lazy as _
-from django.views.debug import get_safe_settings
 
 from debug_toolbar.panels import Panel
 
+if django.VERSION >= (3, 1):
+    from django.views.debug import get_default_exception_reporter_filter
+
+    get_safe_settings = 
get_default_exception_reporter_filter().get_safe_settings
+else:
+    from django.views.debug import get_safe_settings
+
 
 class SettingsPanel(Panel):
     """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/panels/sql/tracking.py 
new/django-debug-toolbar-2.2/debug_toolbar/panels/sql/tracking.py
--- old/django-debug-toolbar-2.1/debug_toolbar/panels/sql/tracking.py   
2019-11-12 09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/debug_toolbar/panels/sql/tracking.py   
2020-01-31 20:53:40.000000000 +0100
@@ -8,6 +8,11 @@
 from debug_toolbar import settings as dt_settings
 from debug_toolbar.utils import get_stack, get_template_info, tidy_stacktrace
 
+try:
+    from psycopg2._json import Json as PostgresJson
+except ImportError:
+    PostgresJson = None
+
 
 class SQLQueryTriggered(Exception):
     """Thrown when template panel triggers a query"""
@@ -105,6 +110,8 @@
         return [self._quote_expr(p) for p in params]
 
     def _decode(self, param):
+        if PostgresJson and isinstance(param, PostgresJson):
+            return param.dumps(param.adapted)
         # If a sequence type, decode each element separately
         if isinstance(param, (tuple, list)):
             return [self._decode(element) for element in param]
@@ -136,7 +143,6 @@
                 _params = json.dumps(self._decode(params))
             except TypeError:
                 pass  # object not JSON serializable
-
             template_info = get_template_info()
 
             alias = getattr(self.db, "alias", "default")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/debug_toolbar/settings.py 
new/django-debug-toolbar-2.2/debug_toolbar/settings.py
--- old/django-debug-toolbar-2.1/debug_toolbar/settings.py      2019-11-12 
09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/debug_toolbar/settings.py      2020-01-31 
20:53:40.000000000 +0100
@@ -24,6 +24,7 @@
     # Panel options
     "EXTRA_SIGNALS": [],
     "ENABLE_STACKTRACES": True,
+    "ENABLE_STACKTRACES_LOCALS": False,
     "HIDE_IN_STACKTRACES": (
         "socketserver",
         "threading",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/static/debug_toolbar/css/toolbar.css 
new/django-debug-toolbar-2.2/debug_toolbar/static/debug_toolbar/css/toolbar.css
--- 
old/django-debug-toolbar-2.1/debug_toolbar/static/debug_toolbar/css/toolbar.css 
    2019-11-12 09:17:34.000000000 +0100
+++ 
new/django-debug-toolbar-2.2/debug_toolbar/static/debug_toolbar/css/toolbar.css 
    2020-01-31 20:53:40.000000000 +0100
@@ -619,13 +619,18 @@
     color: #000;
     font-weight: bold;
 }
-#djDebug .djdt-stack span.djdt-path {
+#djDebug .djdt-stack span.djdt-path,
+#djDebug .djdt-stack pre.djdt-locals,
+#djDebug .djdt-stack pre.djdt-locals span {
     color: #777;
     font-weight: normal;
 }
 #djDebug .djdt-stack span.djdt-code {
     font-weight: normal;
 }
+#djDebug .djdt-stack pre.djdt-locals {
+       margin: 0 27px 27px 27px;
+}
 
 #djDebug .djdt-width-20 {
     width: 20%;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/static/debug_toolbar/js/toolbar.js 
new/django-debug-toolbar-2.2/debug_toolbar/static/debug_toolbar/js/toolbar.js
--- 
old/django-debug-toolbar-2.1/debug_toolbar/static/debug_toolbar/js/toolbar.js   
    2019-11-12 09:17:34.000000000 +0100
+++ 
new/django-debug-toolbar-2.2/debug_toolbar/static/debug_toolbar/js/toolbar.js   
    2020-01-31 20:53:40.000000000 +0100
@@ -78,9 +78,9 @@
                     this.parentElement.classList.add('djdt-active');
 
                     var inner = current.querySelector('.djDebugPanelContent 
.djdt-scroll'),
-                        store_id = djDebug.getAttribute('data-store-id');
+                        store_id = djDebug.dataset.storeId;
                     if (store_id && inner.children.length === 0) {
-                        var url = 
djDebug.getAttribute('data-render-panel-url');
+                        var url = djDebug.dataset.renderPanelUrl;
                         var url_params = new URLSearchParams();
                         url_params.append('store_id', store_id);
                         url_params.append('panel_id', this.className);
@@ -98,7 +98,7 @@
                 djdt.hide_one_level();
             });
             $$.on(djDebug, 'click', '.djDebugPanelButton 
input[type=checkbox]', function() {
-                djdt.cookie.set(this.getAttribute('data-cookie'), this.checked 
? 'on' : 'off', {
+                djdt.cookie.set(this.dataset.cookie, this.checked ? 'on' : 
'off', {
                     path: '/',
                     expires: 10
                 });
@@ -137,12 +137,12 @@
             $$.on(djDebug, 'click', 'a.djToggleSwitch', function(event) {
                 event.preventDefault();
                 var self = this;
-                var id = this.getAttribute('data-toggle-id');
-                var open_me = this.textContent == 
this.getAttribute('data-toggle-open');
+                var id = this.dataset.toggleId;
+                var open_me = this.textContent == this.dataset.toggleOpen;
                 if (id === '' || !id) {
                     return;
                 }
-                var name = this.getAttribute('data-toggle-name');
+                var name = this.dataset.toggleName;
                 var container = 
this.closest('.djDebugPanelContent').querySelector('#' + name + '_' + id);
                 
container.querySelectorAll('.djDebugCollapsed').forEach(function(e) {
                     $$.toggle(e, open_me);
@@ -154,11 +154,11 @@
                     if (open_me) {
                         e.classList.add('djSelected');
                         e.classList.remove('djUnselected');
-                        self.textContent = 
self.getAttribute('data-toggle-close');
+                        self.textContent = self.dataset.toggleClose;
                     } else {
                         e.classList.remove('djSelected');
                         e.classList.add('djUnselected');
-                        self.textContent = 
self.getAttribute('data-toggle-open');
+                        self.textContent = self.dataset.toggleOpen;
                     }
                     var switch_ = e.querySelector('.djToggleSwitch')
                     if (switch_) switch_.textContent = self.textContent;
@@ -312,12 +312,6 @@
                 return value;
             }
         },
-        applyStyle: function(name) {
-            var selector = '#djDebug [data-' + name + ']';
-            document.querySelectorAll(selector).forEach(function(element) {
-                element.style[name] = element.getAttribute('data-' + name);
-            });
-        }
     };
     window.djdt = {
         show_toolbar: djdt.show_toolbar,
@@ -325,7 +319,6 @@
         init: djdt.init,
         close: djdt.hide_one_level,
         cookie: djdt.cookie,
-        applyStyle: djdt.applyStyle
     };
     document.addEventListener('DOMContentLoaded', djdt.init);
 })();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/static/debug_toolbar/js/toolbar.profiling.js
 
new/django-debug-toolbar-2.2/debug_toolbar/static/debug_toolbar/js/toolbar.profiling.js
--- 
old/django-debug-toolbar-2.1/debug_toolbar/static/debug_toolbar/js/toolbar.profiling.js
     2019-11-12 09:17:34.000000000 +0100
+++ 
new/django-debug-toolbar-2.2/debug_toolbar/static/debug_toolbar/js/toolbar.profiling.js
     1970-01-01 01:00:00.000000000 +0100
@@ -1,3 +0,0 @@
-(function () {
-    djdt.applyStyle('padding-left');
-})();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/static/debug_toolbar/js/toolbar.sql.js
 
new/django-debug-toolbar-2.2/debug_toolbar/static/debug_toolbar/js/toolbar.sql.js
--- 
old/django-debug-toolbar-2.1/debug_toolbar/static/debug_toolbar/js/toolbar.sql.js
   2019-11-12 09:17:34.000000000 +0100
+++ 
new/django-debug-toolbar-2.2/debug_toolbar/static/debug_toolbar/js/toolbar.sql.js
   1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-(function () {
-    djdt.applyStyle('background-color');
-    djdt.applyStyle('left');
-    djdt.applyStyle('width');
-})();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/templates/debug_toolbar/panels/profiling.html
 
new/django-debug-toolbar-2.2/debug_toolbar/templates/debug_toolbar/panels/profiling.html
--- 
old/django-debug-toolbar-2.1/debug_toolbar/templates/debug_toolbar/panels/profiling.html
    2019-11-12 09:17:34.000000000 +0100
+++ 
new/django-debug-toolbar-2.2/debug_toolbar/templates/debug_toolbar/panels/profiling.html
    2020-01-31 20:53:40.000000000 +0100
@@ -1,5 +1,5 @@
 {% load i18n %}{% load static %}
-<table width="100%">
+<table>
        <thead>
                <tr>
                        <th>{% trans "Call" %}</th>
@@ -12,9 +12,9 @@
        </thead>
        <tbody>
                {% for call in func_list %}
-                       <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %} 
djDebugProfileRow{% for parent_id in call.parent_ids %} djToggleDetails_{{ 
parent_id }}{% endfor %}" depth="{{ call.depth }}" id="profilingMain_{{ call.id 
}}">
+                       <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}{% for 
parent_id in call.parent_ids %} djToggleDetails_{{ parent_id }}{% endfor %}" 
id="profilingMain_{{ call.id }}">
                                <td>
-                                       <div data-padding-left="{{ call.indent 
}}px">
+                                       <div style="padding-left:{{ call.indent 
}}px">
                                                {% if call.has_subfuncs %}
                                                        <a 
class="djProfileToggleDetails djToggleSwitch" data-toggle-name="profilingMain" 
data-toggle-id="{{ call.id }}" data-toggle-open="+" data-toggle-close="-" 
href>-</a>
                                                {% else %}
@@ -32,5 +32,3 @@
                {% endfor %}
        </tbody>
 </table>
-
-<script src="{% static 'debug_toolbar/js/toolbar.profiling.js' %}" 
defer></script>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/templates/debug_toolbar/panels/sql.html
 
new/django-debug-toolbar-2.2/debug_toolbar/templates/debug_toolbar/panels/sql.html
--- 
old/django-debug-toolbar-2.1/debug_toolbar/templates/debug_toolbar/panels/sql.html
  2019-11-12 09:17:34.000000000 +0100
+++ 
new/django-debug-toolbar-2.2/debug_toolbar/templates/debug_toolbar/panels/sql.html
  2020-01-31 20:53:40.000000000 +0100
@@ -3,7 +3,7 @@
        <ul class="djdt-stats">
                {% for alias, info in databases %}
                        <li>
-                               <strong class="djdt-label"><span 
data-background-color="rgb({{ info.rgb_color|join:", " }})" 
class="djdt-color">&#160;</span> {{ alias }}</strong>
+                               <strong class="djdt-label"><span 
style="background-color:rgb({{ info.rgb_color|join:', ' }})" 
class="djdt-color">&#160;</span> {{ alias }}</strong>
                                <span class="djdt-info">{{ 
info.time_spent|floatformat:"2" }} ms ({% blocktrans count info.num_queries as 
num %}{{ num }} query{% plural %}{{ num }} queries{% endblocktrans %}
                                {% if info.similar_count %}
                                        {% blocktrans with 
count=info.similar_count trimmed %}
@@ -34,7 +34,7 @@
                <tbody>
                        {% for query in queries %}
                                <tr class="{% cycle 'djDebugOdd' 'djDebugEven' 
%}{% if query.is_slow %} djDebugRowWarning{% endif %}{% if query.starts_trans 
%} djDebugStartTransaction{% endif %}{% if query.ends_trans %} 
djDebugEndTransaction{% endif %}{% if query.in_trans %} djDebugInTransaction{% 
endif %}" id="sqlMain_{{ forloop.counter }}">
-                                       <td class="djdt-color"><span 
data-background-color="rgb({{ query.rgb_color|join:", " }})">&#160;</span></td>
+                                       <td class="djdt-color"><span 
style="background-color:rgb({{ query.rgb_color|join:', '}})">&#160;</span></td>
                                        <td class="djdt-toggle">
                                                <a class="djToggleSwitch" 
data-toggle-name="sqlMain" data-toggle-id="{{ forloop.counter }}" 
data-toggle-open="+" data-toggle-close="-" href="">+</a>
                                        </td>
@@ -44,19 +44,19 @@
                                                </div>
                                                {% if query.similar_count %}
                                                        <strong>
-                                                               <span 
data-background-color="{{ query.similar_color }}">&#160;</span>
+                                                               <span 
style="background-color:{{ query.similar_color }}">&#160;</span>
                                                                {% blocktrans 
with count=query.similar_count %}{{ count }} similar queries.{% endblocktrans %}
                                                        </strong>
                                                {% endif %}
                                                {% if query.duplicate_count %}
                                                        <strong>
-                                                               <span 
data-background-color="{{ query.duplicate_color }}">&#160;</span>
+                                                               <span 
style="background-color:{{ query.duplicate_color }}">&#160;</span>
                                                                {% blocktrans 
with dupes=query.duplicate_count %}Duplicated {{ dupes }} times.{% 
endblocktrans %}
                                                        </strong>
                                                {% endif %}
                                        </td>
                                        <td class="djdt-timeline">
-                                               <div 
class="djDebugTimeline"><div class="djDebugLineChart{% if query.is_slow %} 
djDebugLineChartWarning{% endif %}" data-left="{{ query.start_offset|unlocalize 
}}%"><strong data-width="{{ query.width_ratio_relative|unlocalize }}%" 
data-background-color="{{ query.trace_color }}">{{ query.width_ratio 
}}%</strong></div></div>
+                                               <div 
class="djDebugTimeline"><div class="djDebugLineChart{% if query.is_slow %} 
djDebugLineChartWarning{% endif %}" style="left:{{ 
query.start_offset|unlocalize }}%"><strong style="width:{{ 
query.width_ratio_relative|unlocalize }}%;background-color:{{ query.trace_color 
}}">{{ query.width_ratio }}%</strong></div></div>
                                        </td>
                                        <td class="djdt-time">
                                                {{ 
query.duration|floatformat:"2" }}
@@ -113,5 +113,3 @@
 {% else %}
        <p>{% trans "No SQL queries were recorded during this request." %}</p>
 {% endif %}
-
-<script src="{% static 'debug_toolbar/js/toolbar.sql.js' %}" defer></script>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/templates/debug_toolbar/panels/sql_explain.html
 
new/django-debug-toolbar-2.2/debug_toolbar/templates/debug_toolbar/panels/sql_explain.html
--- 
old/django-debug-toolbar-2.1/debug_toolbar/templates/debug_toolbar/panels/sql_explain.html
  2019-11-12 09:17:34.000000000 +0100
+++ 
new/django-debug-toolbar-2.2/debug_toolbar/templates/debug_toolbar/panels/sql_explain.html
  2020-01-31 20:53:40.000000000 +0100
@@ -33,5 +33,3 @@
                </table>
        </div>
 </div>
-
-<script src="{% static 'debug_toolbar/js/toolbar.sql.js' %}" defer></script>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/templates/debug_toolbar/panels/sql_profile.html
 
new/django-debug-toolbar-2.2/debug_toolbar/templates/debug_toolbar/panels/sql_profile.html
--- 
old/django-debug-toolbar-2.1/debug_toolbar/templates/debug_toolbar/panels/sql_profile.html
  2019-11-12 09:17:34.000000000 +0100
+++ 
new/django-debug-toolbar-2.2/debug_toolbar/templates/debug_toolbar/panels/sql_profile.html
  2020-01-31 20:53:40.000000000 +0100
@@ -40,5 +40,3 @@
                {% endif %}
        </div>
 </div>
-
-<script src="{% static 'debug_toolbar/js/toolbar.sql.js' %}" defer></script>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/templates/debug_toolbar/panels/sql_select.html
 
new/django-debug-toolbar-2.2/debug_toolbar/templates/debug_toolbar/panels/sql_select.html
--- 
old/django-debug-toolbar-2.1/debug_toolbar/templates/debug_toolbar/panels/sql_select.html
   2019-11-12 09:17:34.000000000 +0100
+++ 
new/django-debug-toolbar-2.2/debug_toolbar/templates/debug_toolbar/panels/sql_select.html
   2020-01-31 20:53:40.000000000 +0100
@@ -37,5 +37,3 @@
                {% endif %}
        </div>
 </div>
-
-<script src="{% static 'debug_toolbar/js/toolbar.sql.js' %}" defer></script>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/debug_toolbar/templates/debug_toolbar/panels/sql_stacktrace.html
 
new/django-debug-toolbar-2.2/debug_toolbar/templates/debug_toolbar/panels/sql_stacktrace.html
--- 
old/django-debug-toolbar-2.1/debug_toolbar/templates/debug_toolbar/panels/sql_stacktrace.html
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/django-debug-toolbar-2.2/debug_toolbar/templates/debug_toolbar/panels/sql_stacktrace.html
       2020-01-31 20:53:40.000000000 +0100
@@ -0,0 +1,3 @@
+{% for s in stacktrace %}<span class="djdt-path">{{s.0}}/</span><span 
class="djdt-file">{{s.1}}</span> in <span 
class="djdt-func">{{s.3}}</span>(<span class="djdt-lineno">{{s.2}}</span>)
+  <span class="djdt-code">{{s.4}}</span>
+{% if show_locals %}<pre class="djdt-locals">{{s.5|pprint}}</pre>{% endif %}{% 
endfor %}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/debug_toolbar/utils.py 
new/django-debug-toolbar-2.2/debug_toolbar/utils.py
--- old/django-debug-toolbar-2.1/debug_toolbar/utils.py 2019-11-12 
09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/debug_toolbar/utils.py 2020-01-31 
20:53:40.000000000 +0100
@@ -8,7 +8,7 @@
 import django
 from django.core.exceptions import ImproperlyConfigured
 from django.template import Node
-from django.utils.html import escape
+from django.template.loader import render_to_string
 from django.utils.safestring import mark_safe
 
 from debug_toolbar import settings as dt_settings
@@ -59,28 +59,36 @@
         if omit_path(os.path.realpath(path)):
             continue
         text = "".join(text).strip() if text else ""
-        trace.append((path, line_no, func_name, text))
+        frame_locals = (
+            frame.f_locals
+            if dt_settings.get_config()["ENABLE_STACKTRACES_LOCALS"]
+            else None
+        )
+        trace.append((path, line_no, func_name, text, frame_locals))
     return trace
 
 
 def render_stacktrace(trace):
     stacktrace = []
     for frame in trace:
-        params = (escape(v) for v in chain(frame[0].rsplit(os.path.sep, 1), 
frame[1:]))
+        params = (v for v in chain(frame[0].rsplit(os.path.sep, 1), frame[1:]))
         params_dict = {str(idx): v for idx, v in enumerate(params)}
         try:
-            stacktrace.append(
-                '<span class="djdt-path">%(0)s/</span>'
-                '<span class="djdt-file">%(1)s</span>'
-                ' in <span class="djdt-func">%(3)s</span>'
-                '(<span class="djdt-lineno">%(2)s</span>)\n'
-                '  <span class="djdt-code">%(4)s</span>' % params_dict
-            )
+            stacktrace.append(params_dict)
         except KeyError:
             # This frame doesn't have the expected format, so skip it and move
             # on to the next one
             continue
-    return mark_safe("\n".join(stacktrace))
+
+    return mark_safe(
+        render_to_string(
+            "debug_toolbar/panels/sql_stacktrace.html",
+            {
+                "stacktrace": stacktrace,
+                "show_locals": 
dt_settings.get_config()["ENABLE_STACKTRACES_LOCALS"],
+            },
+        )
+    )
 
 
 def get_template_info():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/docs/changes.rst 
new/django-debug-toolbar-2.2/docs/changes.rst
--- old/django-debug-toolbar-2.1/docs/changes.rst       2019-11-12 
09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/docs/changes.rst       2020-01-31 
20:53:40.000000000 +0100
@@ -1,6 +1,18 @@
 Change log
 ==========
 
+UNRELEASED
+----------
+
+
+2.2 (2020-01-31)
+----------------
+
+* Removed support for end of life Django 2.0 and 2.1.
+* Added support for Python 3.8.
+* Add locals() option for sql panel.
+* Added support for Django 3.0
+
 2.1 (2019-11-12)
 ----------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/docs/conf.py 
new/django-debug-toolbar-2.2/docs/conf.py
--- old/django-debug-toolbar-2.1/docs/conf.py   2019-11-12 09:17:34.000000000 
+0100
+++ new/django-debug-toolbar-2.2/docs/conf.py   2020-01-31 20:53:40.000000000 
+0100
@@ -59,9 +59,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '2.1'
+version = '2.2'
 # The full version, including alpha/beta/rc tags.
-release = '2.1'
+release = '2.2'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -135,7 +135,7 @@
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+#html_static_path = ['_static']
 
 # Add any extra paths that contain custom files (such as robots.txt or
 # .htaccess) here, relative to this directory. These files are copied
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/docs/configuration.rst 
new/django-debug-toolbar-2.2/docs/configuration.rst
--- old/django-debug-toolbar-2.1/docs/configuration.rst 2019-11-12 
09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/docs/configuration.rst 2020-01-31 
20:53:40.000000000 +0100
@@ -139,10 +139,40 @@
   calls. Enabling stacktraces can increase the CPU time used when executing
   queries.
 
+* ``ENABLE_STACKTRACES_LOCALS``
+
+  Default: ``False``
+
+  Panels: cache, SQL
+
+  If set to ``True``, this will show locals() for each stacktrace piece of
+  code for SQL queries and cache calls.
+  Enabling stacktraces locals will increase the CPU time used when executing
+  queries and will give too verbose information in most cases, but is useful
+  for debugging complex cases.
+
+.. caution::
+   This will expose all members from each frame of the stacktrace. This can
+   potentially expose sensitive or private information. It's advised to only
+   use this configuration locally.
+
 * ``HIDE_IN_STACKTRACES``
 
-  Default: ``('socketserver', 'threading', 'wsgiref', 'debug_toolbar',
-  'django')``.
+  Default::
+
+    (
+        "socketserver",
+        "threading",
+        "wsgiref",
+        "debug_toolbar",
+        "django.db",
+        "django.core.handlers",
+        "django.core.servers",
+        "django.utils.decorators",
+        "django.utils.deprecation",
+        "django.utils.functional",
+    )
+
 
   Panels: cache, SQL
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/example/README.rst 
new/django-debug-toolbar-2.2/example/README.rst
--- old/django-debug-toolbar-2.1/example/README.rst     2019-11-12 
09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/example/README.rst     2020-01-31 
20:53:40.000000000 +0100
@@ -27,3 +27,10 @@
 Then you can use the following command to run the example::
 
     $ python -m django runserver --settings=example.settings
+
+You can change the database used by specifying the ``DJANGO_DATABASE_ENGINE``
+environment variable::
+
+    $ DJANGO_DATABASE_ENGINE=postgresql python -m django migrate 
--settings=example.settings
+    $ DJANGO_DATABASE_ENGINE=postgresql python -m django runserver 
--settings=example.settings
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/example/settings.py 
new/django-debug-toolbar-2.2/example/settings.py
--- old/django-debug-toolbar-2.1/example/settings.py    2019-11-12 
09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/example/settings.py    2020-01-31 
20:53:40.000000000 +0100
@@ -86,6 +86,7 @@
 if os.environ.get("DJANGO_DATABASE_ENGINE", "").lower() == "mysql":
     # % mysql
     # mysql> CREATE DATABASE debug_toolbar;
+    # mysql> CREATE USER 'debug_toolbar'@'localhost';
     # mysql> GRANT ALL PRIVILEGES ON debug_toolbar.* TO 
'debug_toolbar'@'localhost';
     DATABASES = {
         "default": {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/example/templates/jquery/index.html 
new/django-debug-toolbar-2.2/example/templates/jquery/index.html
--- old/django-debug-toolbar-2.1/example/templates/jquery/index.html    
2019-11-12 09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/example/templates/jquery/index.html    
2020-01-31 20:53:40.000000000 +0100
@@ -7,7 +7,7 @@
        .hide {display:none;}
        </style>
        <script 
src="//ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
-       <script type="text/javascript">
+       <script>
                $(document).ready(function() {
                        $('p.hide').show();
                        $('#v').text($.fn.jquery);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/example/templates/mootools/index.html 
new/django-debug-toolbar-2.2/example/templates/mootools/index.html
--- old/django-debug-toolbar-2.1/example/templates/mootools/index.html  
2019-11-12 09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/example/templates/mootools/index.html  
2020-01-31 20:53:40.000000000 +0100
@@ -7,7 +7,7 @@
        .hide {display:none;}
        </style>
        <script 
src="//ajax.googleapis.com/ajax/libs/mootools/1.6.0/mootools.min.js"></script>
-       <script type="text/javascript">
+       <script>
                window.addEvent('domready', function() {
                        $$('p.hide').setStyle('display', 'block');
                        $('v').set('text', MooTools.version);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/example/templates/prototype/index.html 
new/django-debug-toolbar-2.2/example/templates/prototype/index.html
--- old/django-debug-toolbar-2.1/example/templates/prototype/index.html 
2019-11-12 09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/example/templates/prototype/index.html 
2020-01-31 20:53:40.000000000 +0100
@@ -7,7 +7,7 @@
        .hide {display:none;}
        </style>
        <script 
src="//ajax.googleapis.com/ajax/libs/prototype/1.7.3.0/prototype.js"></script>
-       <script type="text/javascript">
+       <script>
                document.observe('dom:loaded', function() {
                        $('showme').removeClassName('hide');
                        $('v').textContent = Prototype.Version;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/setup.py 
new/django-debug-toolbar-2.2/setup.py
--- old/django-debug-toolbar-2.1/setup.py       2019-11-12 09:17:34.000000000 
+0100
+++ new/django-debug-toolbar-2.2/setup.py       2020-01-31 20:53:40.000000000 
+0100
@@ -12,7 +12,7 @@
 
 setup(
     name="django-debug-toolbar",
-    version="2.1",
+    version="2.2",
     description="A configurable set of panels that display various debug "
     "information about the current request/response.",
     long_description=readall("README.rst"),
@@ -21,6 +21,7 @@
     url="https://github.com/jazzband/django-debug-toolbar";,
     download_url="https://pypi.org/project/django-debug-toolbar/";,
     license="BSD",
+    license_files=["LICENSE"],
     packages=find_packages(exclude=("tests.*", "tests", "example")),
     python_requires=">=3.5",
     install_requires=["Django>=1.11", "sqlparse>=0.2.0"],
@@ -31,8 +32,6 @@
         "Environment :: Web Environment",
         "Framework :: Django",
         "Framework :: Django :: 1.11",
-        "Framework :: Django :: 2.0",
-        "Framework :: Django :: 2.1",
         "Framework :: Django :: 2.2",
         "Framework :: Django :: 3.0",
         "Intended Audience :: Developers",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-debug-toolbar-2.1/tests/commands/test_debugsqlshell.py 
new/django-debug-toolbar-2.2/tests/commands/test_debugsqlshell.py
--- old/django-debug-toolbar-2.1/tests/commands/test_debugsqlshell.py   
2019-11-12 09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/tests/commands/test_debugsqlshell.py   
2020-01-31 20:53:40.000000000 +0100
@@ -1,17 +1,23 @@
 import io
 import sys
 
+import django
 from django.contrib.auth.models import User
 from django.core import management
-from django.db.backends import utils as db_backends_utils
+from django.db import connection
 from django.test import TestCase
 from django.test.utils import override_settings
 
+if connection.vendor == "postgresql" and django.VERSION >= (3, 0, 0):
+    from django.db.backends.postgresql import base as base_module
+else:
+    from django.db.backends import utils as base_module
+
 
 @override_settings(DEBUG=True)
 class DebugSQLShellTestCase(TestCase):
     def setUp(self):
-        self.original_cursor_wrapper = db_backends_utils.CursorDebugWrapper
+        self.original_wrapper = base_module.CursorDebugWrapper
         # Since debugsqlshell monkey-patches django.db.backends.utils, we can
         # test it simply by loading it, without executing it. But we have to
         # undo the monkey-patch on exit.
@@ -20,7 +26,7 @@
         management.load_command_class(app_name, command_name)
 
     def tearDown(self):
-        db_backends_utils.CursorDebugWrapper = self.original_cursor_wrapper
+        base_module.CursorDebugWrapper = self.original_wrapper
 
     def test_command(self):
         original_stdout, sys.stdout = sys.stdout, io.StringIO()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/tests/models.py 
new/django-debug-toolbar-2.2/tests/models.py
--- old/django-debug-toolbar-2.1/tests/models.py        2019-11-12 
09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/tests/models.py        2020-01-31 
20:53:40.000000000 +0100
@@ -8,3 +8,14 @@
 
 class Binary(models.Model):
     field = models.BinaryField()
+
+
+try:
+    from django.contrib.postgres.fields import JSONField
+
+    class PostgresJSON(models.Model):
+        field = JSONField()
+
+
+except ImportError:
+    pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/tests/panels/test_sql.py 
new/django-debug-toolbar-2.2/tests/panels/test_sql.py
--- old/django-debug-toolbar-2.1/tests/panels/test_sql.py       2019-11-12 
09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/tests/panels/test_sql.py       2020-01-31 
20:53:40.000000000 +0100
@@ -1,6 +1,7 @@
 import datetime
 import unittest
 
+import django
 from django.contrib.auth.models import User
 from django.db import connection
 from django.db.models import Count
@@ -10,6 +11,16 @@
 
 from ..base import BaseTestCase
 
+try:
+    from psycopg2._json import Json as PostgresJson
+except ImportError:
+    PostgresJson = None
+
+if connection.vendor == "postgresql":
+    from ..models import PostgresJSON as PostgresJSONModel
+else:
+    PostgresJSONModel = None
+
 
 class SQLPanelTestCase(BaseTestCase):
     panel_id = "SQLPanel"
@@ -108,9 +119,35 @@
         # ensure query was logged
         self.assertEqual(len(self.panel._queries), 3)
 
+        if django.VERSION >= (3, 1):
+            self.assertEqual(
+                tuple([q[1]["params"] for q in self.panel._queries]),
+                ('["Foo"]', "[10, 1]", '["2017-12-22 16:07:01"]'),
+            )
+        else:
+            self.assertEqual(
+                tuple([q[1]["params"] for q in self.panel._queries]),
+                ('["Foo", true, false]', "[10, 1]", '["2017-12-22 16:07:01"]'),
+            )
+
+    @unittest.skipUnless(
+        connection.vendor == "postgresql", "Test valid only on PostgreSQL"
+    )
+    def test_json_param_conversion(self):
+        self.assertEqual(len(self.panel._queries), 0)
+
+        list(PostgresJSONModel.objects.filter(field__contains={"foo": "bar"}))
+
+        response = self.panel.process_request(self.request)
+        self.panel.generate_stats(self.request, response)
+
+        # ensure query was logged
+        self.assertEqual(len(self.panel._queries), 1)
         self.assertEqual(
-            tuple([q[1]["params"] for q in self.panel._queries]),
-            ('["Foo", true, false]', "[10, 1]", '["2017-12-22 16:07:01"]'),
+            self.panel._queries[0][1]["params"], '["{\\"foo\\": \\"bar\\"}"]',
+        )
+        self.assertIsInstance(
+            self.panel._queries[0][1]["raw_params"][0], PostgresJson,
         )
 
     def test_binary_param_force_text(self):
@@ -208,6 +245,30 @@
         self.assertIn("café", self.panel.content)
         self.assertValidHTML(self.panel.content)
 
+    @override_settings(DEBUG_TOOLBAR_CONFIG={"ENABLE_STACKTRACES_LOCALS": 
True})
+    def test_insert_locals(self):
+        """
+        Test that the panel inserts locals() content.
+        """
+        local_var = "<script>alert('test');</script>"  # noqa
+        list(User.objects.filter(username="café".encode("utf-8")))
+        response = self.panel.process_request(self.request)
+        self.panel.generate_stats(self.request, response)
+        self.assertIn("local_var", self.panel.content)
+        # Verify the escape logic works
+        self.assertNotIn("<script>alert", self.panel.content)
+        self.assertIn("&lt;script&gt;alert", self.panel.content)
+        self.assertIn("djdt-locals", self.panel.content)
+
+    def test_not_insert_locals(self):
+        """
+        Test that the panel does not insert locals() content.
+        """
+        list(User.objects.filter(username="café".encode("utf-8")))
+        response = self.panel.process_request(self.request)
+        self.panel.generate_stats(self.request, response)
+        self.assertNotIn("djdt-locals", self.panel.content)
+
     @unittest.skipUnless(
         connection.vendor == "postgresql", "Test valid only on PostgreSQL"
     )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/tests/test_integration.py 
new/django-debug-toolbar-2.2/tests/test_integration.py
--- old/django-debug-toolbar-2.1/tests/test_integration.py      2019-11-12 
09:17:34.000000000 +0100
+++ new/django-debug-toolbar-2.2/tests/test_integration.py      2020-01-31 
20:53:40.000000000 +0100
@@ -1,10 +1,12 @@
 import os
+import re
 import unittest
 
 import html5lib
 from django.contrib.staticfiles.testing import StaticLiveServerTestCase
 from django.core import signing
 from django.core.checks import Warning, run_checks
+from django.db import connection
 from django.http import HttpResponse
 from django.template.loader import get_template
 from django.test import RequestFactory, SimpleTestCase, TestCase
@@ -92,6 +94,7 @@
     def test_middleware(self):
         response = self.client.get("/execute_sql/")
         self.assertEqual(response.status_code, 200)
+        self.assertContains(response, "djDebug")
 
     @override_settings(DEFAULT_CHARSET="iso-8859-1")
     def test_non_utf8_charset(self):
@@ -204,6 +207,35 @@
             )
             self.assertEqual(response.status_code, 404)
 
+    @unittest.skipUnless(
+        connection.vendor == "postgresql", "Test valid only on PostgreSQL"
+    )
+    def test_sql_explain_postgres_json_field(self):
+        url = "/__debug__/sql_explain/"
+        base_query = (
+            'SELECT * FROM "tests_postgresjson" WHERE 
"tests_postgresjson"."field" @>'
+        )
+        query = base_query + """ '{"foo": "bar"}'"""
+        data = {
+            "sql": query,
+            "raw_sql": base_query + " %s",
+            "params": '["{\\"foo\\": \\"bar\\"}"]',
+            "alias": "default",
+            "duration": "0",
+            "hash": "2b7172eb2ac8e2a8d6f742f8a28342046e0d00ba",
+        }
+        response = self.client.post(url, data)
+        self.assertEqual(response.status_code, 200)
+        response = self.client.post(url, data, 
HTTP_X_REQUESTED_WITH="XMLHttpRequest")
+        self.assertEqual(response.status_code, 200)
+        with self.settings(INTERNAL_IPS=[]):
+            response = self.client.post(url, data)
+            self.assertEqual(response.status_code, 404)
+            response = self.client.post(
+                url, data, HTTP_X_REQUESTED_WITH="XMLHttpRequest"
+            )
+            self.assertEqual(response.status_code, 404)
+
     def test_sql_profile_checks_show_toolbar(self):
         url = "/__debug__/sql_profile/"
         data = {
@@ -245,6 +277,20 @@
         # Link to LOCATION header.
         self.assertIn(b'href="/regular/redirect/"', response.content)
 
+    def test_server_timing_headers(self):
+        response = self.client.get("/execute_sql/")
+        server_timing = response["Server-Timing"]
+        expected_partials = [
+            r'TimerPanel_utime;dur=(\d)*(\.(\d)*)?;desc="User CPU time", ',
+            r'TimerPanel_stime;dur=(\d)*(\.(\d)*)?;desc="System CPU time", ',
+            r'TimerPanel_total;dur=(\d)*(\.(\d)*)?;desc="Total CPU time", ',
+            r'TimerPanel_total_time;dur=(\d)*(\.(\d)*)?;desc="Elapsed time", ',
+            r'SQLPanel_sql_time;dur=(\d)*(\.(\d)*)?;desc="SQL 1 queries", ',
+            r'CachePanel_total_time;dur=0;desc="Cache 0 Calls"',
+        ]
+        for expected in expected_partials:
+            self.assertTrue(re.compile(expected).search(server_timing))
+
 
 @unittest.skipIf(webdriver is None, "selenium isn't installed")
 @unittest.skipUnless(
@@ -411,3 +457,23 @@
                 )
             ],
         )
+
+    @override_settings(
+        MIDDLEWARE_CLASSES=[
+            "django.contrib.messages.middleware.MessageMiddleware",
+            "django.contrib.sessions.middleware.SessionMiddleware",
+            "django.contrib.auth.middleware.AuthenticationMiddleware",
+            "django.middleware.gzip.GZipMiddleware",
+            "debug_toolbar.middleware.DebugToolbarMiddleware",
+        ]
+    )
+    def test_check_middleware_classes_error(self):
+        messages = run_checks()
+        self.assertIn(
+            Warning(
+                "debug_toolbar is incompatible with MIDDLEWARE_CLASSES 
setting.",
+                hint="Use MIDDLEWARE instead of MIDDLEWARE_CLASSES",
+                id="debug_toolbar.W004",
+            ),
+            messages,
+        )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/tests/views.py 
new/django-debug-toolbar-2.2/tests/views.py
--- old/django-debug-toolbar-2.1/tests/views.py 2019-11-12 09:17:34.000000000 
+0100
+++ new/django-debug-toolbar-2.2/tests/views.py 2020-01-31 20:53:40.000000000 
+0100
@@ -1,5 +1,5 @@
 from django.contrib.auth.models import User
-from django.http import HttpResponse, HttpResponseRedirect
+from django.http import HttpResponseRedirect
 from django.shortcuts import render
 from django.template.response import TemplateResponse
 from django.views.decorators.cache import cache_page
@@ -7,7 +7,7 @@
 
 def execute_sql(request):
     list(User.objects.all())
-    return HttpResponse()
+    return render(request, "base.html")
 
 
 def regular_view(request, title):
@@ -25,12 +25,12 @@
 
 def resolving_view(request, arg1, arg2):
     # see test_url_resolving in tests.py
-    return HttpResponse()
+    return render(request, "base.html")
 
 
 @cache_page(60)
 def cached_view(request):
-    return HttpResponse()
+    return render(request, "base.html")
 
 
 def regular_jinjia_view(request, title):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-debug-toolbar-2.1/tox.ini 
new/django-debug-toolbar-2.2/tox.ini
--- old/django-debug-toolbar-2.1/tox.ini        2019-11-12 09:17:34.000000000 
+0100
+++ new/django-debug-toolbar-2.2/tox.ini        2020-01-31 20:53:40.000000000 
+0100
@@ -3,22 +3,21 @@
     flake8
     style
     readme
-    py{35,36,37}-dj111
-    py{35,36,37}-dj20
-    py{35,36,37}-dj21
-    py{35,36,37}-dj22
-    py{36,37}-dj30
-    py{36,37}-djmaster
-    postgresql
-    mariadb
+    py{35,36,37}-dj111-sqlite
+    py{35,36,37,38}-dj22-sqlite
+    py{36,37,38}-dj30-sqlite
+    py{36,37,38}-djmaster-sqlite
+    py37-dj111-{postgresql,mariadb}
+    py{37,38}-dj{22,30}-{postgresql,mariadb}
 
 [testenv]
 deps =
     dj111: Django==1.11.*
-    dj20: Django==2.0.*
-    dj21: Django==2.1.*
     dj22: Django==2.2.*
-    dj30: Django>=3.0b1,<3.1
+    dj30: Django==3.0.*
+    sqlite: mock
+    postgresql: psycopg2-binary
+    mariadb: mysqlclient
     djmaster: https://github.com/django/django/archive/master.tar.gz
     coverage
     Jinja2
@@ -27,38 +26,8 @@
     sqlparse
 setenv =
     PYTHONPATH = {toxinidir}
-whitelist_externals = make
-pip_pre = True
-commands = make coverage TEST_ARGS='{posargs:tests}'
-
-[testenv:postgresql]
-deps =
-    Django==2.1.*
-    coverage
-    Jinja2
-    html5lib
-    psycopg2-binary
-    selenium<4.0
-    sqlparse
-setenv =
-    PYTHONPATH = {toxinidir}
-    DJANGO_DATABASE_ENGINE = postgresql
-whitelist_externals = make
-pip_pre = True
-commands = make coverage TEST_ARGS='{posargs:tests}'
-
-[testenv:mariadb]
-deps =
-    Django==2.1.*
-    coverage
-    Jinja2
-    html5lib
-    mysqlclient<1.4
-    selenium<4.0
-    sqlparse
-setenv =
-    PYTHONPATH = {toxinidir}
-    DJANGO_DATABASE_ENGINE = mysql
+    postgresql: DJANGO_DATABASE_ENGINE = postgresql
+    mariadb: DJANGO_DATABASE_ENGINE = mysql
 whitelist_externals = make
 pip_pre = True
 commands = make coverage TEST_ARGS='{posargs:tests}'


Reply via email to