diff --git a/.gitignore b/.gitignore index 36c0b885a..f6e7900c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.pyc *.DS_Store *~ -django_debug_toolbar.egg-info \ No newline at end of file +django_debug_toolbar.egg-info +.idea/* \ No newline at end of file diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index e1e9bdf9c..0689dda67 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -12,7 +12,7 @@ from django.template import Node from django.template.loader import render_to_string from django.utils import simplejson -from django.utils.encoding import force_unicode +from django.utils.encoding import force_unicode, DjangoUnicodeDecodeError from django.utils.hashcompat import sha_constructor from django.utils.translation import ugettext_lazy as _ @@ -85,6 +85,22 @@ class DatabaseStatTracker(util.CursorDebugWrapper): Replacement for CursorDebugWrapper which stores additional information in `connection.queries`. """ + def clean_params(self, params): + clean_params = () + + for x in params: + try: + clean_params += (force_unicode(x, strings_only=True), ) + except DjangoUnicodeDecodeError: + clean_params += ("", ) + return clean_params + + def get_params_json(self, clean_params): + try: + return simplejson.dumps(clean_params) + except TypeError: + return '' # object not JSON serializable + def execute(self, sql, params=()): start = datetime.now() try: @@ -93,12 +109,8 @@ def execute(self, sql, params=()): stop = datetime.now() duration = ms_from_timedelta(stop - start) stacktrace = tidy_stacktrace(traceback.extract_stack()) - _params = '' - try: - _params = simplejson.dumps([force_unicode(x, strings_only=True) for x in params]) - except TypeError: - pass # object not JSON serializable - + params = self.clean_params(params) + _params = self.get_params_json(params) template_info = None cur_frame = sys._getframe().f_back try: diff --git a/debug_toolbar/tests/__init__.py b/debug_toolbar/tests/__init__.py new file mode 100644 index 000000000..f70abd883 --- /dev/null +++ b/debug_toolbar/tests/__init__.py @@ -0,0 +1 @@ +from debug_toolbar.tests.test_sql_panel import * diff --git a/debug_toolbar/tests/test_sql_panel.py b/debug_toolbar/tests/test_sql_panel.py new file mode 100644 index 000000000..fbb2fc885 --- /dev/null +++ b/debug_toolbar/tests/test_sql_panel.py @@ -0,0 +1,24 @@ +from mock import patch, Mock + +from django.test import TestCase +from django.utils.encoding import DjangoUnicodeDecodeError + +from debug_toolbar.panels.sql import DatabaseStatTracker + +class DatabaseStatTrackerTests(TestCase): + + def setUp(self): + self.tracker = DatabaseStatTracker(Mock(), Mock()) + self.tracker.db.queries = [] + + @patch('debug_toolbar.panels.sql.force_unicode') + def test_execute_gracefully_handles_nonunicode_params(self, force_unicode): + force_unicode.side_effect = DjangoUnicodeDecodeError("", "", "", 1, 1, "") + self.tracker.execute('some sql', ('param1', )) + self.assertEqual('[""]', self.tracker.db.queries[0]['params']) + + @patch('debug_toolbar.panels.sql.simplejson.dumps') + def test_execute_gracefully_handles_non_json_serializable_objects(self, dumps): + dumps.side_effect = TypeError('not jsonable') + self.tracker.execute('some sql', ('param1', )) + self.assertEqual('', self.tracker.db.queries[0]['params']) \ No newline at end of file