diff options
| author | Aymeric Augustin | 2013-11-29 10:33:25 +0100 |
|---|---|---|
| committer | Aymeric Augustin | 2013-11-29 10:45:58 +0100 |
| commit | a7dbc61ec4b4932a570d538b23a3ddd1d46203d4 (patch) | |
| tree | a3b24c616ad99fb31160a96fa96e2c2563bf4dcf | |
| parent | 2135eac0d5d8e249af395db903608fd0f4bb5ce0 (diff) | |
| download | django-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.py | 47 | ||||
| -rw-r--r-- | debug_toolbar/templates/debug_toolbar/panels/profiling.html | 7 | ||||
| -rw-r--r-- | docs/panels.rst | 12 | ||||
| -rw-r--r-- | requirements_dev.txt | 4 | ||||
| -rw-r--r-- | tests/panels/test_profiling.py | 28 | ||||
| -rw-r--r-- | tox.ini | 6 |
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']) @@ -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] |
