From efed434a9a70d836371100504fa990d9b378d932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Sat, 16 Jan 2021 16:22:44 +0100 Subject: [PATCH 1/2] profile also all methods of view class --- template_profiler_panel/panels/template.py | 46 +++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/template_profiler_panel/panels/template.py b/template_profiler_panel/panels/template.py index 5602930..136dd5c 100644 --- a/template_profiler_panel/panels/template.py +++ b/template_profiler_panel/panels/template.py @@ -1,5 +1,6 @@ import inspect from collections import defaultdict +from collections.abc import Callable from time import time import wrapt @@ -7,6 +8,8 @@ from debug_toolbar.panels.sql.utils import contrasting_color_generator import django from django.dispatch import Signal +from django.urls import resolve + if django.VERSION < (3, 2): from django.utils.translation import ugettext_lazy as _ @@ -23,6 +26,28 @@ node_element_colors = {} +@wrapt.decorator +def profile_method(wrapped, instance, args, kwargs): + start = time() + + result = wrapped(*args, **kwargs) + end = time() + + instance_name = ( + (wrapped.__self__.__class__.__name__ + ".") + if hasattr(wrapped, '__self__') else "" + ) + wrapped.__name__ + template_rendered.send( + sender=instance.__class__, + instance=instance_name, + start=start, + end=end, + processing_timeline=[], + level=1, + ) + return result + + def get_nodelist_timeline(nodelist, level): timeline = [] for node in nodelist: @@ -77,6 +102,22 @@ def __init__(self, *args, **kwargs): have_monkey_patched_template_classes = False + def generate_stats(self, request, response): + match = resolve(request.path) + func, args, kwargs = match + view_class = getattr(func, 'view_class', None) + if view_class and not hasattr(view_class, '_profile_enabled'): + print(view_class) + view_class._profile_enabled = True + for attr in view_class.__dict__: + print(attr) + if isinstance(getattr(view_class, attr), Callable): + setattr( + view_class, + attr, + profile_method(getattr(view_class, attr)), + ) + @classmethod def monkey_patch_template_classes(cls): if cls.have_monkey_patched_template_classes: @@ -160,7 +201,10 @@ def record(self, instance, start, end, level, if not self.enabled: return - template_name = instance.name + try: + template_name = instance.name + except AttributeError: + template_name = instance # Logic copied from django-debug-toolbar: # https://github.com/jazzband/django-debug-toolbar/blob/5d095f66fde8f10b45a93c0b35be0a85762b0458/debug_toolbar/panels/templates/panel.py#L77 is_skipped_template = isinstance(template_name, str) and ( From 9d73dd07be163da04dec85efd78e96701833e10c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Mon, 18 Jan 2021 14:13:07 +0100 Subject: [PATCH 2/2] add with profile block --- template_profiler_panel/panels/template.py | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/template_profiler_panel/panels/template.py b/template_profiler_panel/panels/template.py index 136dd5c..7295508 100644 --- a/template_profiler_panel/panels/template.py +++ b/template_profiler_panel/panels/template.py @@ -28,6 +28,16 @@ @wrapt.decorator def profile_method(wrapped, instance, args, kwargs): + """ + + Profile method decorator + Usage: + + from template_profiler_panel.panels.template import profile_method + @profile method + def method(): + ... + """ start = time() result = wrapped(*args, **kwargs) @@ -48,6 +58,34 @@ def profile_method(wrapped, instance, args, kwargs): return result +class Profile: + """ + Profile with block + Usage: + + from template_profiler_panel.panels.template import Profile + with Profile("block name"): + ... + """ + def __init__(self, name="Profile with", *args, **kwargs): + self.name = name + + def __enter__(self): + self.start = time() + + def __exit__(self, type, value, traceback): + self.end = time() + + template_rendered.send( + sender=self.__class__, + instance=self.name, + start=self.start, + end=self.end, + processing_timeline=[], + level=1, + ) + + def get_nodelist_timeline(nodelist, level): timeline = [] for node in nodelist: