Merge branch 'master' of git.labs.intellij.net:idea/ultimate

This commit is contained in:
Ekaterina Tuzova
2011-04-20 15:40:39 +04:00
20 changed files with 565 additions and 212 deletions
+151
View File
@@ -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
+22 -16
View File
@@ -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:
+35 -32
View File
@@ -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
+3
View File
@@ -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:
+3 -3
View File
@@ -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
+73 -45
View File
@@ -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
+83 -54
View File
@@ -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, {'"':'&quot;'})
return escape(s, {'"': '&quot;'})
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