Merge remote-tracking branch 'origin/master'
authorDmitry Trofimov <dmitry.trofimov@jetbrains.com>
Tue, 30 Aug 2016 18:50:44 +0000 (20:50 +0200)
committerDmitry Trofimov <dmitry.trofimov@jetbrains.com>
Tue, 30 Aug 2016 18:50:44 +0000 (20:50 +0200)
27 files changed:
python/helpers/pydev/_pydev_bundle/_pydev_calltip_util.py [new file with mode: 0644]
python/helpers/pydev/_pydev_bundle/_pydev_imports_tipper.py
python/helpers/pydev/_pydev_bundle/pydev_console_utils.py
python/helpers/pydev/_pydevd_bundle/pydevd_comm.py
python/helpers/pydev/_pydevd_bundle/pydevd_console.py
python/helpers/pydev/_pydevd_bundle/pydevd_process_net_command.py
python/psi-api/src/com/jetbrains/python/psi/resolve/PyResolveContext.java
python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java
python/pydevSrc/com/jetbrains/python/debugger/pydev/GetDescriptionCommand.java [new file with mode: 0644]
python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java
python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java
python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java
python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java
python/src/com/jetbrains/python/PyParameterInfoHandler.java
python/src/com/jetbrains/python/console/PydevDocumentationProvider.java
python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java
python/src/com/jetbrains/python/console/completion/PydevConsoleReference.java
python/src/com/jetbrains/python/console/parsing/PyConsoleParser.java
python/src/com/jetbrains/python/debugger/PyDebugProcess.java
python/src/com/jetbrains/python/debugger/array/ArrayTableCellRenderer.java
python/src/com/jetbrains/python/debugger/array/JBTableWithRowHeaders.java
python/src/com/jetbrains/python/debugger/containerview/ColoredCellRenderer.java
python/src/com/jetbrains/python/debugger/containerview/NumericContainerViewTable.java
python/src/com/jetbrains/python/debugger/containerview/PyViewNumericContainerAction.java
python/src/com/jetbrains/python/debugger/dataframe/DataFrameTableCellRenderer.java
python/src/com/jetbrains/python/psi/PyFileElementType.java
python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java

diff --git a/python/helpers/pydev/_pydev_bundle/_pydev_calltip_util.py b/python/helpers/pydev/_pydev_bundle/_pydev_calltip_util.py
new file mode 100644 (file)
index 0000000..b846fb4
--- /dev/null
@@ -0,0 +1,158 @@
+'''
+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
index c05c04e521b07e9041a2e12b545947aa66d39a6a..7ee92090f0e8fee91e14b05eacbcb887861fc6ee 100644 (file)
@@ -1,5 +1,5 @@
-import os.path
 import inspect
+import os.path
 import sys
 
 from _pydev_bundle._pydev_tipper_common import do_find
@@ -222,96 +222,7 @@ def generate_imports_tip_for_module(obj_to_complete, dirComps=None, getattr=geta
                             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
 
@@ -350,5 +261,90 @@ def generate_imports_tip_for_module(obj_to_complete, dirComps=None, getattr=geta
     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
index e9d0a6998a8725eddb6989e35dcc9eab1f1e99c0..9d612005e9f37facd3d893c867029dbe29cfb313 100644 (file)
@@ -1,17 +1,15 @@
-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
@@ -54,39 +52,39 @@ class Null:
         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
@@ -95,9 +93,9 @@ class BaseStdIn:
         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)
@@ -110,16 +108,18 @@ class StdIn(BaseStdIn):
         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
@@ -155,9 +155,10 @@ class CodeFragment:
         if not code_fragment.is_single_line:
             self.is_single_line = False
 
-#=======================================================================================================================
+
+# =======================================================================================================================
 # BaseInterpreterInterface
-#=======================================================================================================================
+# =======================================================================================================================
 class BaseInterpreterInterface:
     def __init__(self, mainThread):
         self.mainThread = mainThread
@@ -206,15 +207,15 @@ class BaseInterpreterInterface:
         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
@@ -222,7 +223,7 @@ class BaseInterpreterInterface:
             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
@@ -268,7 +269,6 @@ class BaseInterpreterInterface:
 
         return more
 
-
     def do_add_exec(self, codeFragment):
         '''
         Subclasses should override.
