From 07d042398fb47894d89918206f6c80c42838a300 Mon Sep 17 00:00:00 2001 From: Matthew J Morrison Date: Wed, 8 Dec 2010 08:42:57 -0600 Subject: [PATCH 01/11] added clean_params method to DatabaseStatTracker to scrub non-unicode data for displaying on the sql panel --- debug_toolbar/panels/sql.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index e1e9bdf9c..299da6685 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,12 +85,24 @@ 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: + force_unicode(x, strings_only=True) + except DjangoUnicodeDecodeError: + clean_params += ("", ) + else: + clean_params += (x, ) + return clean_params + def execute(self, sql, params=()): start = datetime.now() try: return self.cursor.execute(sql, params) finally: stop = datetime.now() + params = self.clean_params(params) duration = ms_from_timedelta(stop - start) stacktrace = tidy_stacktrace(traceback.extract_stack()) _params = '' From 278d70affb9d720e25e54b4f04913150fa0b0c2c Mon Sep 17 00:00:00 2001 From: Matthew J Morrison Date: Wed, 8 Dec 2010 08:47:20 -0600 Subject: [PATCH 02/11] changed version to dev --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6051fad63..93ed84b50 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='django-debug-toolbar', - version=__import__('debug_toolbar').__version__, + version='dev', description='A configurable set of panels that display various debug information about the current request/response.', long_description=open('README.rst').read(), # Get more strings from http://www.python.org/pypi?:action=list_classifiers From 14a05031d396aeeca16ca4fc317eb97062376629 Mon Sep 17 00:00:00 2001 From: Matthew J Morrison Date: Wed, 8 Dec 2010 19:39:01 -0600 Subject: [PATCH 03/11] removed duplicate call to force_urlencode --- debug_toolbar/panels/sql.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index 299da6685..08215d079 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -89,12 +89,13 @@ def clean_params(self, params): clean_params = () for x in params: try: - force_unicode(x, strings_only=True) + clean_params += (force_unicode(x, strings_only=True), ) except DjangoUnicodeDecodeError: clean_params += ("", ) - else: - clean_params += (x, ) - return clean_params + try: + return simplejson.dumps(clean_params) + except TypeError: + pass # object not JSON serializable def execute(self, sql, params=()): start = datetime.now() @@ -102,14 +103,9 @@ def execute(self, sql, params=()): return self.cursor.execute(sql, params) finally: stop = datetime.now() - params = self.clean_params(params) 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) template_info = None cur_frame = sys._getframe().f_back From 6f9391d57800cf998ff49889dc147fe96ae6d1f5 Mon Sep 17 00:00:00 2001 From: Matthew J Morrison Date: Thu, 9 Dec 2010 07:51:59 -0600 Subject: [PATCH 04/11] fixed unexpected indent --- debug_toolbar/panels/sql.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index 08215d079..e40114ea9 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -92,10 +92,10 @@ def clean_params(self, params): clean_params += (force_unicode(x, strings_only=True), ) except DjangoUnicodeDecodeError: clean_params += ("", ) - try: - return simplejson.dumps(clean_params) - except TypeError: - pass # object not JSON serializable + try: + return simplejson.dumps(clean_params) + except TypeError: + pass # object not JSON serializable def execute(self, sql, params=()): start = datetime.now() @@ -105,7 +105,7 @@ def execute(self, sql, params=()): stop = datetime.now() duration = ms_from_timedelta(stop - start) stacktrace = tidy_stacktrace(traceback.extract_stack()) - _params = self.clean_params(params) + _params = self.clean_params(params) template_info = None cur_frame = sys._getframe().f_back From 4a3ce90da52365b974d4dfebe3d489a7c5490561 Mon Sep 17 00:00:00 2001 From: Matthew J Morrison Date: Thu, 9 Dec 2010 08:06:53 -0600 Subject: [PATCH 05/11] extracted get_params_json method from clean_params --- debug_toolbar/panels/sql.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index e40114ea9..2b77bfaae 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -87,11 +87,16 @@ class DatabaseStatTracker(util.CursorDebugWrapper): """ 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: @@ -105,7 +110,8 @@ def execute(self, sql, params=()): stop = datetime.now() duration = ms_from_timedelta(stop - start) stacktrace = tidy_stacktrace(traceback.extract_stack()) - _params = self.clean_params(params) + params = self.clean_params(params) + _params = self.get_params_json(params) template_info = None cur_frame = sys._getframe().f_back From cff86ec3e735849ad9b3968411f4d78496d9ffe7 Mon Sep 17 00:00:00 2001 From: Matthew J Morrison Date: Thu, 9 Dec 2010 08:11:46 -0600 Subject: [PATCH 06/11] removed "dev" from version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 93ed84b50..6051fad63 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='django-debug-toolbar', - version='dev', + version=__import__('debug_toolbar').__version__, description='A configurable set of panels that display various debug information about the current request/response.', long_description=open('README.rst').read(), # Get more strings from http://www.python.org/pypi?:action=list_classifiers From d6a3e02e42e5ce368f0fc6ddc10d2890ef2c612f Mon Sep 17 00:00:00 2001 From: Matthew J Morrison Date: Thu, 9 Dec 2010 17:49:15 -0600 Subject: [PATCH 07/11] added .idea to .gitignore for Pycharm --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 From fa6bc37cbe17ce9846d39340765a759c2b59903c Mon Sep 17 00:00:00 2001 From: Matthew J Morrison Date: Thu, 9 Dec 2010 17:53:22 -0600 Subject: [PATCH 08/11] added test case for DatabaseStatTracker --- debug_toolbar/panels/sql.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index 08215d079..e40114ea9 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -92,10 +92,10 @@ def clean_params(self, params): clean_params += (force_unicode(x, strings_only=True), ) except DjangoUnicodeDecodeError: clean_params += ("", ) - try: - return simplejson.dumps(clean_params) - except TypeError: - pass # object not JSON serializable + try: + return simplejson.dumps(clean_params) + except TypeError: + pass # object not JSON serializable def execute(self, sql, params=()): start = datetime.now() @@ -105,7 +105,7 @@ def execute(self, sql, params=()): stop = datetime.now() duration = ms_from_timedelta(stop - start) stacktrace = tidy_stacktrace(traceback.extract_stack()) - _params = self.clean_params(params) + _params = self.clean_params(params) template_info = None cur_frame = sys._getframe().f_back From 16c413a9b45f66ac1ec593eb92547a37518c7b29 Mon Sep 17 00:00:00 2001 From: Matthew J Morrison Date: Thu, 9 Dec 2010 17:55:59 -0600 Subject: [PATCH 09/11] added tests for DatabaseStatTracker --- debug_toolbar/tests/__init__.py | 1 + debug_toolbar/tests/test_sql_panel.py | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 debug_toolbar/tests/__init__.py create mode 100644 debug_toolbar/tests/test_sql_panel.py 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..f2c9c34df --- /dev/null +++ b/debug_toolbar/tests/test_sql_panel.py @@ -0,0 +1,5 @@ +from django.test import TestCase + + +class DatabaseStatTrackerTests(TestCase): + pass \ No newline at end of file From 30bb9b3cc8c80a941e541451e4a7942fe56b414b Mon Sep 17 00:00:00 2001 From: Matthew J Morrison Date: Sat, 11 Dec 2010 21:58:38 -0600 Subject: [PATCH 10/11] added tests for non-unicode param error --- debug_toolbar/panels/sql.py | 2 +- debug_toolbar/tests/test_sql_panel.py | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index 8f4748cff..0689dda67 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -99,7 +99,7 @@ def get_params_json(self, clean_params): try: return simplejson.dumps(clean_params) except TypeError: - pass # object not JSON serializable + return '' # object not JSON serializable def execute(self, sql, params=()): start = datetime.now() diff --git a/debug_toolbar/tests/test_sql_panel.py b/debug_toolbar/tests/test_sql_panel.py index f2c9c34df..fbb2fc885 100644 --- a/debug_toolbar/tests/test_sql_panel.py +++ b/debug_toolbar/tests/test_sql_panel.py @@ -1,5 +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): - pass \ No newline at end of file + + 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 From 304a68d21d0a96d1a0c21a073e007941456b23c5 Mon Sep 17 00:00:00 2001 From: Matthew J Morrison Date: Sat, 11 Dec 2010 22:00:25 -0600 Subject: [PATCH 11/11] changed version back to original --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 93ed84b50..6051fad63 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='django-debug-toolbar', - version='dev', + version=__import__('debug_toolbar').__version__, description='A configurable set of panels that display various debug information about the current request/response.', long_description=open('README.rst').read(), # Get more strings from http://www.python.org/pypi?:action=list_classifiers