Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions debug_toolbar/panels/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from django.core.cache import cache as original_cache, get_cache as original_get_cache
from django.core.cache.backends.base import BaseCache
from django.dispatch import Signal
from django.template import Node
from django.utils.translation import ugettext_lazy as _, ungettext
try:
from collections import OrderedDict
Expand Down Expand Up @@ -37,19 +36,7 @@ def wrapped(self, *args, **kwargs):
else:
stacktrace = []

template_info = None
cur_frame = sys._getframe().f_back
try:
while cur_frame is not None:
if cur_frame.f_code.co_name == 'render':
node = cur_frame.f_locals['self']
if isinstance(node, Node):
template_info = get_template_info(node.source)
break
cur_frame = cur_frame.f_back
except Exception:
pass
del cur_frame
template_info = get_template_info()
cache_called.send(sender=self.__class__, time_taken=t,
name=method.__name__, return_value=value,
args=args, kwargs=kwargs, trace=stacktrace,
Expand Down
17 changes: 1 addition & 16 deletions debug_toolbar/panels/sql/tracking.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
from __future__ import absolute_import, unicode_literals

import sys

import json
from threading import local
from time import time

from django.template import Node
from django.utils.encoding import force_text
from django.utils import six

Expand Down Expand Up @@ -115,19 +112,7 @@ def _record(self, method, sql, params):
except Exception:
pass # object not JSON serializable

template_info = None
cur_frame = sys._getframe().f_back
try:
while cur_frame is not None:
if cur_frame.f_code.co_name == 'render':
node = cur_frame.f_locals['self']
if isinstance(node, Node):
template_info = get_template_info(node.source)
break
cur_frame = cur_frame.f_back
except Exception:
pass
del cur_frame
template_info = get_template_info()

alias = getattr(self.db, 'alias', 'default')
conn = self.db.connection
Expand Down
30 changes: 29 additions & 1 deletion debug_toolbar/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import django
from django.core.exceptions import ImproperlyConfigured
from django.template import Node
from django.utils.encoding import force_text
from django.utils.html import escape
from django.utils.safestring import mark_safe
Expand Down Expand Up @@ -86,7 +87,34 @@ def render_stacktrace(trace):
return mark_safe('\n'.join(stacktrace))


def get_template_info(source, context_lines=3):
def get_template_info():
template_info = None
cur_frame = sys._getframe().f_back
try:
while cur_frame is not None:
in_utils_module = cur_frame.f_code.co_filename.endswith(
"/debug_toolbar/utils.py"
)
is_get_template_context = (
cur_frame.f_code.co_name == get_template_context.__name__
)
if in_utils_module and is_get_template_context:
# If the method in the stack trace is this one
# then break from the loop as it's being check recursively.
break
elif cur_frame.f_code.co_name == 'render':
node = cur_frame.f_locals['self']
if isinstance(node, Node):
template_info = get_template_context(node.source)
break
cur_frame = cur_frame.f_back
except Exception:
pass
del cur_frame
return template_info


def get_template_context(source, context_lines=3):
line = 0
upto = 0
source_lines = []
Expand Down
10 changes: 10 additions & 0 deletions tests/loaders.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from django.contrib.auth.models import User
from django.template.loaders.app_directories import Loader


class LoaderWithSQL(Loader):
def load_template_source(self, template_name, template_dirs=None):
# Force the template loader to run some SQL. Simulates a CMS.
User.objects.all().count()
return super(LoaderWithSQL, self).load_template_source(
template_name, template_dirs=template_dirs)
30 changes: 30 additions & 0 deletions tests/panels/test_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

from __future__ import absolute_import, unicode_literals

import django
from django.contrib.auth.models import User
from django.db import connection
from django.db.utils import DatabaseError
from django.shortcuts import render
from django.utils import unittest
from django.test.utils import override_settings

from ..base import BaseTestCase

Expand Down Expand Up @@ -84,3 +87,30 @@ def test_disable_stacktraces(self):

# ensure the stacktrace is empty
self.assertEqual([], query[1]['stacktrace'])

@unittest.skipIf(django.VERSION < (1, 5),
"Django 1.4 loads the TEMPLATE_LOADERS before "
"override_settings can modify the settings.")
@override_settings(DEBUG=True, TEMPLATE_DEBUG=True,
TEMPLATE_LOADERS=('tests.loaders.LoaderWithSQL',))
def test_regression_infinite_recursion(self):
"""
Test case for when the template loader runs a SQL query that causes
an infinite recursion in the SQL panel.
"""
self.assertEqual(len(self.panel._queries), 0)

render(self.request, "basic.html", {})

# ensure queries were logged
# It's more than one because the SQL run in the loader is run every time
# the template is rendered which is more than once.
self.assertEqual(len(self.panel._queries), 3)
query = self.panel._queries[0]
self.assertEqual(query[0], 'default')
self.assertTrue('sql' in query[1])
self.assertTrue('duration' in query[1])
self.assertTrue('stacktrace' in query[1])

# ensure the stacktrace is populated
self.assertTrue(len(query[1]['stacktrace']) > 0)
9 changes: 9 additions & 0 deletions tests/templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
10 changes: 2 additions & 8 deletions tests/templates/basic.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
</body>
</html>
{% extends "base.html" %}
{% block content %}Test for {{ title }}{% endblock %}