Cache is_django_render_call in PyDBFrame object (the same for Jinja).

This commit is contained in:
Dmitry Trofimov
2014-09-06 00:58:05 +02:00
parent 5774cc3d70
commit 0cb4aae6e1
8 changed files with 58 additions and 43 deletions
+8 -1
View File
@@ -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):
@@ -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
+1 -1
View File
@@ -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
+6 -15
View File
@@ -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
+20 -2
View File
@@ -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)
+1 -1
View File
@@ -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)
@@ -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 \
@@ -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