diff --git a/.gitignore b/.gitignore index d704fe3..fa12b50 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ docs/_build example/db.sqlite3 htmlcov .tox +.idea/ +*.egg-info/ diff --git a/MANIFEST.in b/MANIFEST.in index 02b2e0a..58d8423 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,3 @@ include LICENSE include README.rst recursive-include debug_toolbar_line_profiler/templates * -recursive-include debug_toolbar_line_profiler/static * diff --git a/debug_toolbar_line_profiler/panel.py b/debug_toolbar_line_profiler/panel.py index 3aa8be4..a7db79e 100644 --- a/debug_toolbar_line_profiler/panel.py +++ b/debug_toolbar_line_profiler/panel.py @@ -7,9 +7,13 @@ from pstats import Stats from six import PY2 +from django.urls import resolve from django.utils.translation import ugettext_lazy as _ from django.utils.safestring import mark_safe -from django.utils.six.moves import cStringIO +try: + from django.utils.six.moves import cStringIO +except ImportError: + from io import StringIO as cStringIO from debug_toolbar.panels import Panel from django.views.generic.base import View @@ -26,7 +30,7 @@ def get_root_func(self, view_func): filename = view_func.__code__.co_filename firstlineno = view_func.__code__.co_firstlineno for func, (cc, nc, tt, ct, callers) in self.stats.items(): - if (len(callers) == 0 + if (len(callers) >= 0 and func[0] == filename and func[1] == firstlineno): self.__root = func @@ -76,7 +80,9 @@ def func_std_string(self): # match what old profile produced if idx > -1: file_name = file_name[(idx + 14):] - file_path, file_name = file_name.rsplit(os.sep, 1) + file_items = file_name.rsplit(os.sep, 1) + file_path, file_name = file_items if len(file_items) > 1 else [ + None, file_name] return mark_safe( '{0}/' @@ -165,8 +171,11 @@ class ProfilingPanel(Panel): template = 'debug_toolbar_line_profiler/panels/profiling.html' def _unwrap_closure_and_profile(self, func): - if not hasattr(func, '__code__'): + if not hasattr(func, '__code__') or func in self.added: return + + self.added.add(func) + self.line_profiler.add_function(func) for subfunc in getattr(func, 'profile_additional', []): self._unwrap_closure_and_profile(subfunc) @@ -182,22 +191,26 @@ def _unwrap_closure_and_profile(self, func): self._unwrap_closure_and_profile(cell.cell_contents) if inspect.isclass(target) and View in inspect.getmro(target): for name, value in inspect.getmembers(target): - if name[0] != '_' and inspect.ismethod(value): + if not name.startswith('__') and ( + inspect.ismethod(value) or + inspect.isfunction(value) + ): self._unwrap_closure_and_profile(value) - def process_view(self, request, view_func, view_args, view_kwargs): + def process_request(self, request): + view_func, view_args, view_kwargs = resolve(request.path) self.view_func = view_func self.profiler = cProfile.Profile() - args = (request,) + view_args self.line_profiler = LineProfiler() - self._unwrap_closure_and_profile(view_func) + self.added = set() + self._unwrap_closure_and_profile(self.view_func) signals.profiler_setup.send(sender=self, profiler=self.line_profiler, view_func=view_func, view_args=view_args, view_kwargs=view_kwargs) self.line_profiler.enable_by_count() - out = self.profiler.runcall(view_func, *args, **view_kwargs) + out = self.profiler.runcall(super().process_request, request) self.line_profiler.disable_by_count() return out @@ -238,7 +251,7 @@ def add_node(self, func_list, func, max_depth, cum_time=0.1): max_depth=max_depth, cum_time=subfunc.cumtime()/16) - def process_response(self, request, response): + def generate_stats(self, request, response): if not hasattr(self, 'profiler'): return None # Could be delayed until the panel content is requested (perf. optim.) diff --git a/debug_toolbar_line_profiler/static/debug_toolbar_line_profiler/js/toolbar.profiling.js b/debug_toolbar_line_profiler/static/debug_toolbar_line_profiler/js/toolbar.profiling.js deleted file mode 100644 index 172c2a6..0000000 --- a/debug_toolbar_line_profiler/static/debug_toolbar_line_profiler/js/toolbar.profiling.js +++ /dev/null @@ -1,27 +0,0 @@ -(function (factory) { - if (typeof define === 'function' && define.amd) { - define(['jquery'], factory); - } else { - factory(jQuery); - } -}(function ($) { - function getSubcalls(row) { - var id = row.attr('id'); - return $('.djDebugProfileRow[id^="'+id+'_"]'); - } - function getDirectSubcalls(row) { - var subcalls = getSubcalls(row); - var depth = parseInt(row.attr('depth'), 10) + 1; - return subcalls.filter('[depth='+depth+']'); - } - $('.djDebugProfileRow .djDebugProfileToggle').on('click', function(){ - var row = $(this).closest('.djDebugProfileRow'); - var subcalls = getSubcalls(row); - if (subcalls.css('display') == 'none') { - getDirectSubcalls(row).show(); - } else { - subcalls.hide(); - } - }); - -})); diff --git a/debug_toolbar_line_profiler/templates/debug_toolbar_line_profiler/panels/profiling.html b/debug_toolbar_line_profiler/templates/debug_toolbar_line_profiler/panels/profiling.html index 442437b..716f31f 100644 --- a/debug_toolbar_line_profiler/templates/debug_toolbar_line_profiler/panels/profiling.html +++ b/debug_toolbar_line_profiler/templates/debug_toolbar_line_profiler/panels/profiling.html @@ -1,4 +1,4 @@ -{% load i18n %}{% load static from staticfiles %} +{% load i18n %}{% load static %} @@ -13,11 +13,11 @@ {% for call in func_list %} - +
{% if call.has_subfuncs %} - - + - {% else %} {% endif %} @@ -40,5 +40,3 @@ {% endfor %}
- - diff --git a/setup.py b/setup.py index 5b136de..d0a64e9 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='django-debug-toolbar-line-profiler', - version='0.6.1', + version='0.7.1', description='A panel for django-debug-toolbar that integrates ' + 'information from line_profiler', long_description=open('README.rst').read(), @@ -13,7 +13,7 @@ license='BSD', packages=find_packages(exclude=('tests', 'example')), install_requires=[ - 'django-debug-toolbar>=1.0', + 'django-debug-toolbar>=2.0', 'line_profiler>=1.0b3', 'six>=1.10', ], @@ -31,6 +31,7 @@ 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.7', 'Topic :: Software Development :: Libraries :: Python Modules', ], )