summaryrefslogtreecommitdiff
path: root/python/helpers/pydev/pydevd_frame.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/helpers/pydev/pydevd_frame.py')
-rw-r--r--python/helpers/pydev/pydevd_frame.py451
1 files changed, 342 insertions, 109 deletions
diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py
index 05faaeb77ff2..374d2818bf87 100644
--- a/python/helpers/pydev/pydevd_frame.py
+++ b/python/helpers/pydev/pydevd_frame.py
@@ -1,18 +1,29 @@
-from django_debug import is_django_render_call, get_template_file_name, get_template_line, is_django_suspended, suspend_django, is_django_resolve_call, is_django_context_get_call
+import linecache
+import os.path
+import re
+import traceback # @Reimport
+
from django_debug import find_django_render_frame
-from django_frame import just_raised
-from django_frame import is_django_exception_break_context
+from django_debug import is_django_render_call, is_django_suspended, suspend_django, is_django_resolve_call, is_django_context_get_call
from django_frame import DjangoTemplateFrame
-from pydevd_comm import * #@UnusedWildImport
-from pydevd_breakpoints import * #@UnusedWildImport
-import traceback #@Reimport
-import os.path
-import sys
+from django_frame import is_django_exception_break_context
+from django_frame import just_raised, get_template_file_name, get_template_line
import pydev_log
+from pydevd_breakpoints import get_exception_breakpoint, get_exception_name
+from pydevd_comm import CMD_ADD_DJANGO_EXCEPTION_BREAK, \
+ CMD_STEP_CAUGHT_EXCEPTION, CMD_STEP_RETURN, CMD_STEP_OVER, CMD_SET_BREAK, \
+ CMD_STEP_INTO, CMD_SMART_STEP_INTO, CMD_RUN_TO_LINE, CMD_SET_NEXT_STATEMENT
+from pydevd_constants import * # @UnusedWildImport
+from pydevd_file_utils import GetFilenameAndBase
from pydevd_signature import sendSignatureCallTrace
+import pydevd_vars
+import pydevd_dont_trace
basename = os.path.basename
+IGNORE_EXCEPTION_TAG = re.compile('[^#]*#.*@IgnoreException')
+
+
#=======================================================================================================================
# PyDBFrame
#=======================================================================================================================
@@ -22,6 +33,13 @@ class PyDBFrame:
is reused for the entire context.
'''
+ #Note: class (and not instance) attributes.
+
+ #Same thing in the main debugger but only considering the file contents, while the one in the main debugger
+ #considers the user input (so, the actual result must be a join of both).
+ filename_to_lines_where_exceptions_are_ignored = {}
+ filename_to_stat_info = {}
+
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
@@ -33,84 +51,234 @@ class PyDBFrame:
def doWaitSuspend(self, *args, **kwargs):
self._args[0].doWaitSuspend(*args, **kwargs)
+ def _is_django_render_call(self, frame):
+ 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.shouldStopOnException(frame, event, arg)
+ flag, frame = self.should_stop_on_exception(frame, event, arg)
if flag:
- self.handle_exception(frame, event, arg)
- return self.trace_dispatch
+ self.handle_exception(frame, event, arg)
+ return self.trace_dispatch
return self.trace_exception
- def shouldStopOnException(self, frame, event, arg):
- mainDebugger, filename, info, thread = self._args
- flag = False
-
- if info.pydev_state != STATE_SUSPEND: #and breakpoint is not None:
- (exception, value, trace) = arg
-
- if trace is not None: #on jython trace is None on the first event
- exception_breakpoint = get_exception_breakpoint(exception, dict(mainDebugger.exception_set), NOTIFY_ALWAYS)
- if exception_breakpoint is not None:
- if not exception_breakpoint.notify_on_first_raise_only or just_raised(trace):
- curr_func_name = frame.f_code.co_name
- add_exception_to_frame(frame, (exception, value, trace))
- self.setSuspend(thread, CMD_ADD_EXCEPTION_BREAK)
- thread.additionalInfo.message = exception_breakpoint.qname
- flag = True
- else:
- flag = False
- else:
- try:
- if mainDebugger.django_exception_break and get_exception_name(exception) in ['VariableDoesNotExist', 'TemplateDoesNotExist', 'TemplateSyntaxError'] and just_raised(trace) and is_django_exception_break_context(frame):
- render_frame = find_django_render_frame(frame)
- if render_frame:
- suspend_frame = suspend_django(self, mainDebugger, thread, render_frame, CMD_ADD_DJANGO_EXCEPTION_BREAK)
-
- if suspend_frame:
- add_exception_to_frame(suspend_frame, (exception, value, trace))
- flag = True
- thread.additionalInfo.message = 'VariableDoesNotExist'
- suspend_frame.f_back = frame
- frame = suspend_frame
- except :
- flag = False
-
- return (flag, frame)
+ def should_stop_on_exception(self, frame, event, arg):
+ mainDebugger, _filename, info, thread = self._args
+ flag = False
+
+ if info.pydev_state != STATE_SUSPEND: #and breakpoint is not None:
+ exception, value, trace = arg
+
+ if trace is not None: #on jython trace is None on the first event
+ exception_breakpoint = get_exception_breakpoint(
+ exception, mainDebugger.break_on_caught_exceptions)
+
+ if exception_breakpoint is not None:
+ if not exception_breakpoint.notify_on_first_raise_only or just_raised(trace):
+ # print frame.f_code.co_name
+ add_exception_to_frame(frame, (exception, value, trace))
+ thread.additionalInfo.message = exception_breakpoint.qname
+ flag = True
+ else:
+ flag = False
+ else:
+ try:
+ if mainDebugger.django_exception_break and get_exception_name(exception) in [
+ 'VariableDoesNotExist', 'TemplateDoesNotExist', 'TemplateSyntaxError'] \
+ and just_raised(trace) and is_django_exception_break_context(frame):
+
+ render_frame = find_django_render_frame(frame)
+ if render_frame:
+ suspend_frame = suspend_django(
+ self, mainDebugger, thread, render_frame, CMD_ADD_DJANGO_EXCEPTION_BREAK)
+
+ if suspend_frame:
+ add_exception_to_frame(suspend_frame, (exception, value, trace))
+ flag = True
+ thread.additionalInfo.message = 'VariableDoesNotExist'
+ suspend_frame.f_back = frame
+ frame = suspend_frame
+ except :
+ flag = False
+
+ return flag, frame
def handle_exception(self, frame, event, arg):
- mainDebugger = self._args[0]
- thread = self._args[3]
- self.doWaitSuspend(thread, frame, event, arg)
- mainDebugger.SetTraceForFrameAndParents(frame)
+ try:
+ # print 'handle_exception', frame.f_lineno, frame.f_code.co_name
+
+ # We have 3 things in arg: exception type, description, traceback object
+ trace_obj = arg[2]
+ mainDebugger = self._args[0]
+
+ if not hasattr(trace_obj, 'tb_next'):
+ return #Not always there on Jython...
+
+ initial_trace_obj = trace_obj
+ if trace_obj.tb_next is None and trace_obj.tb_frame is frame:
+ #I.e.: tb_next should be only None in the context it was thrown (trace_obj.tb_frame is frame is just a double check).
+
+ if mainDebugger.break_on_exceptions_thrown_in_same_context:
+ #Option: Don't break if an exception is caught in the same function from which it is thrown
+ return
+ else:
+ #Get the trace_obj from where the exception was raised...
+ while trace_obj.tb_next is not None:
+ trace_obj = trace_obj.tb_next
+
+
+ if mainDebugger.ignore_exceptions_thrown_in_lines_with_ignore_exception:
+ for check_trace_obj in (initial_trace_obj, trace_obj):
+ filename = GetFilenameAndBase(check_trace_obj.tb_frame)[0]
+
+
+ filename_to_lines_where_exceptions_are_ignored = self.filename_to_lines_where_exceptions_are_ignored
+
+
+ lines_ignored = filename_to_lines_where_exceptions_are_ignored.get(filename)
+ if lines_ignored is None:
+ lines_ignored = filename_to_lines_where_exceptions_are_ignored[filename] = {}
+
+ try:
+ curr_stat = os.stat(filename)
+ curr_stat = (curr_stat.st_size, curr_stat.st_mtime)
+ except:
+ curr_stat = None
+
+ last_stat = self.filename_to_stat_info.get(filename)
+ if last_stat != curr_stat:
+ self.filename_to_stat_info[filename] = curr_stat
+ lines_ignored.clear()
+ try:
+ linecache.checkcache(filename)
+ except:
+ #Jython 2.1
+ linecache.checkcache()
+
+ from_user_input = mainDebugger.filename_to_lines_where_exceptions_are_ignored.get(filename)
+ if from_user_input:
+ merged = {}
+ merged.update(lines_ignored)
+ #Override what we have with the related entries that the user entered
+ merged.update(from_user_input)
+ else:
+ merged = lines_ignored
+
+ exc_lineno = check_trace_obj.tb_lineno
+
+ # print ('lines ignored', lines_ignored)
+ # print ('user input', from_user_input)
+ # print ('merged', merged, 'curr', exc_lineno)
+
+ if not DictContains(merged, exc_lineno): #Note: check on merged but update lines_ignored.
+ try:
+ line = linecache.getline(filename, exc_lineno, check_trace_obj.tb_frame.f_globals)
+ except:
+ #Jython 2.1
+ line = linecache.getline(filename, exc_lineno)
+
+ if IGNORE_EXCEPTION_TAG.match(line) is not None:
+ lines_ignored[exc_lineno] = 1
+ return
+ else:
+ #Put in the cache saying not to ignore
+ lines_ignored[exc_lineno] = 0
+ else:
+ #Ok, dict has it already cached, so, let's check it...
+ if merged.get(exc_lineno, 0):
+ return
+
+
+ thread = self._args[3]
+
+ try:
+ frame_id_to_frame = {}
+ frame_id_to_frame[id(frame)] = frame
+ f = trace_obj.tb_frame
+ while f is not None:
+ frame_id_to_frame[id(f)] = f
+ f = f.f_back
+ f = None
+
+ thread_id = GetThreadId(thread)
+ pydevd_vars.addAdditionalFrameById(thread_id, frame_id_to_frame)
+ try:
+ mainDebugger.sendCaughtExceptionStack(thread, arg, id(frame))
+ self.setSuspend(thread, CMD_STEP_CAUGHT_EXCEPTION)
+ self.doWaitSuspend(thread, frame, event, arg)
+ mainDebugger.sendCaughtExceptionStackProceeded(thread)
+
+ finally:
+ pydevd_vars.removeAdditionalFrameById(thread_id)
+ except:
+ traceback.print_exc()
+
+ mainDebugger.SetTraceForFrameAndParents(frame)
+ finally:
+ #Clear some local variables...
+ trace_obj = None
+ initial_trace_obj = None
+ check_trace_obj = None
+ f = None
+ frame_id_to_frame = None
+ mainDebugger = None
+ thread = None
def trace_dispatch(self, frame, event, arg):
- mainDebugger, filename, info, thread = self._args
+ main_debugger, filename, info, thread = self._args
try:
info.is_tracing = True
- if mainDebugger._finishDebuggingSession:
+ if main_debugger._finishDebuggingSession:
return None
if getattr(thread, 'pydev_do_not_trace', None):
return None
- if event == 'call':
- sendSignatureCallTrace(mainDebugger, frame, filename)
+ if event == 'call' and main_debugger.signature_factory:
+ sendSignatureCallTrace(main_debugger, frame, filename)
+
+ is_exception_event = event == 'exception'
+ has_exception_breakpoints = main_debugger.break_on_caught_exceptions or main_debugger.django_exception_break
- if event not in ('line', 'call', 'return'):
- if event == 'exception':
- (flag, frame) = self.shouldStopOnException(frame, event, arg)
+ if is_exception_event:
+ if has_exception_breakpoints:
+ flag, frame = self.should_stop_on_exception(frame, event, arg)
if flag:
self.handle_exception(frame, event, arg)
return self.trace_dispatch
- else:
+
+ elif event not in ('line', 'call', 'return'):
#I believe this can only happen in jython on some frontiers on jython and java code, which we don't want to trace.
- return None
+ return None
- if event is not 'exception':
- breakpoints_for_file = mainDebugger.breakpoints.get(filename)
+ stop_frame = info.pydev_step_stop
+ step_cmd = info.pydev_step_cmd
+
+ if is_exception_event:
+ breakpoints_for_file = None
+ else:
+ # If we are in single step mode and something causes us to exit the current frame, we need to make sure we break
+ # eventually. Force the step mode to step into and the step stop frame to None.
+ # I.e.: F6 in the end of a function should stop in the next possible position (instead of forcing the user
+ # to make a step in or step over at that location).
+ # Note: this is especially troublesome when we're skipping code with the
+ # @DontTrace comment.
+ if stop_frame is frame and event in ('return', 'exception') and step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER):
+ info.pydev_step_cmd = CMD_STEP_INTO
+ info.pydev_step_stop = None
+
+ breakpoints_for_file = main_debugger.breakpoints.get(filename)
can_skip = False
@@ -118,10 +286,11 @@ class PyDBFrame:
#we can skip if:
#- we have no stop marked
#- we should make a step return/step over and we're not in the current frame
- can_skip = (info.pydev_step_cmd is None and info.pydev_step_stop is None)\
- or (info.pydev_step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and info.pydev_step_stop is not frame)
+ can_skip = (step_cmd is None and stop_frame is None)\
+ or (step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and stop_frame is not frame)
- if mainDebugger.django_breakpoints:
+ check_stop_on_django_render_call = main_debugger.django_breakpoints and self._is_django_render_call(frame)
+ if check_stop_on_django_render_call:
can_skip = False
# Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint,
@@ -130,7 +299,7 @@ class PyDBFrame:
#so, that's why the additional checks are there.
if not breakpoints_for_file:
if can_skip:
- if mainDebugger.always_exception_set or mainDebugger.django_exception_break:
+ if has_exception_breakpoints:
return self.trace_exception
else:
return None
@@ -143,17 +312,18 @@ class PyDBFrame:
if curr_func_name in ('?', '<module>'):
curr_func_name = ''
- for breakpoint in breakpoints_for_file.values(): #jython does not support itervalues()
+ for breakpoint in DictIterValues(breakpoints_for_file): #jython does not support itervalues()
#will match either global or some function
if breakpoint.func_name in ('None', curr_func_name):
break
else: # if we had some break, it won't get here (so, that's a context that we want to skip)
if can_skip:
- #print 'skipping', frame.f_lineno, info.pydev_state, info.pydev_step_stop, info.pydev_step_cmd
- return None
- else:
- breakpoints_for_file = None
+ if has_exception_breakpoints:
+ return self.trace_exception
+ else:
+ return None
+
#We may have hit a breakpoint or we are already in step mode. Either way, let's check what we should do in this frame
#print 'NOT skipped', frame.f_lineno, frame.f_code.co_name, event
@@ -163,33 +333,63 @@ class PyDBFrame:
flag = False
- if event == 'call' and info.pydev_state != STATE_SUSPEND and mainDebugger.django_breakpoints \
- and is_django_render_call(frame):
- (flag, frame) = self.shouldStopOnDjangoBreak(frame, event, arg)
+ if event == 'call' and info.pydev_state != STATE_SUSPEND and check_stop_on_django_render_call:
+ flag, frame = self.should_stop_on_django_breakpoint(frame, event, arg)
#return is not taken into account for breakpoint hit because we'd have a double-hit in this case
#(one for the line and the other for the return).
if not flag and event != 'return' and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None\
- and DictContains(breakpoints_for_file, line):
+ and DictContains(breakpoints_for_file, line):
#ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint
# lets do the conditional stuff here
breakpoint = breakpoints_for_file[line]
stop = True
- if info.pydev_step_cmd == CMD_STEP_OVER and info.pydev_step_stop is frame and event in ('line', 'return'):
+ if step_cmd == CMD_STEP_OVER and stop_frame is frame and event in ('line', 'return'):
stop = False #we don't stop on breakpoint if we have to stop by step-over (it will be processed later)
else:
- if breakpoint.condition is not None:
+ condition = breakpoint.condition
+ if condition is not None:
try:
- val = eval(breakpoint.condition, frame.f_globals, frame.f_locals)
+ val = eval(condition, frame.f_globals, frame.f_locals)
if not val:
return self.trace_dispatch
except:
- pydev_log.info('Error while evaluating condition \'%s\': %s\n' % (breakpoint.condition, sys.exc_info()[1]))
-
- return self.trace_dispatch
+ if type(condition) != type(''):
+ if hasattr(condition, 'encode'):
+ condition = condition.encode('utf-8')
+
+ msg = 'Error while evaluating expression: %s\n' % (condition,)
+ sys.stderr.write(msg)
+ traceback.print_exc()
+ if not main_debugger.suspend_on_breakpoint_exception:
+ return self.trace_dispatch
+ else:
+ stop = True
+ try:
+ additional_info = None
+ try:
+ additional_info = thread.additionalInfo
+ except AttributeError:
+ pass #that's ok, no info currently set
+
+ if additional_info is not None:
+ # add exception_type and stacktrace into thread additional info
+ etype, value, tb = sys.exc_info()
+ try:
+ error = ''.join(traceback.format_exception_only(etype, value))
+ stack = traceback.extract_stack(f=tb.tb_frame.f_back)
+
+ # On self.setSuspend(thread, CMD_SET_BREAK) this info will be
+ # sent to the client.
+ additional_info.conditional_breakpoint_exception = \
+ ('Condition:\n' + condition + '\n\nError:\n' + error, stack)
+ finally:
+ etype, value, tb = None, None, None
+ except:
+ traceback.print_exc()
if breakpoint.expression is not None:
try:
@@ -216,30 +416,45 @@ class PyDBFrame:
#step handling. We stop when we hit the right frame
try:
django_stop = False
- if info.pydev_step_cmd == CMD_STEP_INTO:
+
+ should_skip = False
+ if pydevd_dont_trace.should_trace_hook is not None:
+ if not hasattr(self, 'should_skip'):
+ # I.e.: cache the result on self.should_skip (no need to evaluate the same frame multiple times).
+ # Note that on a code reload, we won't re-evaluate this because in practice, the frame.f_code
+ # Which will be handled by this frame is read-only, so, we can cache it safely.
+ should_skip = self.should_skip = not pydevd_dont_trace.should_trace_hook(frame, filename)
+ else:
+ should_skip = self.should_skip
+
+ if should_skip:
+ stop = False
+
+ elif step_cmd == CMD_STEP_INTO:
stop = event in ('line', 'return')
+
if is_django_suspended(thread):
#django_stop = event == 'call' and is_django_render_call(frame)
stop = stop and is_django_resolve_call(frame.f_back) and not is_django_context_get_call(frame)
if stop:
info.pydev_django_resolve_frame = 1 #we remember that we've go into python code from django rendering frame
- elif info.pydev_step_cmd == CMD_STEP_OVER:
+ elif step_cmd == CMD_STEP_OVER:
if is_django_suspended(thread):
- django_stop = event == 'call' and is_django_render_call(frame)
+ django_stop = event == 'call' and self._is_django_render_call(frame)
stop = False
else:
if event == 'return' and info.pydev_django_resolve_frame is not None and is_django_resolve_call(frame.f_back):
#we return to Django suspend mode and should not stop before django rendering frame
- info.pydev_step_stop = info.pydev_django_resolve_frame
+ stop_frame = info.pydev_step_stop = info.pydev_django_resolve_frame
info.pydev_django_resolve_frame = None
thread.additionalInfo.suspend_type = DJANGO_SUSPEND
- stop = info.pydev_step_stop is frame and event in ('line', 'return')
+ stop = stop_frame is frame and event in ('line', 'return')
- elif info.pydev_step_cmd == CMD_SMART_STEP_INTO:
+ elif step_cmd == CMD_SMART_STEP_INTO:
stop = False
if info.pydev_smart_step_stop is frame:
info.pydev_func_name = None
@@ -253,12 +468,12 @@ class PyDBFrame:
curr_func_name = ''
if curr_func_name == info.pydev_func_name:
- stop = True
+ stop = True
- elif info.pydev_step_cmd == CMD_STEP_RETURN:
- stop = event == 'return' and info.pydev_step_stop is frame
+ elif step_cmd == CMD_STEP_RETURN:
+ stop = event == 'return' and stop_frame is frame
- elif info.pydev_step_cmd == CMD_RUN_TO_LINE or info.pydev_step_cmd == CMD_SET_NEXT_STATEMENT:
+ elif step_cmd == CMD_RUN_TO_LINE or step_cmd == CMD_SET_NEXT_STATEMENT:
stop = False
if event == 'line' or event == 'exception':
@@ -286,13 +501,13 @@ class PyDBFrame:
stop = False
if django_stop:
- frame = suspend_django(self, mainDebugger, thread, frame)
+ frame = suspend_django(self, main_debugger, thread, frame)
if frame:
self.doWaitSuspend(thread, frame, event, arg)
elif stop:
#event is always == line or return at this point
if event == 'line':
- self.setSuspend(thread, info.pydev_step_cmd)
+ self.setSuspend(thread, step_cmd)
self.doWaitSuspend(thread, frame, event, arg)
else: #return event
back = frame.f_back
@@ -300,12 +515,18 @@ class PyDBFrame:
#When we get to the pydevd run function, the debugging has actually finished for the main thread
#(note that it can still go on for other threads, but for this one, we just make it finish)
#So, just setting it to None should be OK
- if basename(back.f_code.co_filename) == 'pydevd.py' and back.f_code.co_name == 'run':
+ base = basename(back.f_code.co_filename)
+ if base == 'pydevd.py' and back.f_code.co_name == 'run':
back = None
+ elif base == 'pydevd_traceproperty.py':
+ # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging)
+ #if we're in a return, we want it to appear to the user in the previous frame!
+ return None
+
if back is not None:
#if we're in a return, we want it to appear to the user in the previous frame!
- self.setSuspend(thread, info.pydev_step_cmd)
+ self.setSuspend(thread, step_cmd)
self.doWaitSuspend(thread, back, event, arg)
else:
#in jython we may not have a back frame
@@ -320,7 +541,7 @@ class PyDBFrame:
#if we are quitting, let's stop the tracing
retVal = None
- if not mainDebugger.quitting:
+ if not main_debugger.quitting:
retVal = self.trace_dispatch
return retVal
@@ -339,24 +560,36 @@ class PyDBFrame:
sys.exc_clear() #don't keep the traceback
pass #ok, psyco not available
- def shouldStopOnDjangoBreak(self, frame, event, arg):
- mainDebugger, filename, info, thread = self._args
+ def should_stop_on_django_breakpoint(self, frame, event, arg):
+ mainDebugger = self._args[0]
+ thread = self._args[3]
flag = False
- 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)
+ template_frame_file = get_template_file_name(frame)
+
+ #pydev_log.debug("Django is rendering a template: %s\n" % template_frame_file)
+
+ django_breakpoints_for_file = mainDebugger.django_breakpoints.get(template_frame_file)
if django_breakpoints_for_file:
- pydev_log.debug("Breakpoints for that file: %s\n" % django_breakpoints_for_file)
- template_line = get_template_line(frame)
- pydev_log.debug("Tracing template line: %d\n" % template_line)
- if DictContains(django_breakpoints_for_file, template_line):
- django_breakpoint = django_breakpoints_for_file[template_line]
+ #pydev_log.debug("Breakpoints for that file: %s\n" % django_breakpoints_for_file)
+
+ template_frame_line = get_template_line(frame, template_frame_file)
+
+ #pydev_log.debug("Tracing template line: %d\n" % template_frame_line)
+
+ if DictContains(django_breakpoints_for_file, template_frame_line):
+ django_breakpoint = django_breakpoints_for_file[template_frame_line]
+
+ if django_breakpoint.is_triggered(template_frame_file, template_frame_line):
+
+ #pydev_log.debug("Breakpoint is triggered.\n")
- if django_breakpoint.is_triggered(frame):
- pydev_log.debug("Breakpoint is triggered.\n")
flag = True
- new_frame = DjangoTemplateFrame(frame)
+ new_frame = DjangoTemplateFrame(
+ frame,
+ template_frame_file=template_frame_file,
+ template_frame_line=template_frame_line,
+ )
if django_breakpoint.condition is not None:
try:
@@ -379,7 +612,7 @@ class PyDBFrame:
thread.additionalInfo.message = val
if flag:
frame = suspend_django(self, mainDebugger, thread, frame)
- return (flag, frame)
+ return flag, frame
def add_exception_to_frame(frame, exception_info):
frame.f_locals['__exception__'] = exception_info \ No newline at end of file