@@ -277,7 +277,6 @@ class BaseInterpreterInterface:
         '''
         raise NotImplementedError()
 
-
     def get_namespace(self):
         '''
         Subclasses should override.
@@ -286,67 +285,49 @@ class BaseInterpreterInterface:
         '''
         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)
@@ -364,7 +345,6 @@ class BaseInterpreterInterface:
     def execLine(self, line):
         return self.do_exec_code(line, True)
 
-
     def execMultipleLines(self, lines):
         if IS_JYTHON:
             for line in lines.split('\n'):
@@ -372,9 +352,8 @@ class BaseInterpreterInterface:
         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
@@ -412,10 +391,10 @@ class BaseInterpreterInterface:
                     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()
@@ -495,11 +474,11 @@ class BaseInterpreterInterface:
         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:
@@ -527,7 +506,7 @@ class BaseInterpreterInterface:
             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"
@@ -589,9 +568,10 @@ class BaseInterpreterInterface:
         # it to run in the main thread.
         self.exec_queue.put(do_enable_gui)
 
-#=======================================================================================================================
+
+# =======================================================================================================================
 # FakeFrame
-#=======================================================================================================================
+# =======================================================================================================================
 class FakeFrame:
     '''
     Used to show console with variables connection.
index 70566d248c165cdd211915f07f03e8053ae3ebbf..1c3f2a3ee69a3ac083aa4f59dfa7098113c34bd1 100644 (file)
@@ -139,6 +139,7 @@ CMD_STEP_INTO_MY_CODE = 144
 CMD_GET_CONCURRENCY_EVENT = 145
 CMD_SHOW_RETURN_VALUES = 146
 CMD_INPUT_REQUESTED = 147
+CMD_GET_DESCRIPTION = 148
 
 CMD_VERSION = 501
 CMD_RETURN = 502
@@ -193,6 +194,7 @@ ID_TO_MEANING = {
     '145': 'CMD_GET_CONCURRENCY_EVENT',
     '146': 'CMD_SHOW_RETURN_VALUES',
     '147': 'CMD_INPUT_REQUESTED',
+    '148': 'CMD_GET_DESCRIPTION',
 
     '501': 'CMD_VERSION',
     '502': 'CMD_RETURN',
@@ -700,6 +702,12 @@ class NetCommandFactory:
         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)
@@ -1135,6 +1143,36 @@ class InternalGetCompletions(InternalThreadCommand):
             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
 #=======================================================================================================================
