aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAymeric Augustin2013-11-29 10:33:25 +0100
committerAymeric Augustin2013-11-29 10:45:58 +0100
commita7dbc61ec4b4932a570d538b23a3ddd1d46203d4 (patch)
treea3b24c616ad99fb31160a96fa96e2c2563bf4dcf
parent2135eac0d5d8e249af395db903608fd0f4bb5ce0 (diff)
downloaddjango-debug-toolbar-a7dbc61ec4b4932a570d538b23a3ddd1d46203d4.tar.bz2
Move support for line_profiler to a 3rd party panel.
Many thanks to Dave McLain. Fix #477.
-rw-r--r--debug_toolbar/panels/profiling.py47
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/profiling.html7
-rw-r--r--docs/panels.rst12
-rw-r--r--requirements_dev.txt4
-rw-r--r--tests/panels/test_profiling.py28
-rw-r--r--tox.ini6
6 files changed, 18 insertions, 86 deletions
diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py
index f4d32c4..eacd62c 100644
--- a/debug_toolbar/panels/profiling.py
+++ b/debug_toolbar/panels/profiling.py
@@ -2,16 +2,8 @@ from __future__ import absolute_import, division, unicode_literals
from django.utils.translation import ugettext_lazy as _
from django.utils.safestring import mark_safe
-from django.utils.six.moves import cStringIO
from debug_toolbar.panels import Panel
-try:
- from line_profiler import LineProfiler, show_func
- DJ_PROFILE_USE_LINE_PROFILER = True
-except ImportError:
- DJ_PROFILE_USE_LINE_PROFILER = False
-
-
import cProfile
from pstats import Stats
from colorsys import hsv_to_rgb
@@ -43,7 +35,6 @@ class FunctionCall(object):
self.id = id
self.parent_ids = parent_ids
self.hsv = hsv
- self._line_stats_text = None
def parent_classes(self):
return self.parent_classes
@@ -127,18 +118,6 @@ class FunctionCall(object):
def indent(self):
return 16 * self.depth
- def line_stats_text(self):
- if self._line_stats_text is None and DJ_PROFILE_USE_LINE_PROFILER:
- lstats = self.statobj.line_stats
- if self.func in lstats.timings:
- out = cStringIO()
- fn, lineno, name = self.func
- show_func(fn, lineno, name, lstats.timings[self.func], lstats.unit, stream=out)
- self._line_stats_text = out.getvalue()
- else:
- self._line_stats_text = False
- return self._line_stats_text
-
class ProfilingPanel(Panel):
"""
@@ -148,37 +127,17 @@ class ProfilingPanel(Panel):
template = 'debug_toolbar/panels/profiling.html'
- def _unwrap_closure_and_profile(self, func):
- if not hasattr(func, '__code__'):
- return
- self.line_profiler.add_function(func)
- if func.__closure__:
- for cell in func.__closure__:
- if hasattr(cell.cell_contents, '__code__'):
- self._unwrap_closure_and_profile(cell.cell_contents)
-
def process_view(self, request, view_func, view_args, view_kwargs):
self.profiler = cProfile.Profile()
args = (request,) + view_args
- if DJ_PROFILE_USE_LINE_PROFILER:
- self.line_profiler = LineProfiler()
- self._unwrap_closure_and_profile(view_func)
- self.line_profiler.enable_by_count()
- out = self.profiler.runcall(view_func, *args, **view_kwargs)
- self.line_profiler.disable_by_count()
- else:
- self.line_profiler = None
- out = self.profiler.runcall(view_func, *args, **view_kwargs)
- return out
+ return self.profiler.runcall(view_func, *args, **view_kwargs)
def add_node(self, func_list, func, max_depth, cum_time=0.1):
func_list.append(func)
func.has_subfuncs = False
if func.depth < max_depth:
for subfunc in func.subfuncs():
- if (subfunc.stats[3] >= cum_time or
- (hasattr(self.stats, 'line_stats') and
- (subfunc.func in self.stats.line_stats.timings))):
+ if subfunc.stats[3] >= cum_time:
func.has_subfuncs = True
self.add_node(func_list, subfunc, max_depth, cum_time=cum_time)
@@ -188,8 +147,6 @@ class ProfilingPanel(Panel):
# Could be delayed until the panel content is requested (perf. optim.)
self.profiler.create_stats()
self.stats = DjangoDebugToolbarStats(self.profiler)
- if DJ_PROFILE_USE_LINE_PROFILER:
- self.stats.line_stats = self.line_profiler.get_stats()
self.stats.calc_callees()
root = FunctionCall(self.stats, self.stats.get_root_func(), depth=0)
diff --git a/debug_toolbar/templates/debug_toolbar/panels/profiling.html b/debug_toolbar/templates/debug_toolbar/panels/profiling.html
index 9d34043..3800f98 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/profiling.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/profiling.html
@@ -30,13 +30,6 @@
<td>{{ call.tottime_per_call|floatformat:3 }}</td>
<td>{{ call.count }}</td>
</tr>
- {% if call.line_stats_text %}
- <tr class="djToggleDetails_{{ call.id }}{% for parent_id in call.parent_ids %} djToggleDetails_{{ parent_id }}{% endfor %}">
- <td colspan="6">
- <div style="padding-left: {{ call.indent }}px;"><pre>{{ call.line_stats_text }}</pre></div>
- </td>
- </tr>
- {% endif %}
{% endfor %}
</tbody>
</table>
diff --git a/docs/panels.rst b/docs/panels.rst
index c766780..b82be1a 100644
--- a/docs/panels.rst
+++ b/docs/panels.rst
@@ -155,6 +155,18 @@ Retrieves and displays information you specify using the ``debug`` statement.
Inspector panel also logs to the console by default, but may be instructed not
to.
+Line Profiler
+~~~~~~~~~~~~~
+
+URL: https://github.com/dmclain/django-debug-toolbar-line-profiler
+
+Path: ``debug_toolbar_line_profiler.panel.ProfilingPanel``
+
+This package provides a profiling panel that incorporates output from
+line_profiler_.
+
+.. _line_profiler: http://pythonhosted.org/line_profiler/
+
Memcache
~~~~~~~~
diff --git a/requirements_dev.txt b/requirements_dev.txt
index 7912ecf..8d7af92 100644
--- a/requirements_dev.txt
+++ b/requirements_dev.txt
@@ -7,10 +7,6 @@
Django
sqlparse
-# Optional runtime dependencies
-
-line_profiler
-
# Testing
coverage
diff --git a/tests/panels/test_profiling.py b/tests/panels/test_profiling.py
index 7e61c62..3353b98 100644
--- a/tests/panels/test_profiling.py
+++ b/tests/panels/test_profiling.py
@@ -6,13 +6,6 @@ from django.test import TestCase
from django.test.utils import override_settings
from django.utils import unittest
-try:
- import line_profiler
-except ImportError:
- line_profiler = None
-
-from debug_toolbar.panels import profiling
-
from ..base import BaseTestCase
from ..views import regular_view
@@ -24,28 +17,15 @@ class ProfilingPanelTestCase(BaseTestCase):
super(ProfilingPanelTestCase, self).setUp()
self.panel = self.toolbar.get_panel_by_id('ProfilingPanel')
- def _test_render_with_or_without_line_profiler(self):
+ # This test fails randomly for a reason I don't understand.
+
+ @unittest.expectedFailure
+ def test_regular_view(self):
self.panel.process_view(self.request, regular_view, ('profiling',), {})
self.panel.process_response(self.request, self.response)
self.assertIn('func_list', self.panel.get_stats())
self.assertIn('regular_view', self.panel.content)
- # These two tests fail randomly for a reason I don't understand.
-
- @unittest.expectedFailure
- @unittest.skipIf(line_profiler is None, "line_profiler isn't available")
- def test_render_with_line_profiler(self):
- self._test_render_with_or_without_line_profiler()
-
- @unittest.expectedFailure
- def test_without_line_profiler(self):
- _use_line_profiler = profiling.DJ_PROFILE_USE_LINE_PROFILER
- profiling.DJ_PROFILE_USE_LINE_PROFILER = False
- try:
- self._test_render_with_or_without_line_profiler()
- finally:
- profiling.DJ_PROFILE_USE_LINE_PROFILER = _use_line_profiler
-
@override_settings(DEBUG=True,
DEBUG_TOOLBAR_PANELS=['debug_toolbar.panels.profiling.ProfilingPanel'])
diff --git a/tox.ini b/tox.ini
index c40e711..00941f4 100644
--- a/tox.ini
+++ b/tox.ini
@@ -25,28 +25,24 @@ whitelist_externals = make
basepython = python2.6
deps =
Django>=1.4,<1.5
- line_profiler
{[testenv]deps}
[testenv:py27-django14]
basepython = python2.7
deps =
Django>=1.4,<1.5
- line_profiler
{[testenv]deps}
[testenv:py26-django15]
basepython = python2.6
deps =
Django>=1.5,<1.6
- line_profiler
{[testenv]deps}
[testenv:py27-django15]
basepython = python2.7
deps =
Django>=1.5,<1.6
- line_profiler
{[testenv]deps}
[testenv:py32-django15]
@@ -65,14 +61,12 @@ deps =
basepython = python2.6
deps =
Django>=1.6,<1.7
- line_profiler
{[testenv]deps}
[testenv:py27-django16]
basepython = python2.7
deps =
Django>=1.6,<1.7
- line_profiler
{[testenv]deps}
[testenv:py32-django16]