From 0cb4aae6e103ccc31008132b90c7f329e3b33638 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Sat, 6 Sep 2014 00:58:05 +0200 Subject: [PATCH] Cache is_django_render_call in PyDBFrame object (the same for Jinja). --- python/helpers/pydev/pydev_log.py | 9 ++++++- .../pydev/pydevd_additional_thread_info.py | 1 - python/helpers/pydev/pydevd_breakpoints.py | 2 +- python/helpers/pydev/pydevd_frame.py | 21 +++++----------- python/helpers/pydev/pydevd_frame_utils.py | 22 +++++++++++++++-- python/helpers/pydev/pydevd_plugin_utils.py | 2 +- .../pydev/pydevd_plugins/django_debug.py | 24 ++++++++----------- .../pydev/pydevd_plugins/jinja2_debug.py | 20 +++++++++------- 8 files changed, 58 insertions(+), 43 deletions(-) diff --git a/python/helpers/pydev/pydev_log.py b/python/helpers/pydev/pydev_log.py index 229784b76a91..b5e65b3102e6 100644 --- a/python/helpers/pydev/pydev_log.py +++ b/python/helpers/pydev/pydev_log.py @@ -2,6 +2,8 @@ import sys from pydevd_constants import DebugInfoHolder from pydevd_constants import DictContains +import traceback + WARN_ONCE_MAP = {} def stderr_write(message): @@ -18,11 +20,16 @@ def warn(message): if DebugInfoHolder.DEBUG_TRACE_LEVEL>1: stderr_write(message) + def info(message): stderr_write(message) -def error(message): + +def error(message, tb=False): stderr_write(message) + if tb: + traceback.print_exc() + def error_once(message): if not DictContains(WARN_ONCE_MAP, message): diff --git a/python/helpers/pydev/pydevd_additional_thread_info.py b/python/helpers/pydev/pydevd_additional_thread_info.py index 76fb49ed1986..7662387b0994 100644 --- a/python/helpers/pydev/pydevd_additional_thread_info.py +++ b/python/helpers/pydev/pydevd_additional_thread_info.py @@ -101,7 +101,6 @@ class PyDBAdditionalThreadInfoWithoutCurrentFramesSupport(AbstractPyDBAdditional #1. we can't have weak-references to python frame object #2. only from 2.5 onwards we have _current_frames support from the interpreter db_frame = PyDBFrame(args) - db_frame.frame = args[-1] self._AddDbFrame(db_frame) return db_frame diff --git a/python/helpers/pydev/pydevd_breakpoints.py b/python/helpers/pydev/pydevd_breakpoints.py index 1171157257e9..693823917a2f 100644 --- a/python/helpers/pydev/pydevd_breakpoints.py +++ b/python/helpers/pydev/pydevd_breakpoints.py @@ -40,8 +40,8 @@ class ExceptionBreakpoint: def __str__(self): return self.qname -class LineBreakpoint: +class LineBreakpoint(object): def __init__(self, line, condition, func_name, expression): self.line = line self.condition = condition diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py index c54ebc191f8d..f106318c9872 100644 --- a/python/helpers/pydev/pydevd_frame.py +++ b/python/helpers/pydev/pydevd_frame.py @@ -10,7 +10,8 @@ from pydevd_comm import CMD_STEP_CAUGHT_EXCEPTION, CMD_STEP_RETURN, CMD_STEP_OVE from pydevd_constants import * # @UnusedWildImport from pydevd_file_utils import GetFilenameAndBase -from pydevd_frame_utils import add_exception_to_frame +from pydevd_frame_utils import add_exception_to_frame, just_raised + try: from pydevd_signature import sendSignatureCallTrace except ImportError: @@ -43,6 +44,7 @@ class PyDBFrame: def __init__(self, args): #args = mainDebugger, filename, base, info, t, frame #yeap, much faster than putting in self and then getting it from self later on + self.frame = args[-1] self._args = args[:-1] def setSuspend(self, *args, **kwargs): @@ -51,17 +53,6 @@ class PyDBFrame: def doWaitSuspend(self, *args, **kwargs): self._args[0].doWaitSuspend(*args, **kwargs) - def _is_django_render_call(self, frame): # todo: cache in plugins the same way - try: - return self._cached_is_django_render_call - except: - # Calculate lazily: note that a PyDBFrame always deals with the same - # frame over and over, so, we can cache this. - # -- although we can't cache things which change over time (such as - # the breakpoints for the file). - ret = self._cached_is_django_render_call = is_django_render_call(frame) - return ret - def trace_exception(self, frame, event, arg): if event == 'exception': flag, frame = self.should_stop_on_exception(frame, event, arg) @@ -93,7 +84,7 @@ class PyDBFrame: flag = False else: try: - result = mainDebugger.plugin_exception_break(self, frame, event, self._args, arg) + result = mainDebugger.plugin_exception_break(self, self._args, arg) if result: (flag, frame) = result @@ -280,7 +271,7 @@ class PyDBFrame: or (step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and stop_frame is not frame) if can_skip: - can_skip = main_debugger.plugin_can_skip(frame) + can_skip = main_debugger.plugin_can_skip(self) # Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint, # we will return nothing for the next trace @@ -335,7 +326,7 @@ class PyDBFrame: if info.pydev_step_cmd == CMD_STEP_OVER and info.pydev_step_stop is frame and event in ('line', 'return'): stop_info['stop'] = False #we don't stop on breakpoint if we have to stop by step-over (it will be processed later) else: - result = main_debugger.plugin_get_breakpoint(frame, event, self._args) + result = main_debugger.plugin_get_breakpoint(self, event, self._args) if result: exist_result = True (flag, breakpoint, new_frame) = result diff --git a/python/helpers/pydev/pydevd_frame_utils.py b/python/helpers/pydev/pydevd_frame_utils.py index 0202d6246cc9..0c9e8446d19c 100644 --- a/python/helpers/pydev/pydevd_frame_utils.py +++ b/python/helpers/pydev/pydevd_frame_utils.py @@ -1,4 +1,4 @@ -class Frame: +class Frame(object): def __init__( self, f_back, @@ -17,10 +17,28 @@ class Frame: if self.f_globals is None: self.f_globals = {} -class FCode: + +class FCode(object): def __init__(self, name, filename): self.co_name = name self.co_filename = filename + def add_exception_to_frame(frame, exception_info): frame.f_locals['__exception__'] = exception_info + + +def just_raised(trace): + if trace is None: + return False + return trace.tb_next is None + + +def cached_call(obj, func, *args): + cached_name = '_cached_' + func.__name__ + if not hasattr(obj, cached_name): + setattr(obj, cached_name, func(*args)) + + return getattr(obj, cached_name) + + diff --git a/python/helpers/pydev/pydevd_plugin_utils.py b/python/helpers/pydev/pydevd_plugin_utils.py index 5c63de8d257c..52297e90eaa5 100644 --- a/python/helpers/pydev/pydevd_plugin_utils.py +++ b/python/helpers/pydev/pydevd_plugin_utils.py @@ -15,7 +15,7 @@ def load_plugins(package): try: loaded_plugin = plugin_source.load_plugin(plugin) except: - pydev_log.error("Failed to load plugin %s" % plugin) + pydev_log.error("Failed to load plugin %s" % plugin, True) if loaded_plugin: plugins.append(loaded_plugin) diff --git a/python/helpers/pydev/pydevd_plugins/django_debug.py b/python/helpers/pydev/pydevd_plugins/django_debug.py index 64835d775908..6785b50f54df 100644 --- a/python/helpers/pydev/pydevd_plugins/django_debug.py +++ b/python/helpers/pydev/pydevd_plugins/django_debug.py @@ -6,7 +6,7 @@ from pydevd_breakpoints import LineBreakpoint, get_exception_name import pydevd_vars import traceback import pydev_log -from pydevd_frame_utils import add_exception_to_frame, FCode +from pydevd_frame_utils import add_exception_to_frame, FCode, cached_call, just_raised class DjangoLineBreakpoint(LineBreakpoint): @@ -251,7 +251,6 @@ class DjangoTemplateFrame: if k == name: d[k] = value - def is_django_exception_break_context(frame): try: name = frame.f_code.co_name @@ -260,18 +259,13 @@ def is_django_exception_break_context(frame): return name in ['_resolve_lookup', 'find_template'] -def just_raised(trace): - if trace is None: - return False - return trace.tb_next is None - - #======================================================================================================================= # Django Step Commands #======================================================================================================================= -def can_skip(mainDebugger, frame): - if hasattr(mainDebugger, 'django_breakpoints') and mainDebugger.django_breakpoints and is_django_render_call(frame): +def can_skip(mainDebugger, pydb_frame): + frame = pydb_frame.frame + if hasattr(mainDebugger, 'django_breakpoints') and mainDebugger.django_breakpoints and cached_call(pydb_frame, is_django_render_call, frame): filename = get_template_file_name(frame) django_breakpoints_for_file = mainDebugger.django_breakpoints.get(filename) if django_breakpoints_for_file: @@ -285,7 +279,7 @@ def has_exception_breaks(mainDebugger): def cmd_step_into(mainDebugger, frame, event, args, stop_info): mainDebugger, filename, info, thread = args if is_django_suspended(thread): - #stop_info['django_stop'] = event == 'call' and is_django_render_call(frame) + #stop_info['django_stop'] = event == 'call' and cached_call(frame, is_django_render_call) stop_info['stop'] = stop_info['stop'] and is_django_resolve_call(frame.f_back) and not is_django_context_get_call(frame) if stop_info['stop']: info.pydev_django_resolve_frame = 1 #we remember that we've go into python code from django rendering frame @@ -318,14 +312,15 @@ def stop(mainDebugger, frame, event, args, stop_info, arg, step_cmd): return False -def get_breakpoint(mainDebugger, frame, event, args): +def get_breakpoint(mainDebugger, pydb_frame, event, args): mainDebugger, filename, info, thread = args + frame = pydb_frame.frame flag = False django_breakpoint = None new_frame = None if event == 'call' and info.pydev_state != STATE_SUSPEND and hasattr(mainDebugger, 'django_breakpoints') and \ - mainDebugger.django_breakpoints and is_django_render_call(frame): + mainDebugger.django_breakpoints and cached_call(pydb_frame, is_django_render_call, frame): filename = get_template_file_name(frame) pydev_log.debug("Django is rendering a template: %s\n" % filename) django_breakpoints_for_file = mainDebugger.django_breakpoints.get(filename) @@ -344,8 +339,9 @@ def get_breakpoint(mainDebugger, frame, event, args): def suspend(mainDebugger, pydb_frame, thread, frame): return suspend_django(pydb_frame, mainDebugger, thread, frame) -def exception_break(mainDebugger, pydb_frame, frame, event, args, arg): +def exception_break(mainDebugger, pydb_frame, args, arg): mainDebugger, filename, info, thread = args + frame = pydb_frame.frame exception, value, trace = arg if hasattr(mainDebugger, 'django_exception_break') and mainDebugger.django_exception_break and \ get_exception_name(exception) in ['VariableDoesNotExist', 'TemplateDoesNotExist', 'TemplateSyntaxError'] and \ diff --git a/python/helpers/pydev/pydevd_plugins/jinja2_debug.py b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py index 7109fbb30e25..f741282738f3 100644 --- a/python/helpers/pydev/pydevd_plugins/jinja2_debug.py +++ b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py @@ -1,9 +1,10 @@ +import traceback from pydevd_breakpoints import LineBreakpoint, get_exception_name from pydevd_constants import JINJA2_SUSPEND, GetThreadId, STATE_SUSPEND, DictContains from pydevd_comm import CMD_SET_BREAK, CMD_STEP_OVER, CMD_ADD_EXCEPTION_BREAK import pydevd_vars from pydevd_file_utils import GetFileNameAndBaseFromFile -from pydevd_frame_utils import add_exception_to_frame, FCode +from pydevd_frame_utils import add_exception_to_frame, FCode, cached_call class Jinja2LineBreakpoint(LineBreakpoint): @@ -191,8 +192,9 @@ def get_jinja2_template_filename(frame): def has_exception_breaks(mainDebugger): return hasattr(mainDebugger, 'jinja2_exception_break') and mainDebugger.jinja2_exception_break -def can_skip(mainDebugger, frame): - if hasattr(mainDebugger, 'jinja2_breakpoints') and mainDebugger.jinja2_breakpoints and is_jinja2_render_call(frame): +def can_skip(mainDebugger, pydb_frame): + frame = pydb_frame.frame + if hasattr(mainDebugger, 'jinja2_breakpoints') and mainDebugger.jinja2_breakpoints and cached_call(pydb_frame, is_jinja2_render_call, frame): filename = get_jinja2_template_filename(frame) jinja2_breakpoints_for_file = mainDebugger.jinja2_breakpoints.get(filename) if jinja2_breakpoints_for_file: @@ -284,13 +286,14 @@ def stop(mainDebugger, frame, event, args, stop_info, arg, step_cmd): return False -def get_breakpoint(mainDebugger, frame, event, args): +def get_breakpoint(mainDebugger, pydb_frame, event, args): mainDebugger, filename, info, thread = args + frame = pydb_frame.frame new_frame = None jinja2_breakpoint = None flag = False if event in ('line', 'call') and info.pydev_state != STATE_SUSPEND and hasattr(mainDebugger, 'jinja2_breakpoints') and \ - mainDebugger.jinja2_breakpoints and is_jinja2_render_call(frame): + mainDebugger.jinja2_breakpoints and cached_call(pydb_frame, is_jinja2_render_call, frame): filename = get_jinja2_template_filename(frame) jinja2_breakpoints_for_file = mainDebugger.jinja2_breakpoints.get(filename) new_frame = Jinja2TemplateFrame(frame) @@ -310,8 +313,9 @@ def suspend(mainDebugger, pydb_frame, thread, frame): return suspend_jinja2(pydb_frame, mainDebugger, thread, frame) -def exception_break(mainDebugger, pydb_frame, frame, event, args, arg): +def exception_break(mainDebugger, pydb_frame, args, arg): mainDebugger, filename, info, thread = args + frame = pydb_frame.frame exception, value, trace = arg if hasattr(mainDebugger, 'jinja2_exception_break') and mainDebugger.jinja2_exception_break: if get_exception_name(exception) in ('UndefinedError', 'TemplateNotFound', 'TemplatesNotFound'): @@ -324,7 +328,7 @@ def exception_break(mainDebugger, pydb_frame, frame, event, args, arg): flag = True suspend_frame.f_back = frame frame = suspend_frame - return (flag, frame) + return flag, frame elif get_exception_name(exception) in ('TemplateSyntaxError', 'TemplateAssertionError'): #errors in compile time name = frame.f_code.co_name @@ -334,5 +338,5 @@ def exception_break(mainDebugger, pydb_frame, frame, event, args, arg): add_exception_to_frame(frame, (exception, value, trace)) thread.additionalInfo.suspend_type = JINJA2_SUSPEND flag = True - return (flag, frame) + return flag, frame return None \ No newline at end of file