index d35cdc9df39dbe35e7cb3e07021c86a9ed2534a2..b48daae2703a197cf8e0bcc634f88fc1724090ab 100644 (file)
@@ -1,17 +1,17 @@
 '''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"
@@ -160,6 +160,12 @@ class DebugConsole(InteractiveConsole, BaseInterpreterInterface):
         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
@@ -175,6 +181,7 @@ class 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
@@ -218,6 +225,16 @@ def execute_console_command(frame, thread_id, frame_id, line, buffer_output=True
     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
index 2b7783cbe8ca97cf540020df8994b47755bd0e1f..dec84ed73369cdf535d12a6da12db211a4123e12 100644 (file)
@@ -16,11 +16,10 @@ from _pydevd_bundle.pydevd_comm import CMD_RUN, CMD_VERSION, CMD_LIST_THREADS, C
     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):
@@ -229,6 +228,14 @@ 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)
index 860cef734a1dd86af781eee9244b9dcb283ac366..3cd3c0809bddcd74b650a05dba32bd6622f8ab81 100644 (file)
@@ -24,17 +24,22 @@ import org.jetbrains.annotations.NotNull;
 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;
   }
 
@@ -46,6 +51,10 @@ public class PyResolveContext {
     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);
@@ -63,11 +72,15 @@ public class PyResolveContext {
   }
 
   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() {
index 941e39343ba47a5dbec25a14d8b0f005a52f1810..9090238a6a457db1b7e3f9506d3647d6abd6355f 100644 (file)
@@ -30,7 +30,9 @@ public abstract class AbstractCommand<T> {
   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;
@@ -52,6 +54,7 @@ public abstract class AbstractCommand<T> {
   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;
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetDescriptionCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetDescriptionCommand.java
new file mode 100644 (file)
index 0000000..ca216c7
--- /dev/null
@@ -0,0 +1,47 @@
+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;
+  }
+}
index 042b455f3f1b3e6f7b40eb35923849cbfaf745a5..9b3231974b933dd2b1a6c672d1487be09515098b 100644 (file)
@@ -518,6 +518,11 @@ public class MultiProcessDebugger implements ProcessDebugger {
     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()) {
index 99c8908ab5c97e59ed9683e3d9f1c106add82372..186dd53a569d625b4b21b2782624706f2c360943 100644 (file)
@@ -87,6 +87,9 @@ public interface ProcessDebugger {
 
   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);
index 34b860897cc57deb53a81e0d52ac283830a7c389..71c7ab7d745f08d931af428cca3ac6995a6eeb82 100644 (file)
@@ -5,6 +5,7 @@ import com.intellij.openapi.util.text.StringUtil;
 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;
 
@@ -383,33 +384,14 @@ public class ProtocolParser {
   }
 
   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);
@@ -419,11 +401,12 @@ public class ProtocolParser {
     }
   }
 
-  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);
   }
 }
index 457947dc9431e6a6390078824a41ec9b48590a9f..3149e42efa5e46e895d6b3ca24e6c60ee0fc9069 100644 (file)
@@ -761,6 +761,13 @@ public class RemoteDebugger implements ProcessDebugger {
     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));
index d704f26ae5ca57753b427375fd049700bd5aabfe..4307c6d6d0faa68090db7e324d7f63acbe0050fc 100644 (file)
@@ -65,7 +65,7 @@ public class PyParameterInfoHandler implements ParameterInfoHandler<PyArgumentLi
       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 });
@@ -152,7 +152,7 @@ public class PyParameterInfoHandler implements ParameterInfoHandler<PyArgumentLi
     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
index fc131a44771d9230453f06fd507b047d026e0f86..65905172a12a873d872ac63beaf448df990281ee 100644 (file)
 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;
 
 /**
@@ -49,21 +51,21 @@ public class PydevDocumentationProvider extends AbstractDocumentationProvider {
 
   @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();
+
   }
 }
index 78ecbf99578b3d29bd0f261c85a3fc81e0cc6332..f0a16fcb3b69146a718eddddbd0fa39e034bc595 100644 (file)
@@ -55,8 +55,8 @@ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunicatio
   }
 
   @Override
-  public String getDescription(String text) {
-    return null;
+  public String getDescription(String refExpression) throws Exception {
+    return myDebugProcess.getDescription(refExpression);
   }
 
   @Override
index 6fb65ae80ca0859910c5b076f99fbabe4fba3d8f..735e225fe044b393f235f82ce24641b9bf5a6acf 100644 (file)
@@ -15,6 +15,7 @@
  */
 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;
@@ -24,19 +25,18 @@ import com.intellij.codeInsight.lookup.LookupElement;
 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;
@@ -46,20 +46,75 @@ import java.util.Map;
  * @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
@@ -71,8 +126,7 @@ public class PydevConsoleReference extends PsiPolyVariantReferenceBase<PyReferen
         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));
 
 
index d0a6854bf6347bb0a347216b3946d12b2b7abc30..b09bb3300c11cca86deaa934a10d78efec9e9786 100644 (file)
@@ -33,9 +33,9 @@ public class PyConsoleParser extends PyParser{
   private PythonConsoleData myPythonConsoleData;
   private boolean myIPythonStartSymbol;
 
-  public PyConsoleParser(PythonConsoleData pythonConsoleData) {
+  public PyConsoleParser(PythonConsoleData pythonConsoleData, LanguageLevel languageLevel) {
     myPythonConsoleData = pythonConsoleData;
-    myLanguageLevel = LanguageLevel.getDefault();
+    myLanguageLevel = languageLevel;
   }
 
   @NotNull
index 913a7a8c73c646ac1e6f17e34df1464a6073d375..99df44bd5403e2ed934627bdfa32400611e53986 100644 (file)
@@ -901,6 +901,17 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
     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) {
   }
index 046af042c57f98e4935e0ccb12114d41a1d6859e..379902756851f6a163f6a878d10a6dd78eba2eb9 100644 (file)
@@ -50,6 +50,11 @@ class ArrayTableCellRenderer extends DefaultTableCellRenderer implements Colored
     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);
index b204cd56960429ed23136b524d845dc7dbfeea10..511d82fd4ca18e25b5d90c164ea71cba1789007e 100644 (file)
@@ -15,6 +15,7 @@
  */
 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;
@@ -87,7 +88,9 @@ public class JBTableWithRowHeaders extends JBTable {
 
     @Override
     protected void paintComponent(@NotNull Graphics g) {
-      getEmptyText().setText("");
+      if (!Strings.isNullOrEmpty(getEmptyText().getText())) {
+        getEmptyText().setText("");
+      }
       super.paintComponent(g);
     }
 
@@ -105,7 +108,10 @@ public class JBTableWithRowHeaders extends JBTable {
 
     @Override
     public int getRowHeight(int row) {
-      setRowHeight(myMainTable.getRowHeight());
+      int height = super.getRowHeight();
+      if (height != myMainTable.getRowHeight()) {
+        setRowHeight(myMainTable.getRowHeight());
+      }
       return super.getRowHeight(row);
     }
 
index c26de6c87141c88e2797ae5c8d25459c150af93d..9ce0471c37066a5353d4ea9533092b120c2b68fc 100644 (file)
@@ -22,4 +22,6 @@ import javax.swing.table.TableCellRenderer;
  */
 public interface ColoredCellRenderer extends TableCellRenderer {
   void setColored(boolean colored);
+
+  boolean getColored();
 }
index 2a3c75df8aa0a1cf3be304695b1af0337247ff01..263b69daf670e66779705b5595ac815cc6eb6c83 100644 (file)
@@ -82,12 +82,15 @@ public abstract class NumericContainerViewTable implements TableChunkDatasource
       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) {
@@ -227,7 +230,8 @@ public abstract class NumericContainerViewTable implements TableChunkDatasource
                        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();
index 28675739859544b1a871f8773ce2d688484e4a6e..17b354c99e67ed3409ce4c3e2b69d2a47c31c54d 100644 (file)
@@ -72,6 +72,7 @@ public class PyViewNumericContainerAction extends XDebuggerTreeActionBase {
 
   @Override
   public void update(AnActionEvent e) {
+    e.getPresentation().setVisible(false);
     TreePath[] paths = getSelectedPaths(e.getDataContext());
     if (paths != null) {
       if (paths.length > 1) {
index 76946ce79e433cc3ead02d50dd3fca37814f35ee..72eec940f57827480a537ecea34ae2798ad2f84f 100644 (file)
@@ -41,6 +41,11 @@ class DataFrameTableCellRenderer extends DefaultTableCellRenderer implements Col
     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);
index 6358424b5d55fc68723cb585c4c3fd68fb565059..11cd013273ee3c3c3114666ea827799f8c49cbdc 100644 (file)
@@ -106,7 +106,7 @@ public class PyFileElementType extends IStubFileElementType<PyFileStub> {
       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();
     }
index 417b7f495632bb5ccdcabffcbb8fd714be4a026c..5915ff454435deceea84f11458caa33dee662362 100644 (file)
@@ -83,9 +83,9 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
     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) {