mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git.labs.intellij.net:idea/ultimate
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
import inspect
|
||||
from pydev.pydevd_comm import CMD_SET_BREAK
|
||||
from pydev.pydevd_constants import DJANGO_SUSPEND, GetThreadId
|
||||
from pydev.pydevd_file_utils import NormFileToServer
|
||||
from pydev.runfiles import DictContains
|
||||
from pydevd_breakpoints import LineBreakpoint
|
||||
import traceback
|
||||
|
||||
|
||||
def get_source(frame):
|
||||
try:
|
||||
return frame.f_locals['self'].source
|
||||
except:
|
||||
return None
|
||||
|
||||
def get_template_file_name(frame):
|
||||
try:
|
||||
source = get_source(frame)
|
||||
return source[0].name
|
||||
except:
|
||||
return None
|
||||
|
||||
def get_template_line(frame):
|
||||
source = get_source(frame)
|
||||
file_name = get_template_file_name(frame)
|
||||
try:
|
||||
return offset_to_line_number(read_file(file_name), source[1][0])
|
||||
except:
|
||||
return None
|
||||
|
||||
class DjangoTemplateFrame:
|
||||
def __init__(self, frame):
|
||||
file_name = get_template_file_name(frame)
|
||||
context = frame.f_locals['context']
|
||||
self.f_code = FCode('Django Template', file_name)
|
||||
self.f_lineno = get_template_line(frame)
|
||||
self.f_back = frame
|
||||
self.f_globals = {}
|
||||
self.f_locals = collect_context(context)
|
||||
self.f_trace = None
|
||||
|
||||
|
||||
class FCode:
|
||||
def __init__(self, name, filename):
|
||||
self.co_name = name
|
||||
self.co_filename = filename
|
||||
|
||||
|
||||
def collect_context(context):
|
||||
res = {}
|
||||
for d in context.dicts:
|
||||
for k,v in d.items():
|
||||
res[k] = v
|
||||
return res
|
||||
|
||||
def read_file(filename):
|
||||
f = open(filename, "r")
|
||||
s = f.read()
|
||||
f.close()
|
||||
return s
|
||||
|
||||
def offset_to_line_number(text, offset):
|
||||
curLine = 1
|
||||
curOffset = 0
|
||||
while curOffset < offset:
|
||||
if curOffset == len(text):
|
||||
return -1
|
||||
c = text[curOffset]
|
||||
if c == '\n':
|
||||
curLine += 1
|
||||
elif c == '\r':
|
||||
curLine += 1
|
||||
if curOffset < len(text) and text[curOffset + 1] == '\n':
|
||||
curOffset += 1
|
||||
|
||||
curOffset += 1
|
||||
|
||||
return curLine
|
||||
|
||||
class DjangoLineBreakpoint(LineBreakpoint):
|
||||
def __init__(self, type, file, line, flag, condition, func_name, expression):
|
||||
self.file = file
|
||||
self.line = line
|
||||
LineBreakpoint.__init__(self, type, flag, condition, func_name, expression)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, DjangoLineBreakpoint):
|
||||
return False
|
||||
return self.file == other.file and self.line == other.line
|
||||
|
||||
def is_triggered(self, frame):
|
||||
file = get_template_file_name(frame)
|
||||
line = get_template_line(frame)
|
||||
return self.file == file and self.line == line
|
||||
|
||||
def is_django_render_call(frame):
|
||||
try:
|
||||
name = frame.f_code.co_name
|
||||
if name != 'render':
|
||||
return False
|
||||
|
||||
if not DictContains(frame.f_locals, 'self'):
|
||||
return False
|
||||
|
||||
cls = frame.f_locals['self'].__class__
|
||||
|
||||
inherits_node = False
|
||||
for base in inspect.getmro(cls):
|
||||
if base.__name__ == 'Node':
|
||||
inherits_node = True
|
||||
break
|
||||
|
||||
if not inherits_node:
|
||||
return False
|
||||
|
||||
clsname = cls.__name__
|
||||
return clsname != 'TextNode' and clsname != 'NodeList'
|
||||
except :
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def is_django_suspended(thread):
|
||||
return thread.additionalInfo.suspend_type == DJANGO_SUSPEND
|
||||
|
||||
def suspend_django(py_db_frame, mainDebugger, thread, frame):
|
||||
frame = DjangoTemplateFrame(frame)
|
||||
|
||||
if frame.f_lineno is None:
|
||||
return None
|
||||
|
||||
#try:
|
||||
# if thread.additionalInfo.filename == frame.f_code.co_filename and thread.additionalInfo.line == frame.f_lineno:
|
||||
# return None # don't stay twice on the same line
|
||||
#except AttributeError:
|
||||
# pass
|
||||
|
||||
mainDebugger.additional_frames.addAdditionalFrameById(GetThreadId(thread), {id(frame): frame})
|
||||
|
||||
|
||||
py_db_frame.setSuspend(thread, CMD_SET_BREAK)
|
||||
thread.additionalInfo.suspend_type = DJANGO_SUSPEND
|
||||
|
||||
thread.additionalInfo.filename = frame.f_code.co_filename
|
||||
thread.additionalInfo.line = frame.f_lineno
|
||||
|
||||
return frame
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#IMPORTANT: pydevd_constants must be the 1st thing defined because it'll keep a reference to the original sys._getframe
|
||||
from pydev.django_debug import DjangoLineBreakpoint
|
||||
from pydevd_constants import * #@UnusedWildImport
|
||||
from pydevd_breakpoints import * #@UnusedWildImport
|
||||
|
||||
@@ -48,6 +49,7 @@ from pydevd_comm import CMD_CHANGE_VARIABLE, \
|
||||
|
||||
from pydevd_file_utils import NormFileToServer, GetFilenameAndBase
|
||||
import pydevd_vars
|
||||
from pydevd_vars import getAdditionalFramesContainer
|
||||
import traceback
|
||||
import pydevd_vm_type
|
||||
import pydevd_tracing
|
||||
@@ -194,6 +196,8 @@ class PyDB:
|
||||
self.cmdFactory = NetCommandFactory()
|
||||
self.cmdQueue = {} # the hash of Queues. Key is thread id, value is thread
|
||||
self.breakpoints = {}
|
||||
self.django_breakpoints = {}
|
||||
self.additional_frames = getAdditionalFramesContainer()
|
||||
self.readyToRun = False
|
||||
self.lock = threading.RLock()
|
||||
self.internalQueueLock = threading.Lock()
|
||||
@@ -529,7 +533,8 @@ class PyDB:
|
||||
|
||||
#command to add some breakpoint.
|
||||
# text is file\tline. Add to breakpoints dictionary
|
||||
file, line, condition, expression = text.split('\t', 3)
|
||||
type, file, line, condition, expression = text.split('\t', 4)
|
||||
|
||||
if condition.startswith('**FUNC**'):
|
||||
func_name, condition = condition.split('\t', 1)
|
||||
|
||||
@@ -552,32 +557,29 @@ class PyDB:
|
||||
|
||||
line = int(line)
|
||||
|
||||
if DEBUG_TRACE_BREAKPOINTS > 0:
|
||||
sys.stderr.write('Added breakpoint:%s - line:%s - func_name:%s\n' % (file, line, func_name))
|
||||
sys.stderr.flush()
|
||||
|
||||
if DictContains(self.breakpoints, file):
|
||||
breakDict = self.breakpoints[file]
|
||||
else:
|
||||
breakDict = {}
|
||||
|
||||
if len(condition) <= 0 or condition is None or condition == "None":
|
||||
condition = None
|
||||
|
||||
if len(expression) <= 0 or expression is None or expression == "None":
|
||||
expression = None
|
||||
|
||||
breakDict[line] = (True, condition, func_name, expression)
|
||||
if type == 'python-line':
|
||||
breakpoint = LineBreakpoint(type, True, condition, func_name, expression)
|
||||
breakpoint.add(self.breakpoints, file, line, func_name)
|
||||
elif type == 'django-line':
|
||||
breakpoint = DjangoLineBreakpoint(type, file, line, True, condition, func_name, expression)
|
||||
breakpoint.add(self.django_breakpoints, file, line, func_name)
|
||||
else:
|
||||
raise NameError(type)
|
||||
|
||||
|
||||
self.breakpoints[file] = breakDict
|
||||
|
||||
self.enable_tracing()
|
||||
|
||||
elif cmd_id == CMD_REMOVE_BREAK:
|
||||
#command to remove some breakpoint
|
||||
#text is file\tline. Remove from breakpoints dictionary
|
||||
file, line = text.split('\t', 1)
|
||||
type, file, line = text.split('\t', 2)
|
||||
file = NormFileToServer(file)
|
||||
try:
|
||||
line = int(line)
|
||||
@@ -586,7 +588,10 @@ class PyDB:
|
||||
|
||||
else:
|
||||
try:
|
||||
del self.breakpoints[file][line] #remove the breakpoint in that line
|
||||
if type == 'django-line':
|
||||
del self.django_breakpoints[file][line]
|
||||
else:
|
||||
del self.breakpoints[file][line] #remove the breakpoint in that line
|
||||
if DEBUG_TRACE_BREAKPOINTS > 0:
|
||||
sys.stderr.write('Removed breakpoint:%s\n' % (file,))
|
||||
sys.stderr.flush()
|
||||
@@ -685,6 +690,7 @@ class PyDB:
|
||||
thread.additionalInfo.pydev_notify_kill = True
|
||||
|
||||
def setSuspend(self, thread, stop_reason):
|
||||
thread.additionalInfo.suspend_type = PYTHON_SUSPEND
|
||||
thread.additionalInfo.pydev_state = STATE_SUSPEND
|
||||
thread.stop_reason = stop_reason
|
||||
|
||||
@@ -816,13 +822,13 @@ class PyDB:
|
||||
self.force_post_mortem_stop -= 1
|
||||
frame, frames_byid = additionalInfo.pydev_force_stop_at_exception
|
||||
thread_id = GetThreadId(t)
|
||||
used_id = pydevd_vars.addAdditionalFrameById(thread_id, frames_byid)
|
||||
used_id = pydev_vars.additional_frames_container.addAdditionalFrameById(thread_id, frames_byid)
|
||||
try:
|
||||
self.setSuspend(t, CMD_ADD_EXCEPTION_BREAK)
|
||||
self.doWaitSuspend(t, frame, 'exception', None)
|
||||
finally:
|
||||
additionalInfo.pydev_force_stop_at_exception = None
|
||||
pydevd_vars.removeAdditionalFrameById(thread_id)
|
||||
pydev_vars.additional_frames_container.removeAdditionalFrameById(thread_id)
|
||||
|
||||
# if thread is not alive, cancel trace_dispatch processing
|
||||
if not t.isAlive():
|
||||
|
||||
@@ -21,6 +21,34 @@ class ExceptionBreakpoint:
|
||||
self.type = exctype
|
||||
self.notify = {NOTIFY_ALWAYS: notify_always, NOTIFY_ON_TERMINATE: notify_on_terminate}
|
||||
|
||||
class LineBreakpoint:
|
||||
def __init__(self, type, flag, condition, func_name, expression):
|
||||
self.type = type
|
||||
self.condition = condition
|
||||
self.func_name = func_name
|
||||
self.expression = expression
|
||||
|
||||
def get_break_dict(self, breakpoints, file):
|
||||
if DictContains(breakpoints, file):
|
||||
breakDict = breakpoints[file]
|
||||
else:
|
||||
breakDict = {}
|
||||
breakpoints[file] = breakDict
|
||||
return breakDict
|
||||
|
||||
def trace(self, file, line, func_name):
|
||||
if DEBUG_TRACE_BREAKPOINTS > 0:
|
||||
sys.stderr.write('Added breakpoint:%s - line:%s - func_name:%s\n' % (file, line, func_name))
|
||||
sys.stderr.flush()
|
||||
|
||||
def add(self, breakpoints, file, line, func_name):
|
||||
self.trace(file, line, func_name)
|
||||
|
||||
breakDict = self.get_break_dict(breakpoints, file)
|
||||
|
||||
breakDict[line] = self
|
||||
|
||||
|
||||
def get_exception_breakpoint(exctype, exceptions, notify_class):
|
||||
exc = None
|
||||
if exceptions is not None:
|
||||
|
||||
@@ -481,38 +481,41 @@ class NetCommandFactory:
|
||||
try:
|
||||
cmdTextList = ["<xml>"]
|
||||
cmdTextList.append('<thread id="%s" stop_reason="%s" message="%s">' % (thread_id, stop_reason, message))
|
||||
|
||||
curFrame = frame
|
||||
while curFrame:
|
||||
#print cmdText
|
||||
myId = str(id(curFrame))
|
||||
#print "id is ", myId
|
||||
|
||||
if curFrame.f_code is None:
|
||||
break #Iron Python sometimes does not have it!
|
||||
|
||||
myName = curFrame.f_code.co_name #method name (if in method) or ? if global
|
||||
if myName is None:
|
||||
break #Iron Python sometimes does not have it!
|
||||
|
||||
#print "name is ", myName
|
||||
|
||||
myFile = pydevd_file_utils.NormFileToClient(curFrame.f_code.co_filename)
|
||||
#print "file is ", myFile
|
||||
#myFile = inspect.getsourcefile(curFrame) or inspect.getfile(frame)
|
||||
|
||||
myLine = str(curFrame.f_lineno)
|
||||
#print "line is ", myLine
|
||||
|
||||
#the variables are all gotten 'on-demand'
|
||||
#variables = pydevd_vars.frameVarsToXML(curFrame)
|
||||
|
||||
variables = ''
|
||||
cmdTextList.append('<frame id="%s" name="%s" ' % (myId , pydevd_vars.makeValidXmlValue(myName)))
|
||||
cmdTextList.append('file="%s" line="%s">"' % (quote(myFile, '/>_= \t'), myLine))
|
||||
cmdTextList.append(variables)
|
||||
cmdTextList.append("</frame>")
|
||||
curFrame = curFrame.f_back
|
||||
curFrame = frame
|
||||
try:
|
||||
while curFrame:
|
||||
#print cmdText
|
||||
myId = str(id(curFrame))
|
||||
#print "id is ", myId
|
||||
|
||||
if curFrame.f_code is None:
|
||||
break #Iron Python sometimes does not have it!
|
||||
|
||||
myName = curFrame.f_code.co_name #method name (if in method) or ? if global
|
||||
if myName is None:
|
||||
break #Iron Python sometimes does not have it!
|
||||
|
||||
#print "name is ", myName
|
||||
|
||||
myFile = pydevd_file_utils.NormFileToClient(curFrame.f_code.co_filename)
|
||||
#print "file is ", myFile
|
||||
#myFile = inspect.getsourcefile(curFrame) or inspect.getfile(frame)
|
||||
|
||||
myLine = str(curFrame.f_lineno)
|
||||
#print "line is ", myLine
|
||||
|
||||
#the variables are all gotten 'on-demand'
|
||||
#variables = pydevd_vars.frameVarsToXML(curFrame)
|
||||
|
||||
variables = ''
|
||||
cmdTextList.append('<frame id="%s" name="%s" ' % (myId , pydevd_vars.makeValidXmlValue(myName)))
|
||||
cmdTextList.append('file="%s" line="%s">"' % (quote(myFile, '/>_= \t'), myLine))
|
||||
cmdTextList.append(variables)
|
||||
cmdTextList.append("</frame>")
|
||||
curFrame = curFrame.f_back
|
||||
except :
|
||||
traceback.print_exc()
|
||||
|
||||
cmdTextList.append("</thread></xml>")
|
||||
cmdText = ''.join(cmdTextList)
|
||||
@@ -778,7 +781,7 @@ class InternalGetCompletions(InternalThreadCommand):
|
||||
try:
|
||||
|
||||
frame = pydevd_vars.findFrame(self.thread_id, self.frame_id)
|
||||
|
||||
|
||||
#Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
|
||||
#(Names not resolved in generator expression in method)
|
||||
#See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
|
||||
|
||||
@@ -5,6 +5,9 @@ This module holds the constants used for specifying the states of the debugger.
|
||||
STATE_RUN = 1
|
||||
STATE_SUSPEND = 2
|
||||
|
||||
PYTHON_SUSPEND = 1
|
||||
DJANGO_SUSPEND = 2
|
||||
|
||||
try:
|
||||
__setFalse = False
|
||||
except:
|
||||
|
||||
@@ -191,11 +191,11 @@ if PATHS_FROM_ECLIPSE_TO_PYTHON:
|
||||
except KeyError:
|
||||
#used to translate a path from the debug server to the client
|
||||
translated = _NormFile(filename)
|
||||
for eclipse_prefix, pyhon_prefix in PATHS_FROM_ECLIPSE_TO_PYTHON:
|
||||
if translated.startswith(pyhon_prefix):
|
||||
for eclipse_prefix, python_prefix in PATHS_FROM_ECLIPSE_TO_PYTHON:
|
||||
if translated.startswith(python_prefix):
|
||||
if DEBUG_CLIENT_SERVER_TRANSLATION:
|
||||
sys.stderr.write('pydev debugger: replacing to client: %s\n' % (translated,))
|
||||
translated = translated.replace(pyhon_prefix, eclipse_prefix)
|
||||
translated = translated.replace(python_prefix, eclipse_prefix)
|
||||
if DEBUG_CLIENT_SERVER_TRANSLATION:
|
||||
sys.stderr.write('pydev debugger: sent to client: %s\n' % (translated,))
|
||||
break
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from pydev.django_debug import DjangoTemplateFrame, DjangoLineBreakpoint, is_django_render_call, get_template_file_name, get_template_line, is_django_suspended, suspend_django
|
||||
import pydevd_vars
|
||||
from pydevd_comm import * #@UnusedWildImport
|
||||
from pydevd_constants import * #@UnusedWildImport
|
||||
from pydevd_breakpoints import * #@UnusedWildImport
|
||||
@@ -15,18 +17,18 @@ class PyDBFrame:
|
||||
is used initially when we enter into a new context ('call') and then
|
||||
is reused for the entire context.
|
||||
'''
|
||||
|
||||
|
||||
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._args = args[:-1]
|
||||
|
||||
|
||||
def setSuspend(self, *args, **kwargs):
|
||||
self._args[0].setSuspend(*args, **kwargs)
|
||||
|
||||
|
||||
def doWaitSuspend(self, *args, **kwargs):
|
||||
self._args[0].doWaitSuspend(*args, **kwargs)
|
||||
|
||||
|
||||
def trace_dispatch(self, frame, event, arg):
|
||||
if event not in ('line', 'call', 'return', 'exception'):
|
||||
return None
|
||||
@@ -34,10 +36,11 @@ class PyDBFrame:
|
||||
mainDebugger, filename, info, thread = self._args
|
||||
|
||||
if event is not 'exception':
|
||||
breakpoint = mainDebugger.breakpoints.get(filename)
|
||||
breakpoints_for_file = mainDebugger.breakpoints.get(filename)
|
||||
|
||||
can_skip = False
|
||||
if len(always_exception_set) == 0:
|
||||
|
||||
if len(always_exception_set):
|
||||
if info.pydev_state == STATE_RUN:
|
||||
#we can skip if:
|
||||
#- we have no stop marked
|
||||
@@ -45,14 +48,16 @@ class PyDBFrame:
|
||||
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)
|
||||
|
||||
if mainDebugger.django_breakpoints:
|
||||
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,
|
||||
# we will return nothing for the next trace
|
||||
#also, after we hit a breakpoint and go to some other debugging state, we have to force the set trace anyway,
|
||||
#so, that's why the additional checks are there.
|
||||
if not breakpoint:
|
||||
if not breakpoints_for_file:
|
||||
if can_skip:
|
||||
return None
|
||||
return None
|
||||
|
||||
else:
|
||||
#checks the breakpoint to see if there is a context match in some function
|
||||
@@ -62,9 +67,9 @@ class PyDBFrame:
|
||||
if curr_func_name in ('?', '<module>'):
|
||||
curr_func_name = ''
|
||||
|
||||
for _b, condition, func_name, expression in breakpoint.values(): #jython does not support itervalues()
|
||||
for breakpoint in breakpoints_for_file.values(): #jython does not support itervalues()
|
||||
#will match either global or some function
|
||||
if func_name in ('None', curr_func_name):
|
||||
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)
|
||||
@@ -72,7 +77,7 @@ class PyDBFrame:
|
||||
#print 'skipping', frame.f_lineno, info.pydev_state, info.pydev_step_stop, info.pydev_step_cmd
|
||||
return None
|
||||
else:
|
||||
breakpoint = None
|
||||
breakpoints_for_file = 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
|
||||
@@ -91,31 +96,47 @@ class PyDBFrame:
|
||||
thread.additionalInfo.message = exception_breakpoint.qname
|
||||
#self.doWaitSuspend(thread, frame, event, arg)
|
||||
|
||||
elif event == 'call' and info.pydev_state != STATE_SUSPEND and mainDebugger.django_breakpoints \
|
||||
and is_django_render_call(frame):
|
||||
flag = False
|
||||
filename = get_template_file_name(frame)
|
||||
django_breakpoints_for_file = mainDebugger.django_breakpoints.get(filename)
|
||||
if django_breakpoints_for_file:
|
||||
template_line = get_template_line(frame)
|
||||
if DictContains(django_breakpoints_for_file, template_line):
|
||||
django_breakpoint = django_breakpoints_for_file[template_line]
|
||||
|
||||
if django_breakpoint.is_triggered(frame):
|
||||
frame = suspend_django(self, mainDebugger, thread, frame)
|
||||
flag = True
|
||||
|
||||
#if not flag:
|
||||
# return self.trace_dispatch
|
||||
|
||||
|
||||
#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).
|
||||
elif event != 'return' and info.pydev_state != STATE_SUSPEND and breakpoint is not None \
|
||||
and DictContains(breakpoint, line):
|
||||
|
||||
elif event != 'return' and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None\
|
||||
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
|
||||
condition = breakpoint[line][1]
|
||||
breakpoint = breakpoints_for_file[line]
|
||||
|
||||
if condition is not None:
|
||||
if breakpoint.condition is not None:
|
||||
try:
|
||||
val = eval(condition, frame.f_globals, frame.f_locals)
|
||||
val = eval(breakpoint.condition, frame.f_globals, frame.f_locals)
|
||||
if not val:
|
||||
return self.trace_dispatch
|
||||
|
||||
|
||||
except:
|
||||
sys.stderr.write('Error while evaluating condition \'%s\': %s\n'%(condition, sys.exc_info()[1]))
|
||||
sys.stderr.write('Error while evaluating condition \'%s\': %s\n' % (breakpoint.condition, sys.exc_info()[1]))
|
||||
sys.stderr.flush()
|
||||
return self.trace_dispatch
|
||||
|
||||
expression = breakpoint[line][3]
|
||||
if expression is not None:
|
||||
if breakpoint.expression is not None:
|
||||
try:
|
||||
try:
|
||||
val = eval(expression, frame.f_globals, frame.f_locals)
|
||||
val = eval(breakpoint.expression, frame.f_globals, frame.f_locals)
|
||||
except:
|
||||
val = sys.exc_info()[1]
|
||||
finally:
|
||||
@@ -123,41 +144,45 @@ class PyDBFrame:
|
||||
thread.log_expression = val
|
||||
|
||||
self.setSuspend(thread, CMD_SET_BREAK)
|
||||
|
||||
|
||||
# if thread has a suspend flag, we suspend with a busy wait
|
||||
if info.pydev_state == STATE_SUSPEND:
|
||||
self.doWaitSuspend(thread, frame, event, arg)
|
||||
return self.trace_dispatch
|
||||
|
||||
|
||||
except:
|
||||
raise
|
||||
|
||||
|
||||
#step handling. We stop when we hit the right frame
|
||||
try:
|
||||
|
||||
django_stop = False
|
||||
if info.pydev_step_cmd == CMD_STEP_INTO:
|
||||
|
||||
stop = event in ('line', 'return')
|
||||
|
||||
|
||||
elif info.pydev_step_cmd == CMD_STEP_OVER:
|
||||
|
||||
stop = info.pydev_step_stop is frame and event in ('line', 'return')
|
||||
|
||||
if is_django_suspended(thread):
|
||||
|
||||
django_stop = event == 'call' and is_django_render_call(frame)
|
||||
|
||||
stop = False
|
||||
else:
|
||||
stop = info.pydev_step_stop is frame and event in ('line', 'return')
|
||||
|
||||
elif info.pydev_step_cmd == CMD_STEP_RETURN:
|
||||
|
||||
stop = event == 'return' and info.pydev_step_stop is frame
|
||||
|
||||
|
||||
elif info.pydev_step_cmd == CMD_RUN_TO_LINE:
|
||||
stop = False
|
||||
|
||||
if event == 'line':
|
||||
#Yes, we can only act on line events (weird hum?)
|
||||
#Note: This code is duplicated at pydevd.py
|
||||
curr_func_name = frame.f_code.co_name
|
||||
|
||||
|
||||
#global context is set with an empty name
|
||||
if curr_func_name in ('?', '<module>'):
|
||||
curr_func_name = ''
|
||||
|
||||
|
||||
if curr_func_name == info.pydev_func_name:
|
||||
line = info.pydev_next_line
|
||||
if frame.f_lineno == line:
|
||||
@@ -168,11 +193,15 @@ class PyDBFrame:
|
||||
frame.f_lineno = line
|
||||
frame.f_trace = None
|
||||
stop = True
|
||||
|
||||
|
||||
else:
|
||||
stop = False
|
||||
|
||||
if stop:
|
||||
|
||||
if django_stop:
|
||||
frame = suspend_django(self, mainDebugger, 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)
|
||||
@@ -180,14 +209,12 @@ class PyDBFrame:
|
||||
else: #return event
|
||||
back = frame.f_back
|
||||
if back is not None:
|
||||
|
||||
#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':
|
||||
back = 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)
|
||||
@@ -197,22 +224,23 @@ class PyDBFrame:
|
||||
info.pydev_step_stop = None
|
||||
info.pydev_step_cmd = None
|
||||
info.pydev_state = STATE_RUN
|
||||
|
||||
|
||||
|
||||
|
||||
except:
|
||||
traceback.print_exc()
|
||||
info.pydev_step_cmd = None
|
||||
|
||||
|
||||
#if we are quitting, let's stop the tracing
|
||||
retVal = None
|
||||
if not mainDebugger.quitting:
|
||||
retVal = self.trace_dispatch
|
||||
|
||||
return retVal
|
||||
|
||||
|
||||
if USE_PSYCO_OPTIMIZATION:
|
||||
try:
|
||||
import psyco
|
||||
|
||||
trace_dispatch = psyco.proxy(trace_dispatch)
|
||||
except ImportError:
|
||||
if hasattr(sys, 'exc_clear'): #jython does not have it
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
""" pydevd_vars deals with variables:
|
||||
resolution/conversion to XML.
|
||||
"""
|
||||
import pickle
|
||||
from pydevd_constants import * #@UnusedWildImport
|
||||
from types import * #@UnusedWildImport
|
||||
from console import pydevconsole
|
||||
@@ -13,6 +14,7 @@ try:
|
||||
except ImportError:
|
||||
from io import StringIO
|
||||
import sys #@Reimport
|
||||
|
||||
try:
|
||||
from urllib import quote
|
||||
except:
|
||||
@@ -32,30 +34,32 @@ try:
|
||||
__setFalse = False
|
||||
except:
|
||||
import __builtin__
|
||||
|
||||
setattr(__builtin__, 'True', 1)
|
||||
setattr(__builtin__, 'False', 0)
|
||||
|
||||
#------------------------------------------------------------------------------------------------------ class for errors
|
||||
|
||||
class VariableError(RuntimeError):pass
|
||||
class FrameNotFoundError(RuntimeError):pass
|
||||
class VariableError(RuntimeError): pass
|
||||
|
||||
class FrameNotFoundError(RuntimeError): pass
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------------------------------ resolvers in map
|
||||
|
||||
if not sys.platform.startswith("java"):
|
||||
typeMap = [
|
||||
#None means that it should not be treated as a compound variable
|
||||
#None means that it should not be treated as a compound variable
|
||||
|
||||
#isintance does not accept a tuple on some versions of python, so, we must declare it expanded
|
||||
(type(None), None,),
|
||||
(int, None),
|
||||
(float, None),
|
||||
(complex, None),
|
||||
(str, None),
|
||||
(tuple, pydevd_resolver.tupleResolver),
|
||||
(list, pydevd_resolver.tupleResolver),
|
||||
(dict, pydevd_resolver.dictResolver),
|
||||
#isintance does not accept a tuple on some versions of python, so, we must declare it expanded
|
||||
(type(None), None,),
|
||||
(int, None),
|
||||
(float, None),
|
||||
(complex, None),
|
||||
(str, None),
|
||||
(tuple, pydevd_resolver.tupleResolver),
|
||||
(list, pydevd_resolver.tupleResolver),
|
||||
(dict, pydevd_resolver.dictResolver),
|
||||
]
|
||||
|
||||
try:
|
||||
@@ -80,17 +84,18 @@ if not sys.platform.startswith("java"):
|
||||
|
||||
else: #platform is java
|
||||
from org.python import core #@UnresolvedImport
|
||||
|
||||
typeMap = [
|
||||
(core.PyNone, None),
|
||||
(core.PyInteger, None),
|
||||
(core.PyLong, None),
|
||||
(core.PyFloat, None),
|
||||
(core.PyComplex, None),
|
||||
(core.PyString, None),
|
||||
(core.PyTuple, pydevd_resolver.tupleResolver),
|
||||
(core.PyList, pydevd_resolver.tupleResolver),
|
||||
(core.PyDictionary, pydevd_resolver.dictResolver),
|
||||
(core.PyStringMap, pydevd_resolver.dictResolver),
|
||||
(core.PyNone, None),
|
||||
(core.PyInteger, None),
|
||||
(core.PyLong, None),
|
||||
(core.PyFloat, None),
|
||||
(core.PyComplex, None),
|
||||
(core.PyString, None),
|
||||
(core.PyTuple, pydevd_resolver.tupleResolver),
|
||||
(core.PyList, pydevd_resolver.tupleResolver),
|
||||
(core.PyDictionary, pydevd_resolver.dictResolver),
|
||||
(core.PyStringMap, pydevd_resolver.dictResolver),
|
||||
]
|
||||
|
||||
if hasattr(core, 'PyJavaInstance'):
|
||||
@@ -115,7 +120,6 @@ def getType(o):
|
||||
return 'Unable to get Type', 'Unable to get Type', None
|
||||
|
||||
try:
|
||||
|
||||
if type_name == 'org.python.core.PyJavaInstance':
|
||||
return (type_object, type_name, pydevd_resolver.instanceResolver)
|
||||
|
||||
@@ -134,8 +138,9 @@ def getType(o):
|
||||
|
||||
try:
|
||||
from xml.sax.saxutils import escape
|
||||
|
||||
def makeValidXmlValue(s):
|
||||
return escape(s, {'"':'"'})
|
||||
return escape(s, {'"': '"'})
|
||||
except:
|
||||
#Simple replacement if it's not there.
|
||||
def makeValidXmlValue(s):
|
||||
@@ -177,7 +182,7 @@ def varToXML(val, name, doTrim=True):
|
||||
except:
|
||||
value = 'Unable to get repr for %s' % v.__class__
|
||||
|
||||
xml = '<var name="%s" type="%s"' % (makeValidXmlValue(name),makeValidXmlValue(typeName))
|
||||
xml = '<var name="%s" type="%s"' % (makeValidXmlValue(name), makeValidXmlValue(typeName))
|
||||
|
||||
if value:
|
||||
#cannot be too big... communication may not handle it.
|
||||
@@ -214,6 +219,7 @@ def varToXML(val, name, doTrim=True):
|
||||
if USE_PSYCO_OPTIMIZATION:
|
||||
try:
|
||||
import psyco
|
||||
|
||||
varToXML = psyco.proxy(varToXML)
|
||||
except ImportError:
|
||||
if hasattr(sys, 'exc_clear'): #jython does not have it
|
||||
@@ -255,44 +261,68 @@ def iterFrames(initialFrame):
|
||||
|
||||
def dumpFrames(thread_id):
|
||||
sys.stdout.write('dumping frames\n')
|
||||
if thread_id != GetThreadId(threading.currentThread()) :
|
||||
if thread_id != GetThreadId(threading.currentThread()):
|
||||
raise VariableError("findFrame: must execute on same thread")
|
||||
|
||||
curFrame = GetFrame()
|
||||
for frame in iterFrames(curFrame):
|
||||
sys.stdout.write('%s\n' % id(frame))
|
||||
sys.stdout.write('%s\n' % pickle.dumps(frame))
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# AdditionalFramesContainer
|
||||
#===============================================================================
|
||||
class AdditionalFramesContainer:
|
||||
lock = threading.Lock()
|
||||
additional_frames = {} #dict of dicts
|
||||
__instance__ = None
|
||||
|
||||
@staticmethod
|
||||
def getInstance():
|
||||
if AdditionalFramesContainer.__instance__ is None:
|
||||
AdditionalFramesContainer.__instance__ = AdditionalFramesContainer()
|
||||
return AdditionalFramesContainer.__instance__
|
||||
|
||||
def addAdditionalFrameById(thread_id, frames_by_id):
|
||||
AdditionalFramesContainer.additional_frames[thread_id] = frames_by_id
|
||||
def __init__(self):
|
||||
self.additional_frames = {} #dict of dicts
|
||||
self.lock = threading.Lock()
|
||||
|
||||
def addAdditionalFrameById(self, thread_id, frames_by_id):
|
||||
self.lock.acquire()
|
||||
self.additional_frames[thread_id] = frames_by_id
|
||||
self.lock.release()
|
||||
|
||||
def removeAdditionalFrameById(thread_id):
|
||||
del AdditionalFramesContainer.additional_frames[thread_id]
|
||||
def findFrameById(self, thread_id, frame_id):
|
||||
self.lock.acquire()
|
||||
frame = None
|
||||
if self.additional_frames:
|
||||
if DictContains(self.additional_frames, thread_id):
|
||||
frame = self.additional_frames[thread_id].get(frame_id)
|
||||
|
||||
self.lock.release()
|
||||
return frame
|
||||
|
||||
def removeAdditionalFrameById(self, thread_id):
|
||||
#del self.additional_frames[thread_id]
|
||||
pass
|
||||
|
||||
additional_frames_container = AdditionalFramesContainer()
|
||||
|
||||
def getAdditionalFramesContainer():
|
||||
global additional_frames_container
|
||||
|
||||
return additional_frames_container
|
||||
|
||||
|
||||
def findFrame(thread_id, frame_id):
|
||||
""" returns a frame on the thread that has a given frame_id """
|
||||
if thread_id != GetThreadId(threading.currentThread()) :
|
||||
if thread_id != GetThreadId(threading.currentThread()):
|
||||
raise VariableError("findFrame: must execute on same thread")
|
||||
|
||||
lookingFor = int(frame_id)
|
||||
|
||||
if AdditionalFramesContainer.additional_frames:
|
||||
if DictContains(AdditionalFramesContainer.additional_frames, thread_id):
|
||||
frame = AdditionalFramesContainer.additional_frames[thread_id].get(lookingFor)
|
||||
if frame is not None:
|
||||
return frame
|
||||
frame = getAdditionalFramesContainer().findFrameById(thread_id, lookingFor)
|
||||
|
||||
if frame is not None:
|
||||
return frame
|
||||
|
||||
curFrame = GetFrame()
|
||||
if frame_id == "*":
|
||||
@@ -349,9 +379,9 @@ def resolveCompoundVariable(thread_id, frame_id, scope, attrs):
|
||||
var = frame.f_locals
|
||||
type, _typeName, resolver = getType(var)
|
||||
try:
|
||||
resolver.resolve(var, attrList[0])
|
||||
resolver.resolve(var, attrList[0])
|
||||
except:
|
||||
var = frame.f_globals
|
||||
var = frame.f_globals
|
||||
|
||||
for k in attrList:
|
||||
type, _typeName, resolver = getType(var)
|
||||
@@ -384,7 +414,6 @@ def evaluateExpression(thread_id, frame_id, expression, doExec):
|
||||
updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals
|
||||
|
||||
try:
|
||||
|
||||
if doExec:
|
||||
try:
|
||||
#try to make it an eval (if it is an eval we can print it, otherwise we'll exec it and
|
||||
@@ -427,12 +456,13 @@ def evaluateExpression(thread_id, frame_id, expression, doExec):
|
||||
|
||||
class ConsoleWriter(InteractiveInterpreter):
|
||||
skip = 0
|
||||
|
||||
def __init__(self, locals=None):
|
||||
InteractiveInterpreter.__init__(self, locals)
|
||||
|
||||
def write(self, data):
|
||||
#if (data.find("global_vars") == -1 and data.find("pydevd") == -1):
|
||||
if self.skip>0:
|
||||
if self.skip > 0:
|
||||
self.skip = self.skip - 1
|
||||
else:
|
||||
if data == "Traceback (most recent call last):\n":
|
||||
@@ -478,7 +508,6 @@ def consoleExec(thread_id, frame_id, expression):
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def changeAttrExpression(thread_id, frame_id, attr, expression):
|
||||
'''Changes some attribute in a given frame.
|
||||
@note: it will not (currently) work if we're not in the topmost frame (that's a python
|
||||
@@ -489,16 +518,16 @@ def changeAttrExpression(thread_id, frame_id, attr, expression):
|
||||
|
||||
try:
|
||||
expression = expression.replace('@LINE@', '\n')
|
||||
#tests (needs proposed patch in python accepted)
|
||||
# if hasattr(frame, 'savelocals'):
|
||||
# if attr in frame.f_locals:
|
||||
# frame.f_locals[attr] = eval(expression, frame.f_globals, frame.f_locals)
|
||||
# frame.savelocals()
|
||||
# return
|
||||
#
|
||||
# elif attr in frame.f_globals:
|
||||
# frame.f_globals[attr] = eval(expression, frame.f_globals, frame.f_locals)
|
||||
# return
|
||||
#tests (needs proposed patch in python accepted)
|
||||
# if hasattr(frame, 'savelocals'):
|
||||
# if attr in frame.f_locals:
|
||||
# frame.f_locals[attr] = eval(expression, frame.f_globals, frame.f_locals)
|
||||
# frame.savelocals()
|
||||
# return
|
||||
#
|
||||
# elif attr in frame.f_globals:
|
||||
# frame.f_globals[attr] = eval(expression, frame.f_globals, frame.f_locals)
|
||||
# return
|
||||
|
||||
|
||||
if attr[:7] == "Globals":
|
||||
|
||||
@@ -6,20 +6,23 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @author traff
|
||||
*/
|
||||
public abstract class LineBreakpointCommand extends AbstractCommand {
|
||||
private final String myType;
|
||||
@NotNull protected final String myFile;
|
||||
protected final int myLine;
|
||||
|
||||
|
||||
public LineBreakpointCommand(RemoteDebugger debugger,
|
||||
int commandCode,
|
||||
String type, int commandCode,
|
||||
@NotNull final String file,
|
||||
final int line) {
|
||||
super(debugger, commandCode);
|
||||
myType = type;
|
||||
myFile = file;
|
||||
myLine = line;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildPayload(Payload payload) {
|
||||
payload.add(myFile).add(Integer.toString(myLine));
|
||||
payload.add(myType).add(myFile).add(Integer.toString(myLine));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.jetbrains.python.debugger.pydev;
|
||||
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class RemoveBreakpointCommand extends LineBreakpointCommand {
|
||||
|
||||
public RemoveBreakpointCommand(final RemoteDebugger debugger, final String file, final int line) {
|
||||
super(debugger, REMOVE_BREAKPOINT, file, line);
|
||||
public RemoveBreakpointCommand(final RemoteDebugger debugger, @NotNull final String type, final String file, final int line) {
|
||||
super(debugger, type, REMOVE_BREAKPOINT, file, line);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,17 +9,19 @@ public class SetBreakpointCommand extends LineBreakpointCommand {
|
||||
private @Nullable final String myLogExpression;
|
||||
|
||||
public SetBreakpointCommand(@NotNull final RemoteDebugger debugger,
|
||||
@NotNull final String type,
|
||||
@NotNull final String file,
|
||||
@NotNull final int line) {
|
||||
this(debugger, file, line, null, null);
|
||||
this(debugger, type, file, line, null, null);
|
||||
}
|
||||
|
||||
public SetBreakpointCommand(@NotNull final RemoteDebugger debugger,
|
||||
@NotNull final String type,
|
||||
@NotNull final String file,
|
||||
@NotNull final int line,
|
||||
@Nullable final String condition,
|
||||
@Nullable final String logExpression) {
|
||||
super(debugger, SET_BREAKPOINT, file, line);
|
||||
super(debugger, type, SET_BREAKPOINT, file, line);
|
||||
myCondition = condition;
|
||||
myLogExpression = logExpression;
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
<programRunner implementation="com.jetbrains.python.debugger.remote.PyRemoteDebugRunner"/>
|
||||
<configurationProducer implementation="com.jetbrains.python.run.PythonRunConfigurationProducer"/>
|
||||
<xdebugger.breakpointType implementation="com.jetbrains.python.debugger.PyLineBreakpointType"/>
|
||||
<xdebugger.breakpointType implementation="com.jetbrains.python.debugger.DjangoTemplateLineBreakpointType"/>
|
||||
<xdebugger.breakpointType implementation="com.jetbrains.python.debugger.PyExceptionBreakpointType"/>
|
||||
|
||||
<configurationType implementation="com.jetbrains.python.testing.unittest.PythonUnitTestConfigurationType"/>
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.jetbrains.python.debugger;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.intellij.xdebugger.XSourcePosition;
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpointHandler;
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpointProperties;
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpointType;
|
||||
import com.intellij.xdebugger.breakpoints.XLineBreakpoint;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author traff
|
||||
*/
|
||||
public class AbstractLineBreakpointHandler extends XBreakpointHandler<XLineBreakpoint<XBreakpointProperties>> {
|
||||
protected final PyDebugProcess myDebugProcess;
|
||||
private final Map<XLineBreakpoint<XBreakpointProperties>, XSourcePosition> myBreakPointPositions = Maps.newHashMap();
|
||||
|
||||
public AbstractLineBreakpointHandler(
|
||||
Class<? extends XBreakpointType<XLineBreakpoint<XBreakpointProperties>, ?>> breakpointTypeClass,
|
||||
@NotNull final PyDebugProcess debugProcess) {
|
||||
super(breakpointTypeClass);
|
||||
myDebugProcess = debugProcess;
|
||||
}
|
||||
|
||||
public void reregisterBreakpoints() {
|
||||
List<XLineBreakpoint<XBreakpointProperties>> breakpoints = Lists.newArrayList(myBreakPointPositions.keySet());
|
||||
for (XLineBreakpoint<XBreakpointProperties> breakpoint : breakpoints) {
|
||||
unregisterBreakpoint(breakpoint, false);
|
||||
registerBreakpoint(breakpoint);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerBreakpoint(@NotNull final XLineBreakpoint<XBreakpointProperties> breakpoint) {
|
||||
final XSourcePosition position = breakpoint.getSourcePosition();
|
||||
if (position != null) {
|
||||
myDebugProcess.addBreakpoint(myDebugProcess.getPositionConverter().convert(position), breakpoint);
|
||||
myBreakPointPositions.put(breakpoint, position);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterBreakpoint(@NotNull final XLineBreakpoint<XBreakpointProperties> breakpoint, final boolean temporary) {
|
||||
final XSourcePosition position = myBreakPointPositions.get(breakpoint);
|
||||
if (position != null) {
|
||||
myDebugProcess.removeBreakpoint(myDebugProcess.getPositionConverter().convert(position));
|
||||
myBreakPointPositions.remove(breakpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.jetbrains.python.debugger;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class DjangoLineBreakpointHandler extends AbstractLineBreakpointHandler {
|
||||
public DjangoLineBreakpointHandler(@NotNull final PyDebugProcess debugProcess) {
|
||||
super(DjangoTemplateLineBreakpointType.class, debugProcess);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.jetbrains.python.debugger;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.xdebugger.XDebuggerUtil;
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpointProperties;
|
||||
import com.intellij.xdebugger.breakpoints.XLineBreakpointType;
|
||||
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
|
||||
import com.jetbrains.django.util.DjangoUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
public class DjangoTemplateLineBreakpointType extends XLineBreakpointType<XBreakpointProperties> {
|
||||
private final PyDebuggerEditorsProvider myEditorsProvider = new PyDebuggerEditorsProvider();
|
||||
|
||||
public DjangoTemplateLineBreakpointType() {
|
||||
super("django-line", "Django Line Breakpoint");
|
||||
}
|
||||
|
||||
public boolean canPutAt(@NotNull final VirtualFile file, final int line, @NotNull final Project project) {
|
||||
final Ref<Boolean> stoppable = Ref.create(false);
|
||||
final Document document = FileDocumentManager.getInstance().getDocument(file);
|
||||
if (document != null) {
|
||||
if (DjangoUtil.isDjangoTemplateDocument(document, project)) {
|
||||
XDebuggerUtil.getInstance().iterateLine(project, document, line, new Processor<PsiElement>() {
|
||||
public boolean process(PsiElement psiElement) {
|
||||
if (psiElement instanceof PsiWhiteSpace || psiElement instanceof PsiComment) return true;
|
||||
// Python debugger seems to be able to stop on pretty much everything
|
||||
stoppable.set(true);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return stoppable.get();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public XBreakpointProperties createBreakpointProperties(@NotNull final VirtualFile file, final int line) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBreakpointsDialogHelpTopic() {
|
||||
return "reference.dialogs.breakpoints";
|
||||
}
|
||||
|
||||
@Override
|
||||
public XDebuggerEditorsProvider getEditorsProvider() {
|
||||
return myEditorsProvider;
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
|
||||
super(session);
|
||||
session.setPauseActionSupported(true);
|
||||
myDebugger = new RemoteDebugger(this, serverSocket, 10);
|
||||
myBreakpointHandlers = new XBreakpointHandler[]{new PyLineBreakpointHandler(this), new PyExceptionBreakpointHandler(this)};
|
||||
myBreakpointHandlers = new XBreakpointHandler[]{new PyLineBreakpointHandler(this), new PyExceptionBreakpointHandler(this), new DjangoLineBreakpointHandler(this)};
|
||||
myEditorsProvider = new PyDebuggerEditorsProvider();
|
||||
myProcessHandler = processHandler;
|
||||
myExecutionConsole = executionConsole;
|
||||
@@ -156,7 +156,8 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
|
||||
printToConsole("Connected to pydev debugger (build " + remoteVersion + ")\n", ConsoleViewContentType.SYSTEM_OUTPUT);
|
||||
|
||||
if (!remoteVersion.equals(currentBuild)) {
|
||||
printToConsole("Warning: wrong debugger version. Use pycharm-debugger.egg from PyCharm installation folder.\n", ConsoleViewContentType.ERROR_OUTPUT);
|
||||
printToConsole("Warning: wrong debugger version. Use pycharm-debugger.egg from PyCharm installation folder.\n",
|
||||
ConsoleViewContentType.ERROR_OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +229,8 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
|
||||
dropFrameCaches();
|
||||
if (myDebugger.isConnected() && !mySuspendedThreads.isEmpty()) {
|
||||
final PySourcePosition pyPosition = myPositionConverter.convert(position);
|
||||
final SetBreakpointCommand command = new SetBreakpointCommand(myDebugger, pyPosition.getFile(), pyPosition.getLine());
|
||||
final SetBreakpointCommand command =
|
||||
new SetBreakpointCommand(myDebugger, PyLineBreakpointType.ID, pyPosition.getFile(), pyPosition.getLine());
|
||||
myDebugger.execute(command); // set temp. breakpoint
|
||||
resume(ResumeCommand.Mode.RESUME);
|
||||
}
|
||||
@@ -322,17 +324,21 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
|
||||
myRegisteredBreakpoints.put(position, breakpoint);
|
||||
if (myDebugger.isConnected()) {
|
||||
final SetBreakpointCommand command =
|
||||
new SetBreakpointCommand(myDebugger, position.getFile(), position.getLine(), breakpoint.getCondition(),
|
||||
new SetBreakpointCommand(myDebugger, breakpoint.getType().getId(), position.getFile(), position.getLine(),
|
||||
breakpoint.getCondition(),
|
||||
breakpoint.getLogExpression());
|
||||
myDebugger.execute(command);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeBreakpoint(final PySourcePosition position) {
|
||||
myRegisteredBreakpoints.remove(position);
|
||||
if (myDebugger.isConnected()) {
|
||||
final RemoveBreakpointCommand command = new RemoveBreakpointCommand(myDebugger, position.getFile(), position.getLine());
|
||||
myDebugger.execute(command);
|
||||
XLineBreakpoint breakpoint = myRegisteredBreakpoints.get(position);
|
||||
if (breakpoint != null) {
|
||||
myRegisteredBreakpoints.remove(position);
|
||||
if (myDebugger.isConnected()) {
|
||||
final RemoveBreakpointCommand command = new RemoveBreakpointCommand(myDebugger, breakpoint.getType().getId(), position.getFile(), position.getLine());
|
||||
myDebugger.execute(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,7 +381,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
|
||||
final PySourcePosition position = frames.get(0).getPosition();
|
||||
breakpoint = myRegisteredBreakpoints.get(position);
|
||||
if (breakpoint == null) {
|
||||
final RemoveBreakpointCommand command = new RemoveBreakpointCommand(myDebugger, position.getFile(), position.getLine());
|
||||
final RemoveBreakpointCommand command = new RemoveBreakpointCommand(myDebugger, "all", position.getFile(), position.getLine());
|
||||
myDebugger.execute(command); // remove temp. breakpoint
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +1,11 @@
|
||||
package com.jetbrains.python.debugger;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.intellij.xdebugger.XSourcePosition;
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpointHandler;
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpointProperties;
|
||||
import com.intellij.xdebugger.breakpoints.XLineBreakpoint;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class PyLineBreakpointHandler extends XBreakpointHandler<XLineBreakpoint<XBreakpointProperties>> {
|
||||
|
||||
private final PyDebugProcess myDebugProcess;
|
||||
|
||||
private final Map<XLineBreakpoint<XBreakpointProperties>, XSourcePosition> myBreakPointPositions = Maps.newHashMap();
|
||||
public class PyLineBreakpointHandler extends AbstractLineBreakpointHandler {
|
||||
|
||||
public PyLineBreakpointHandler(@NotNull final PyDebugProcess debugProcess) {
|
||||
super(PyLineBreakpointType.class);
|
||||
myDebugProcess = debugProcess;
|
||||
}
|
||||
|
||||
public void reregisterBreakpoints() {
|
||||
List<XLineBreakpoint<XBreakpointProperties>> breakpoints = Lists.newArrayList(myBreakPointPositions.keySet());
|
||||
for (XLineBreakpoint<XBreakpointProperties> breakpoint : breakpoints) {
|
||||
unregisterBreakpoint(breakpoint, false);
|
||||
registerBreakpoint(breakpoint);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerBreakpoint(@NotNull final XLineBreakpoint<XBreakpointProperties> breakpoint) {
|
||||
final XSourcePosition position = breakpoint.getSourcePosition();
|
||||
if (position != null) {
|
||||
myDebugProcess.addBreakpoint(myDebugProcess.getPositionConverter().convert(position), breakpoint);
|
||||
myBreakPointPositions.put(breakpoint, position);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterBreakpoint(@NotNull final XLineBreakpoint<XBreakpointProperties> breakpoint, final boolean temporary) {
|
||||
final XSourcePosition position = myBreakPointPositions.get(breakpoint);
|
||||
if (position != null) {
|
||||
myDebugProcess.removeBreakpoint(myDebugProcess.getPositionConverter().convert(position));
|
||||
myBreakPointPositions.remove(breakpoint);
|
||||
}
|
||||
super(PyLineBreakpointType.class, debugProcess);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.xdebugger.XDebuggerUtil;
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpointProperties;
|
||||
@@ -17,17 +19,20 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
public class PyLineBreakpointType extends XLineBreakpointType<XBreakpointProperties> {
|
||||
public static final String ID = "python-line";
|
||||
private static final String NAME = "Python Line Breakpoint";
|
||||
|
||||
private final PyDebuggerEditorsProvider myEditorsProvider = new PyDebuggerEditorsProvider();
|
||||
|
||||
public PyLineBreakpointType() {
|
||||
super("python-line", "Python Line Breakpoint");
|
||||
super(ID, NAME);
|
||||
}
|
||||
|
||||
public boolean canPutAt(@NotNull final VirtualFile file, final int line, @NotNull final Project project) {
|
||||
final Ref<Boolean> stoppable = Ref.create(false);
|
||||
if (file.getFileType() == PythonFileType.INSTANCE) {
|
||||
final Document document = FileDocumentManager.getInstance().getDocument(file);
|
||||
if (document != null) {
|
||||
final Document document = FileDocumentManager.getInstance().getDocument(file);
|
||||
if (document != null) {
|
||||
if (file.getFileType() == PythonFileType.INSTANCE) {
|
||||
XDebuggerUtil.getInstance().iterateLine(project, document, line, new Processor<PsiElement>() {
|
||||
public boolean process(PsiElement psiElement) {
|
||||
if (psiElement instanceof PsiWhiteSpace || psiElement instanceof PsiComment) return true;
|
||||
@@ -42,6 +47,7 @@ public class PyLineBreakpointType extends XLineBreakpointType<XBreakpointPropert
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stoppable.get();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public class JythonUnitTestUtil {
|
||||
File jythonJar = new File(PathManager.getHomePath(), "python/lib/jython.jar");
|
||||
parameters.getClassPath().add(jythonJar.getPath());
|
||||
|
||||
parameters.getProgramParametersList().add("-Dpython.path=" + pythonPath + ";" + workDir);
|
||||
parameters.getProgramParametersList().add("-Dpython.path=" + pythonPath + File.pathSeparator + workDir);
|
||||
parameters.getProgramParametersList().addAll(args);
|
||||
parameters.setWorkingDirectory(workDir);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.jetbrains.python.fixtures.PyLightFixtureTestCase;
|
||||
*/
|
||||
public class PyFoldingTest extends PyLightFixtureTestCase {
|
||||
private void doTest() {
|
||||
myFixture.testFolding(getTestDataPath() + "/folding/" + getTestName(false) + ".py");
|
||||
myFixture.testFolding(getTestDataPath() + "/folding/" + getTestName(true) + ".py");
|
||||
}
|
||||
|
||||
public void testClassTrailingSpace() { // PY-2544
|
||||
|
||||
Reference in New Issue
Block a user