--- /dev/null
+'''
+License: Apache 2.0
+Author: Yuli Fitterman
+'''
+# noinspection PyBroadException
+import types
+
+from _pydevd_bundle.pydevd_constants import IS_JYTHON, IS_PY3K
+
+try:
+ import inspect
+except:
+ try:
+ from _pydev_imps import _pydev_inspect as inspect
+ except:
+ import traceback;
+
+ traceback.print_exc() # Ok, no inspect available (search will not work)from _pydevd_bundle.pydevd_constants import IS_JYTHON, IS_PY3K
+
+from _pydev_bundle._pydev_imports_tipper import signature_from_docstring
+
+
+def is_bound_method(obj):
+ if isinstance(obj, types.MethodType):
+ return getattr(obj, '__self__', getattr(obj, 'im_self', None)) is not None
+ else:
+ return False
+
+
+def get_class_name(instance):
+ return getattr(getattr(instance, "__class__", None), "__name__", None)
+
+
+def get_bound_class_name(obj):
+ my_self = getattr(obj, '__self__', getattr(obj, 'im_self', None))
+ if my_self is None:
+ return None
+ return get_class_name(my_self)
+
+
+def get_description(obj):
+ try:
+ ob_call = obj.__call__
+ except:
+ ob_call = None
+
+ if isinstance(obj, type) or type(obj).__name__ == 'classobj':
+ fob = getattr(obj, '__init__', lambda: None)
+ if not isinstance(fob, (types.FunctionType, types.MethodType)):
+ fob = obj
+ elif is_bound_method(ob_call):
+ fob = ob_call
+ else:
+ fob = obj
+
+ argspec = ""
+ fn_name = None
+ fn_class = None
+ if isinstance(fob, (types.FunctionType, types.MethodType)):
+ spec_info = inspect.getfullargspec(fob) if IS_PY3K else inspect.getargspec(fob)
+ argspec = inspect.formatargspec(*spec_info)
+ fn_name = getattr(fob, '__name__', None)
+ if isinstance(obj, type) or type(obj).__name__ == 'classobj':
+ fn_name = "__init__"
+ fn_class = getattr(obj, "__name__", "UnknownClass")
+ elif is_bound_method(obj) or is_bound_method(ob_call):
+ fn_class = get_bound_class_name(obj) or "UnknownClass"
+
+ else:
+ fn_name = getattr(fob, '__name__', None)
+ fn_self = getattr(fob, '__self__', None)
+ if fn_self is not None and not isinstance(fn_self, types.ModuleType):
+ fn_class = get_class_name(fn_self)
+
+ doc_string = get_docstring(ob_call) if is_bound_method(ob_call) else get_docstring(obj)
+ return create_method_stub(fn_name, fn_class, argspec, doc_string)
+
+
+def create_method_stub(fn_name, fn_class, argspec, doc_string):
+ if fn_name and argspec:
+ doc_string = "" if doc_string is None else doc_string
+ fn_stub = create_function_stub(fn_name, argspec, doc_string, indent=1 if fn_class else 0)
+ if fn_class:
+ expr = fn_class if fn_name == '__init__' else fn_class + '().' + fn_name
+ return create_class_stub(fn_class, fn_stub) + "\n" + expr
+ else:
+ expr = fn_name
+ return fn_stub + "\n" + expr
+ elif doc_string:
+ if fn_name:
+ restored_signature, _ = signature_from_docstring(doc_string, fn_name)
+ if restored_signature:
+ return create_method_stub(fn_name, fn_class, restored_signature, doc_string)
+ return create_function_stub('unknown', '(*args, **kwargs)', doc_string) + '\nunknown'
+
+ else:
+ return ''
+
+
+def get_docstring(obj):
+ if obj is not None:
+ try:
+ if IS_JYTHON:
+ # Jython
+ doc = obj.__doc__
+ if doc is not None:
+ return doc
+
+ from _pydev_bundle import _pydev_jy_imports_tipper
+
+ is_method, infos = _pydev_jy_imports_tipper.ismethod(obj)
+ ret = ''
+ if is_method:
+ for info in infos:
+ ret += info.get_as_doc()
+ return ret
+
+ else:
+
+ doc = inspect.getdoc(obj)
+ if doc is not None:
+ return doc
+ except:
+ pass
+ else:
+ return ''
+ try:
+ # if no attempt succeeded, try to return repr()...
+ return repr(obj)
+ except:
+ try:
+ # otherwise the class
+ return str(obj.__class__)
+ except:
+ # if all fails, go to an empty string
+ return ''
+
+
+def create_class_stub(class_name, contents):
+ return "class %s(object):\n%s" % (class_name, contents)
+
+
+def create_function_stub(fn_name, fn_argspec, fn_docstring, indent=0):
+ def shift_right(string, prefix):
+ return ''.join(prefix + line for line in string.splitlines(True))
+
+ fn_docstring = shift_right(inspect.cleandoc(fn_docstring), " " * (indent + 1))
+ ret = '''
+def %s%s:
+ """%s"""
+ pass
+''' % (fn_name, fn_argspec, fn_docstring)
+ ret = ret[1:] # remove first /n
+ ret = ret.replace('\t', " ")
+ if indent:
+ prefix = " " * indent
+ ret = shift_right(ret, prefix)
+ return ret
-import os.path
import inspect
+import os.path
import sys
from _pydev_bundle._pydev_tipper_common import do_find
args = '(%s)' % (r)
except TypeError:
#ok, let's see if we can get the arguments from the doc
- args = '()'
- try:
- found = False
- if len(doc) > 0:
- if IS_IPY:
- #Handle case where we have the situation below
- #sort(self, object cmp, object key)
- #sort(self, object cmp, object key, bool reverse)
- #sort(self)
- #sort(self, object cmp)
-
- #Or: sort(self: list, cmp: object, key: object)
- #sort(self: list, cmp: object, key: object, reverse: bool)
- #sort(self: list)
- #sort(self: list, cmp: object)
- if hasattr(obj, '__name__'):
- name = obj.__name__+'('
-
-
- #Fix issue where it was appearing sort(aa)sort(bb)sort(cc) in the same line.
- lines = doc.splitlines()
- if len(lines) == 1:
- c = doc.count(name)
- if c > 1:
- doc = ('\n'+name).join(doc.split(name))
-
-
- major = ''
- for line in doc.splitlines():
- if line.startswith(name) and line.endswith(')'):
- if len(line) > len(major):
- major = line
- if major:
- args = major[major.index('('):]
- found = True
-
-
- if not found:
- i = doc.find('->')
- if i < 0:
- i = doc.find('--')
- if i < 0:
- i = doc.find('\n')
- if i < 0:
- i = doc.find('\r')
-
-
- if i > 0:
- s = doc[0:i]
- s = s.strip()
-
- #let's see if we have a docstring in the first line
- if s[-1] == ')':
- start = s.find('(')
- if start >= 0:
- end = s.find('[')
- if end <= 0:
- end = s.find(')')
- if end <= 0:
- end = len(s)
-
- args = s[start:end]
- if not args[-1] == ')':
- args = args + ')'
-
-
- #now, get rid of unwanted chars
- l = len(args) - 1
- r = []
- for i in xrange(len(args)):
- if i == 0 or i == l:
- r.append(args[i])
- else:
- r.append(check_char(args[i]))
-
- args = ''.join(r)
-
- if IS_IPY:
- if args.startswith('(self:'):
- i = args.find(',')
- if i >= 0:
- args = '(self'+args[i:]
- else:
- args = '(self)'
- i = args.find(')')
- if i > 0:
- args = args[:i+1]
-
- except:
- pass
+ args, doc = signature_from_docstring(doc, getattr(obj, '__name__', None))
retType = TYPE_FUNCTION
return ret
+def signature_from_docstring(doc, obj_name):
+ args = '()'
+ try:
+ found = False
+ if len(doc) > 0:
+ if IS_IPY:
+ # Handle case where we have the situation below
+ # sort(self, object cmp, object key)
+ # sort(self, object cmp, object key, bool reverse)
+ # sort(self)
+ # sort(self, object cmp)
+
+ # Or: sort(self: list, cmp: object, key: object)
+ # sort(self: list, cmp: object, key: object, reverse: bool)
+ # sort(self: list)
+ # sort(self: list, cmp: object)
+ if obj_name:
+ name = obj_name + '('
+
+ # Fix issue where it was appearing sort(aa)sort(bb)sort(cc) in the same line.
+ lines = doc.splitlines()
+ if len(lines) == 1:
+ c = doc.count(name)
+ if c > 1:
+ doc = ('\n' + name).join(doc.split(name))
+
+ major = ''
+ for line in doc.splitlines():
+ if line.startswith(name) and line.endswith(')'):
+ if len(line) > len(major):
+ major = line
+ if major:
+ args = major[major.index('('):]
+ found = True
+
+ if not found:
+ i = doc.find('->')
+ if i < 0:
+ i = doc.find('--')
+ if i < 0:
+ i = doc.find('\n')
+ if i < 0:
+ i = doc.find('\r')
+
+ if i > 0:
+ s = doc[0:i]
+ s = s.strip()
+
+ # let's see if we have a docstring in the first line
+ if s[-1] == ')':
+ start = s.find('(')
+ if start >= 0:
+ end = s.find('[')
+ if end <= 0:
+ end = s.find(')')
+ if end <= 0:
+ end = len(s)
+
+ args = s[start:end]
+ if not args[-1] == ')':
+ args = args + ')'
+
+ # now, get rid of unwanted chars
+ l = len(args) - 1
+ r = []
+ for i in xrange(len(args)):
+ if i == 0 or i == l:
+ r.append(args[i])
+ else:
+ r.append(check_char(args[i]))
+
+ args = ''.join(r)
+
+ if IS_IPY:
+ if args.startswith('(self:'):
+ i = args.find(',')
+ if i >= 0:
+ args = '(self' + args[i:]
+ else:
+ args = '(self)'
+ i = args.find(')')
+ if i > 0:
+ args = args[:i + 1]
-
+ except:
+ pass
+ return args, doc
-import os
-
from _pydev_bundle.pydev_imports import xmlrpclib, _queue, Exec
-import sys
-from _pydevd_bundle.pydevd_constants import IS_JYTHON
+from _pydev_bundle._pydev_calltip_util import get_description
from _pydev_imps._pydev_saved_modules import thread
-from _pydevd_bundle import pydevd_xml
from _pydevd_bundle import pydevd_vars
+from _pydevd_bundle import pydevd_xml
+from _pydevd_bundle.pydevd_constants import IS_JYTHON
from _pydevd_bundle.pydevd_utils import * # @UnusedWildImport
-import traceback
-#=======================================================================================================================
+
+# =======================================================================================================================
# Null
-#=======================================================================================================================
+# =======================================================================================================================
class Null:
"""
Gotten from: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205
return 0
-#=======================================================================================================================
+# =======================================================================================================================
# BaseStdIn
-#=======================================================================================================================
+# =======================================================================================================================
class BaseStdIn:
def __init__(self, original_stdin=sys.stdin, *args, **kwargs):
try:
self.encoding = sys.stdin.encoding
except:
- #Not sure if it's available in all Python versions...
+ # Not sure if it's available in all Python versions...
pass
self.original_stdin = original_stdin
def readline(self, *args, **kwargs):
- #sys.stderr.write('Cannot readline out of the console evaluation\n') -- don't show anything
- #This could happen if the user had done input('enter number).<-- upon entering this, that message would appear,
- #which is not something we want.
+ # sys.stderr.write('Cannot readline out of the console evaluation\n') -- don't show anything
+ # This could happen if the user had done input('enter number).<-- upon entering this, that message would appear,
+ # which is not something we want.
return '\n'
def isatty(self):
- return False #not really a file
+ return False # not really a file
def write(self, *args, **kwargs):
- pass #not available StdIn (but it can be expected to be in the stream interface)
+ pass # not available StdIn (but it can be expected to be in the stream interface)
def flush(self, *args, **kwargs):
- pass #not available StdIn (but it can be expected to be in the stream interface)
+ pass # not available StdIn (but it can be expected to be in the stream interface)
def read(self, *args, **kwargs):
- #in the interactive interpreter, a read and a readline are the same.
+ # in the interactive interpreter, a read and a readline are the same.
return self.readline()
def close(self, *args, **kwargs):
- pass #expected in StdIn
+ pass # expected in StdIn
def __getattr__(self, item):
# it's called if the attribute wasn't found
raise AttributeError("%s has no attribute %s" % (self.original_stdin, item))
-#=======================================================================================================================
+# =======================================================================================================================
# StdIn
-#=======================================================================================================================
+# =======================================================================================================================
class StdIn(BaseStdIn):
'''
Object to be added to stdin (to emulate it as non-blocking while the next line arrives)
self.host = host
def readline(self, *args, **kwargs):
- #Ok, callback into the client to get the new input
+ # Ok, callback into the client to get the new input
try:
server = xmlrpclib.Server('http://%s:%s' % (self.host, self.client_port))
requested_input = server.RequestInput()
if not requested_input:
- return '\n' #Yes, a readline must return something (otherwise we can get an EOFError on the input() call).
+ return '\n' # Yes, a readline must return something (otherwise we can get an EOFError on the input() call).
return requested_input
except:
return '\n'
+ def close(self, *args, **kwargs):
+ pass # expected in StdIn
#=======================================================================================================================
# DebugConsoleStdIn
if not code_fragment.is_single_line:
self.is_single_line = False
-#=======================================================================================================================
+
+# =======================================================================================================================
# BaseInterpreterInterface
-#=======================================================================================================================
+# =======================================================================================================================
class BaseInterpreterInterface:
def __init__(self, mainThread):
self.mainThread = mainThread
try:
help = None
if 'pydoc' in sys.modules:
- pydoc = sys.modules['pydoc'] #Don't import it if it still is not there.
+ pydoc = sys.modules['pydoc'] # Don't import it if it still is not there.
if hasattr(pydoc, 'help'):
- #You never know how will the API be changed, so, let's code defensively here
+ # You never know how will the API be changed, so, let's code defensively here
help = pydoc.help
if not hasattr(help, 'input'):
help = None
except:
- #Just ignore any error here
+ # Just ignore any error here
pass
more = False
sys.stdin = self.create_std_in(debugger, original_in)
try:
if help is not None:
- #This will enable the help() function to work.
+ # This will enable the help() function to work.
try:
try:
help.input = sys.stdin
return more
-
def do_add_exec(self, codeFragment):
'''
Subclasses should override.
'''
raise NotImplementedError()
-
def get_namespace(self):
'''
Subclasses should override.
'''
raise NotImplementedError()
+ def __resolve_reference__(self, text):
+ """
- def getDescription(self, text):
- try:
- obj = None
- if '.' not in text:
- try:
- obj = self.get_namespace()[text]
- except KeyError:
- return ''
+ :type text: str
+ """
+ obj = None
+ if '.' not in text:
+ try:
+ obj = self.get_namespace()[text]
+ except KeyError:
+ pass
- else:
+ if obj is None:
try:
- splitted = text.split('.')
- obj = self.get_namespace()[splitted[0]]
- for t in splitted[1:]:
- obj = getattr(obj, t)
+ obj = self.get_namespace()['__builtins__'][text]
except:
- return ''
+ pass
- if obj is not None:
+ if obj is None:
try:
- if sys.platform.startswith("java"):
- #Jython
- doc = obj.__doc__
- if doc is not None:
- return doc
-
- from _pydev_bundle import _pydev_jy_imports_tipper
-
- is_method, infos = _pydev_jy_imports_tipper.ismethod(obj)
- ret = ''
- if is_method:
- for info in infos:
- ret += info.get_as_doc()
- return ret
-
- else:
- #Python and Iron Python
- import inspect #@UnresolvedImport
-
- doc = inspect.getdoc(obj)
- if doc is not None:
- return doc
+ obj = getattr(self.get_namespace()['__builtins__'], text, None)
except:
pass
+ else:
try:
- #if no attempt succeeded, try to return repr()...
- return repr(obj)
+ last_dot = text.rindex('.')
+ parent_context = text[0:last_dot]
+ res = pydevd_vars.eval_in_context(parent_context, self.get_namespace(), self.get_namespace())
+ obj = getattr(res, text[last_dot + 1:])
except:
- try:
- #otherwise the class
- return str(obj.__class__)
- except:
- #if all fails, go to an empty string
- return ''
+ pass
+ return obj
+
+ def getDescription(self, text):
+ try:
+ obj = self.__resolve_reference__(text)
+ if obj is None:
+ return ''
+ return get_description(obj)
except:
- traceback.print_exc()
return ''
-
def do_exec_code(self, code, is_single_line):
try:
code_fragment = CodeFragment(code, is_single_line)
def execLine(self, line):
return self.do_exec_code(line, True)
-
def execMultipleLines(self, lines):
if IS_JYTHON:
for line in lines.split('\n'):
else:
return self.do_exec_code(lines, False)
-
def interrupt(self):
- self.buffer = None # Also clear the buffer when it's interrupted.
+ self.buffer = None # Also clear the buffer when it's interrupted.
try:
if self.interruptable:
called = False
pass
if not called:
- if hasattr(thread, 'interrupt_main'): #Jython doesn't have it
+ if hasattr(thread, 'interrupt_main'): # Jython doesn't have it
thread.interrupt_main()
else:
- self.mainThread._thread.interrupt() #Jython
+ self.mainThread._thread.interrupt() # Jython
return True
except:
traceback.print_exc()
Used to show console with variables connection.
Always return a frame where the locals map to our internal namespace.
'''
- VIRTUAL_FRAME_ID = "1" # matches PyStackFrameConsole.java
- VIRTUAL_CONSOLE_ID = "console_main" # matches PyThreadConsole.java
+ VIRTUAL_FRAME_ID = "1" # matches PyStackFrameConsole.java
+ VIRTUAL_CONSOLE_ID = "console_main" # matches PyThreadConsole.java
if thread_id == VIRTUAL_CONSOLE_ID and frame_id == VIRTUAL_FRAME_ID:
f = FakeFrame()
- f.f_globals = {} #As globals=locals here, let's simply let it empty (and save a bit of network traffic).
+ f.f_globals = {} # As globals=locals here, let's simply let it empty (and save a bit of network traffic).
f.f_locals = self.get_namespace()
return f
else:
except:
# This happens on Jython embedded in host eclipse
traceback.print_exc()
- sys.stderr.write('pydevd is not available, cannot connect\n',)
+ sys.stderr.write('pydevd is not available, cannot connect\n', )
from _pydev_bundle import pydev_localhost
threading.currentThread().__pydevd_id__ = "console_main"
# it to run in the main thread.
self.exec_queue.put(do_enable_gui)
-#=======================================================================================================================
+
+# =======================================================================================================================
# FakeFrame
-#=======================================================================================================================
+# =======================================================================================================================
class FakeFrame:
'''
Used to show console with variables connection.
CMD_GET_CONCURRENCY_EVENT = 145
CMD_SHOW_RETURN_VALUES = 146
CMD_INPUT_REQUESTED = 147
+CMD_GET_DESCRIPTION = 148
CMD_VERSION = 501
CMD_RETURN = 502
'145': 'CMD_GET_CONCURRENCY_EVENT',
'146': 'CMD_SHOW_RETURN_VALUES',
'147': 'CMD_INPUT_REQUESTED',
+ '148': 'CMD_GET_DESCRIPTION',
'501': 'CMD_VERSION',
'502': 'CMD_RETURN',
except Exception:
return self.make_error_message(seq, get_exception_traceback_str())
+ def make_get_description_message(self, seq, payload):
+ try:
+ return NetCommand(CMD_GET_DESCRIPTION, seq, payload)
+ except Exception:
+ return self.make_error_message(seq, get_exception_traceback_str())
+
def make_get_frame_message(self, seq, payload):
try:
return NetCommand(CMD_GET_FRAME, seq, payload)
cmd = dbg.cmd_factory.make_error_message(self.sequence, "Error evaluating expression " + exc)
dbg.writer.add_command(cmd)
+
+# =======================================================================================================================
+# InternalGetDescription
+# =======================================================================================================================
+class InternalGetDescription(InternalThreadCommand):
+ """ Fetch the variable description stub from the debug console
+ """
+
+ def __init__(self, seq, thread_id, frame_id, expression):
+ self.sequence = seq
+ self.thread_id = thread_id
+ self.frame_id = frame_id
+ self.expression = expression
+
+ def do_it(self, dbg):
+ """ Get completions and write back to the client
+ """
+ try:
+ frame = pydevd_vars.find_frame(self.thread_id, self.frame_id)
+ description = pydevd_console.get_description(frame, self.thread_id, self.frame_id, self.expression)
+ description = pydevd_vars.make_valid_xml_value(quote(description, '/>_= \t'))
+ description_xml = '<xml><var name="" type="" value="%s"/></xml>' % description
+ cmd = dbg.cmd_factory.make_get_description_message(self.sequence, description_xml)
+ dbg.writer.add_command(cmd)
+ except:
+ exc = get_exception_traceback_str()
+ cmd = dbg.cmd_factory.make_error_message(self.sequence, "Error in fetching description" + exc)
+ dbg.writer.add_command(cmd)
+
+
#=======================================================================================================================
# InternalGetBreakpointException
#=======================================================================================================================
'''An helper file for the pydev debugger (REPL) console
'''
-from code import InteractiveConsole
import sys
import traceback
+from code import InteractiveConsole
from _pydev_bundle import _pydev_completer
-from _pydevd_bundle.pydevd_tracing import get_exception_traceback_str
-from _pydevd_bundle.pydevd_vars import make_valid_xml_value
-from _pydev_bundle.pydev_imports import Exec
-from _pydevd_bundle.pydevd_io import IOBuf
from _pydev_bundle.pydev_console_utils import BaseInterpreterInterface, BaseStdIn
+from _pydev_bundle.pydev_imports import Exec
from _pydev_bundle.pydev_override import overrides
from _pydevd_bundle import pydevd_save_locals
+from _pydevd_bundle.pydevd_io import IOBuf
+from _pydevd_bundle.pydevd_tracing import get_exception_traceback_str
+from _pydevd_bundle.pydevd_vars import make_valid_xml_value
CONSOLE_OUTPUT = "output"
CONSOLE_ERROR = "error"
except:
self.showtraceback()
+ def get_namespace(self):
+ dbg_namespace = {}
+ dbg_namespace.update(self.frame.f_globals)
+ dbg_namespace.update(self.frame.f_locals) # locals later because it has precedence over the actual globals
+ return dbg_namespace
+
#=======================================================================================================================
# InteractiveConsoleCache
def get_interactive_console(thread_id, frame_id, frame, console_message):
"""returns the global interactive console.
interactive console should have been initialized by this time
+ :rtype: DebugConsole
"""
if InteractiveConsoleCache.thread_id == thread_id and InteractiveConsoleCache.frame_id == frame_id:
return InteractiveConsoleCache.interactive_console_instance
return console_message
+def get_description(frame, thread_id, frame_id, expression):
+ console_message = ConsoleMessage()
+ interpreter = get_interactive_console(thread_id, frame_id, frame, console_message)
+ try:
+ interpreter.frame = frame
+ return interpreter.getDescription(expression)
+ finally:
+ interpreter.frame = None
+
+
def get_completions(frame, act_tok):
""" fetch all completions, create xml for the same
return the completions xml
CMD_SET_PY_EXCEPTION, CMD_GET_FILE_CONTENTS, CMD_SET_PROPERTY_TRACE, CMD_ADD_EXCEPTION_BREAK, \
CMD_REMOVE_EXCEPTION_BREAK, CMD_LOAD_SOURCE, CMD_ADD_DJANGO_EXCEPTION_BREAK, CMD_REMOVE_DJANGO_EXCEPTION_BREAK, \
CMD_EVALUATE_CONSOLE_EXPRESSION, InternalEvaluateConsoleExpression, InternalConsoleGetCompletions, \
- CMD_RUN_CUSTOM_OPERATION, InternalRunCustomOperation, CMD_IGNORE_THROWN_EXCEPTION_AT, CMD_ENABLE_DONT_TRACE,\
- CMD_SHOW_RETURN_VALUES, ID_TO_MEANING
+ CMD_RUN_CUSTOM_OPERATION, InternalRunCustomOperation, CMD_IGNORE_THROWN_EXCEPTION_AT, CMD_ENABLE_DONT_TRACE, \
+ CMD_SHOW_RETURN_VALUES, ID_TO_MEANING, CMD_GET_DESCRIPTION, InternalGetDescription
from _pydevd_bundle.pydevd_constants import get_thread_id, IS_PY3K, DebugInfoHolder, dict_contains, dict_keys, dict_pop, \
STATE_RUN
-import pydevd_file_utils
def process_net_command(py_db, cmd_id, seq, text):
except:
traceback.print_exc()
+ elif cmd_id == CMD_GET_DESCRIPTION:
+ try:
+
+ thread_id, frame_id, expression = text.split('\t', 2)
+ int_cmd = InternalGetDescription(seq, thread_id, frame_id, expression)
+ py_db.post_internal_command(int_cmd, thread_id)
+ except:
+ traceback.print_exc()
elif cmd_id == CMD_GET_FRAME:
thread_id, frame_id, scope = text.split('\t', 2)
public class PyResolveContext {
private final boolean myAllowImplicits;
private final boolean myAllowProperties;
+ private final boolean myAllowRemote;
private final TypeEvalContext myTypeEvalContext;
+
private PyResolveContext(boolean allowImplicits, boolean allowProperties) {
myAllowImplicits = allowImplicits;
myAllowProperties = allowProperties;
myTypeEvalContext = null;
+ myAllowRemote = false;
}
- private PyResolveContext(boolean allowImplicits, boolean allowProperties, TypeEvalContext typeEvalContext) {
+
+ private PyResolveContext(boolean allowImplicits, boolean allowProperties, boolean allowRemote, TypeEvalContext typeEvalContext) {
myAllowImplicits = allowImplicits;
myAllowProperties = allowProperties;
+ myAllowRemote = allowRemote;
myTypeEvalContext = typeEvalContext;
}
return myAllowProperties;
}
+ public boolean allowRemote() {
+ return myAllowRemote;
+ }
+
private static final PyResolveContext ourDefaultContext = new PyResolveContext(true, true);
private static final PyResolveContext ourNoImplicitsContext = new PyResolveContext(false, true);
private static final PyResolveContext ourNoPropertiesContext = new PyResolveContext(false, false);
}
public PyResolveContext withTypeEvalContext(@NotNull TypeEvalContext context) {
- return new PyResolveContext(myAllowImplicits, myAllowProperties, context);
+ return new PyResolveContext(myAllowImplicits, myAllowProperties, myAllowRemote, context);
}
public PyResolveContext withoutImplicits() {
- return new PyResolveContext(false, myAllowProperties, myTypeEvalContext);
+ return new PyResolveContext(false, myAllowProperties, myAllowRemote, myTypeEvalContext);
+ }
+
+ public PyResolveContext withRemote() {
+ return new PyResolveContext(myAllowImplicits, myAllowProperties, true, myTypeEvalContext);
}
public TypeEvalContext getTypeEvalContext() {
public static final int LOAD_SOURCE = 124;
public static final int SMART_STEP_INTO = 128;
public static final int EXIT = 129;
-
+ public static final int GET_DESCRIPTION = 148;
+
+
public static final int CALL_SIGNATURE_TRACE = 130;
public static final int CMD_SET_PY_EXCEPTION = 131;
public static final int SHOW_RETURN_VALUES = 146;
public static final int INPUT_REQUESTED = 147;
+
public static final int ERROR = 901;
public static final int VERSION = 501;
--- /dev/null
+package com.jetbrains.python.debugger.pydev;
+
+import com.jetbrains.python.debugger.PyDebugValue;
+import com.jetbrains.python.debugger.PyDebuggerException;
+
+/**
+ * @author traff
+ */
+public class GetDescriptionCommand extends AbstractFrameCommand {
+
+ private String myActionToken;
+ private String result = null;
+
+ public GetDescriptionCommand(final RemoteDebugger debugger, String threadId, String frameId, final String myActionToken) {
+ super(debugger, GET_DESCRIPTION, threadId, frameId);
+ this.myActionToken = myActionToken;
+ }
+
+
+ @Override
+ public boolean isResponseExpected() {
+ return true;
+ }
+
+ @Override
+ protected void processResponse(ProtocolFrame response) throws PyDebuggerException {
+ super.processResponse(response);
+ try {
+ PyDebugValue pyDebugValue = ProtocolParser.parseValue(response.getPayload(), getDebugger().getDebugProcess());
+ result = pyDebugValue.getValue();
+ }
+ catch (Exception e) {
+ throw new PyDebuggerException("cant obtain completions", e);
+ }
+ }
+
+
+ @Override
+ protected void buildPayload(Payload payload) {
+ super.buildPayload(payload);
+ payload.add(myActionToken);
+ }
+
+ public String getResult() {
+ return result;
+ }
+}
return debugger(threadId).getCompletions(threadId, frameId, prefix);
}
+ @Override
+ public String getDescription(String threadId, String frameId, String cmd) {
+ return debugger(threadId).getDescription(threadId, frameId, cmd);
+ }
+
@Override
public void addExceptionBreakpoint(ExceptionBreakpointCommandFactory factory) {
for (RemoteDebugger d : allDebuggers()) {
List<PydevCompletionVariant> getCompletions(String threadId, String frameId, String prefix);
+ String getDescription(String threadId, String frameId, String cmd);
+
+
void addExceptionBreakpoint(ExceptionBreakpointCommandFactory factory);
void removeExceptionBreakpoint(ExceptionBreakpointCommandFactory factory);
import com.jetbrains.python.debugger.*;
import com.thoughtworks.xstream.io.naming.NoNameCoder;
import com.thoughtworks.xstream.io.xml.XppReader;
+import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.xmlpull.mxp1.MXParser;
}
private static String readString(final XppReader reader, final String name, final String fallback) throws PyDebuggerException {
- final String value;
- try {
- value = read(reader, name);
- }
- catch (PyDebuggerException e) {
- if (fallback != null) {
- return fallback;
- }
- else {
- throw e;
- }
- }
- return decode(value);
+ final String value = read(reader, name, fallback == null);
+ return value == null ? fallback : value;
}
private static int readInt(final XppReader reader, final String name, final Integer fallback) throws PyDebuggerException {
- final String value;
- try {
- value = read(reader, name);
- }
- catch (PyDebuggerException e) {
- if (fallback != null) {
- return fallback;
- }
- else {
- throw e;
- }
+ final String value = read(reader, name, fallback == null);
+ if (value == null) {
+ return fallback;
}
try {
return Integer.parseInt(value);
}
}
- private static String read(final XppReader reader, final String name) throws PyDebuggerException {
+ @Contract("_, _, true -> !null")
+ private static String read(final XppReader reader, final String name, boolean isRequired) throws PyDebuggerException {
final String value = reader.getAttribute(name);
- if (value == null) {
+ if (value == null && isRequired) {
throw new PyDebuggerException("Attribute not found: " + name);
}
- return value;
+ return value == null ? null : decode(value);
}
}
return command.getCompletions();
}
+ @Override
+ public String getDescription(String threadId, String frameId, String cmd) {
+ final GetDescriptionCommand command = new GetDescriptionCommand(this, threadId, frameId, cmd);
+ execute(command);
+ return command.getResult();
+ }
+
@Override
public void addExceptionBreakpoint(ExceptionBreakpointCommandFactory factory) {
execute(factory.createAddCommand(this));
final PyCallExpression callExpr = argumentList.getCallExpression();
if (callExpr != null) {
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(argumentList.getProject(), argumentList.getContainingFile());
- final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(typeEvalContext);
+ final PyResolveContext resolveContext = PyResolveContext.noImplicits().withRemote().withTypeEvalContext(typeEvalContext);
final PyCallExpression.PyArgumentsMapping mapping = callExpr.mapArguments(resolveContext);
if (mapping.getMarkedCallee() != null) {
context.setItemsToShow(new Object[] { mapping });
PyPsiUtils.assertValid(callExpression);
// really we need to redo analysis every UI update; findElementForParameterInfo isn't called while typing
final TypeEvalContext typeEvalContext = TypeEvalContext.userInitiated(callExpression.getProject(), callExpression.getContainingFile());
- final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(typeEvalContext);
+ final PyResolveContext resolveContext = PyResolveContext.noImplicits().withRemote().withTypeEvalContext(typeEvalContext);
final PyCallExpression.PyArgumentsMapping mapping = callExpression.mapArguments(resolveContext);
final PyMarkedCallee marked = mapping.getMarkedCallee();
if (marked == null) return; // resolution failed
package com.jetbrains.python.console;
import com.intellij.lang.documentation.AbstractDocumentationProvider;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.console.completion.PydevConsoleElement;
-import com.jetbrains.python.console.pydev.ConsoleCommunication;
-import com.jetbrains.python.psi.PyExpression;
+import com.jetbrains.python.console.completion.PydevConsoleReference;
+import com.jetbrains.python.documentation.PyDocumentationBuilder;
+import com.jetbrains.python.psi.PyElement;
+import com.jetbrains.python.psi.PyReferenceExpression;
+import com.jetbrains.python.psi.PyUtil;
import org.jetbrains.annotations.Nullable;
/**
@Nullable
public static String createDoc(final PsiElement element, final PsiElement originalElement) {
- final PyExpression expression = PsiTreeUtil.getParentOfType(originalElement, PyExpression.class);
+ final PyReferenceExpression expression = PsiTreeUtil.getNonStrictParentOfType(originalElement, PyReferenceExpression.class);
// Indicates that we are inside console, not a lookup element!
if (expression == null){
return null;
}
- final ConsoleCommunication communication = PydevConsoleRunner.getConsoleCommunication(originalElement);
- if (communication == null){
+ PydevConsoleReference consoleRef = PyUtil.as(expression.getReference(), PydevConsoleReference.class);
+ if (consoleRef == null) { //shouldn't really happen!
return null;
}
- try {
- final String description = communication.getDescription(expression.getText());
- return StringUtil.isEmptyOrSpaces(description) ? null : description;
- }
- catch (Exception e) {
+ PyElement documentationElement = consoleRef.getDocumentationElement();
+ if (documentationElement == null) {
return null;
}
+
+ return new PyDocumentationBuilder(documentationElement, null).build();
+
}
}
}
@Override
- public String getDescription(String text) {
- return null;
+ public String getDescription(String refExpression) throws Exception {
+ return myDebugProcess.getDescription(refExpression);
}
@Override
*/
package com.jetbrains.python.console.completion;
+import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.intellij.codeInsight.completion.CompletionInitializationContext;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiManager;
-import com.intellij.psi.PsiPolyVariantReferenceBase;
-import com.intellij.psi.ResolveResult;
+import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.console.pydev.ConsoleCommunication;
import com.jetbrains.python.console.pydev.IToken;
import com.jetbrains.python.console.pydev.PyCodeCompletionImages;
import com.jetbrains.python.console.pydev.PydevCompletionVariant;
-import com.jetbrains.python.psi.PyFile;
-import com.jetbrains.python.psi.PyReferenceExpression;
+import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.resolve.RatedResolveResult;
import org.jetbrains.annotations.NotNull;
import java.util.List;
* @author oleg
*/
public class PydevConsoleReference extends PsiPolyVariantReferenceBase<PyReferenceExpression> {
+
private final ConsoleCommunication myCommunication;
private final String myPrefix;
+ private final boolean myAllowRemoteResolve;
public PydevConsoleReference(final PyReferenceExpression expression,
- final ConsoleCommunication communication,
- final String prefix) {
+ final ConsoleCommunication communication, final String prefix, boolean allowRemoteResolve) {
super(expression, true);
myCommunication = communication;
myPrefix = prefix;
+ myAllowRemoteResolve = allowRemoteResolve;
}
@NotNull
public ResolveResult[] multiResolve(boolean incompleteCode) {
- return ResolveResult.EMPTY_ARRAY;
+ if (!myAllowRemoteResolve) {
+ return RatedResolveResult.EMPTY_ARRAY;
+ }
+ PyExpression pyExpression = resolveToDummyDescription();
+ if (pyExpression == null) {
+ return RatedResolveResult.EMPTY_ARRAY;
+ }
+
+ if (pyExpression instanceof PyReferenceExpression) {
+ final PsiReference redirectedRef = pyExpression.getReference();
+ if (redirectedRef != null) {
+ PsiElement resolved = redirectedRef.resolve();
+ if (resolved != null) {
+ return new ResolveResult[]{new RatedResolveResult(RatedResolveResult.RATE_HIGH, resolved)};
+ }
+ }
+ }
+
+ return RatedResolveResult.EMPTY_ARRAY;
+
+ }
+
+ public PyElement getDocumentationElement() {
+ return resolveToDummyDescription();
+ }
+
+
+ private PyExpression resolveToDummyDescription() {
+ String qualifiedName = myElement.getText();
+ if (qualifiedName == null) {
+ return null;
+ }
+ String description;
+ try {
+
+ description = myCommunication.getDescription(qualifiedName);
+ if (Strings.isNullOrEmpty(description)) {
+ return null;
+ }
+ }
+ catch (Exception e) {
+ return null;
+ }
+
+ PyElementGenerator generator = PyElementGenerator.getInstance(myElement.getProject());
+ PyFile dummyFile = (PyFile)generator.createDummyFile(LanguageLevel.forElement(myElement), description);
+ Module module = ModuleUtilCore.findModuleForPsiElement(myElement);
+ if (module != null) {
+ dummyFile.putUserData(ModuleUtilCore.KEY_MODULE, module);
+ }
+
+ List<PyStatement> statements = dummyFile.getStatements();
+ PyStatement pyStatement = statements.get(statements.size() - 1);
+ return pyStatement instanceof PyExpressionStatement ? ((PyExpressionStatement)pyStatement).getExpression() : null;
}
@NotNull
final PsiManager manager = myElement.getManager();
final String name = completion.getName();
final int type = completion.getType();
- LookupElementBuilder builder = LookupElementBuilder
- .create(new PydevConsoleElement(manager, name, completion.getDescription()))
+ LookupElementBuilder builder = LookupElementBuilder.create(new PydevConsoleElement(manager, name, completion.getDescription()))
.withIcon(PyCodeCompletionImages.getImageForType(type));
private PythonConsoleData myPythonConsoleData;
private boolean myIPythonStartSymbol;
- public PyConsoleParser(PythonConsoleData pythonConsoleData) {
+ public PyConsoleParser(PythonConsoleData pythonConsoleData, LanguageLevel languageLevel) {
myPythonConsoleData = pythonConsoleData;
- myLanguageLevel = LanguageLevel.getDefault();
+ myLanguageLevel = languageLevel;
}
@NotNull
return Lists.newArrayList();
}
+ @NotNull
+ public String getDescription(String prefix) throws Exception {
+ if (isConnected()) {
+ dropFrameCaches();
+ final PyStackFrame frame = currentFrame();
+ return myDebugger.getDescription(frame.getThreadId(), frame.getFrameId(), prefix);
+ }
+ return "";
+ }
+
+
@Override
public void startNotified(ProcessEvent event) {
}
myColored = colored;
}
+ @Override
+ public boolean getColored() {
+ return myColored;
+ }
+
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
*/
package com.jetbrains.python.debugger.array;
+import com.google.common.base.Strings;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.table.JBTable;
import org.jetbrains.annotations.NotNull;
@Override
protected void paintComponent(@NotNull Graphics g) {
- getEmptyText().setText("");
+ if (!Strings.isNullOrEmpty(getEmptyText().getText())) {
+ getEmptyText().setText("");
+ }
super.paintComponent(g);
}
@Override
public int getRowHeight(int row) {
- setRowHeight(myMainTable.getRowHeight());
+ int height = super.getRowHeight();
+ if (height != myMainTable.getRowHeight()) {
+ setRowHeight(myMainTable.getRowHeight());
+ }
return super.getRowHeight(row);
}
*/
public interface ColoredCellRenderer extends TableCellRenderer {
void setColored(boolean colored);
+
+ boolean getColored();
}
myComponent.getSliceTextField().setText(chunk.getSlicePresentation());
myComponent.getFormatTextField().setText(chunk.getFormat());
myDialog.setTitle(getTitlePresentation(chunk.getSlicePresentation()));
+ boolean shouldSetColored = myTableCellRenderer == null || myTableCellRenderer.getColored();
myTableCellRenderer = createCellRenderer(Double.MIN_VALUE, Double.MIN_VALUE, chunk);
if (!isNumeric()) {
disableColor();
}
else {
myComponent.getColoredCheckbox().setEnabled(true);
+ myComponent.getColoredCheckbox().setSelected(shouldSetColored);
+ myTableCellRenderer.setColored(shouldSetColored);
}
if (!inPlace) {
myValue.isErrorOnEval(), myValue.isReturnedVal(),
myValue.getParent(), myValue.getFrameAccessor());
- return myValue.getFrameAccessor().getArrayItems(slicedValue, rowOffset, colOffset, rows, cols, getFormat());
+ final String format = getFormat().isEmpty() ? "%" : getFormat();
+ return myValue.getFrameAccessor().getArrayItems(slicedValue, rowOffset, colOffset, rows, cols, format);
}
public abstract boolean isNumeric();
@Override
public void update(AnActionEvent e) {
+ e.getPresentation().setVisible(false);
TreePath[] paths = getSelectedPaths(e.getDataContext());
if (paths != null) {
if (paths.length > 1) {
myColored = colored;
}
+ @Override
+ public boolean getColored() {
+ return myColored;
+ }
+
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
final Project project = psi.getProject();
final PsiBuilderFactory factory = PsiBuilderFactory.getInstance();
final PsiBuilder builder = factory.createBuilder(project, node, lexer, getLanguage(), node.getChars());
- final PyParser parser = new PyConsoleParser(consoleData);
+ final PyParser parser = new PyConsoleParser(consoleData, getLanguageLevel(psi));
return parser.parse(this, builder).getFirstChildNode();
}
final ConsoleCommunication communication = file.getCopyableUserData(PydevConsoleRunner.CONSOLE_KEY);
if (communication != null) {
if (qualifier != null) {
- return new PydevConsoleReference(this, communication, qualifier.getText() + ".");
+ return new PydevConsoleReference(this, communication, qualifier.getText() + ".", context.allowRemote());
}
- return new PydevConsoleReference(this, communication, "");
+ return new PydevConsoleReference(this, communication, "", context.allowRemote());
}
if (qualifier != null) {