mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
add support for parameter info in console
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
'''
|
||||
Id: "$Id$"
|
||||
Copyright: Copyright (c) 2015 Bank of America Merrill Lynch, All Rights Reserved
|
||||
Description:
|
||||
Test:
|
||||
'''
|
||||
# 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
|
||||
@@ -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
|
||||
|
||||
@@ -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,66 +285,48 @@ class BaseInterpreterInterface:
|
||||
'''
|
||||
raise NotImplementedError()
|
||||
|
||||
def __resolve_reference__(self, text):
|
||||
"""
|
||||
|
||||
def getDescription(self, text):
|
||||
try:
|
||||
obj = None
|
||||
if '.' not in text:
|
||||
:type text: str
|
||||
"""
|
||||
obj = None
|
||||
if '.' not in text:
|
||||
try:
|
||||
obj = self.get_namespace()[text]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if obj is None:
|
||||
try:
|
||||
obj = self.get_namespace()[text]
|
||||
except KeyError:
|
||||
return ''
|
||||
|
||||
else:
|
||||
try:
|
||||
splitted = text.split('.')
|
||||
obj = self.get_namespace()[splitted[0]]
|
||||
for t in splitted[1:]:
|
||||
obj = getattr(obj, t)
|
||||
except:
|
||||
return ''
|
||||
|
||||
if obj is not 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 = self.get_namespace()['__builtins__'][text]
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
#if no attempt succeeded, try to return repr()...
|
||||
return repr(obj)
|
||||
except:
|
||||
if obj is None:
|
||||
try:
|
||||
#otherwise the class
|
||||
return str(obj.__class__)
|
||||
obj = getattr(self.get_namespace()['__builtins__'], text, None)
|
||||
except:
|
||||
#if all fails, go to an empty string
|
||||
return ''
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return ''
|
||||
pass
|
||||
|
||||
else:
|
||||
try:
|
||||
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:
|
||||
pass
|
||||
return obj
|
||||
|
||||
def getDescription(self, text):
|
||||
try:
|
||||
obj = self.__resolve_reference__(text)
|
||||
if obj is None:
|
||||
return ''
|
||||
return get_description(obj)
|
||||
except:
|
||||
return ''
|
||||
|
||||
def do_exec_code(self, code, is_single_line):
|
||||
try:
|
||||
@@ -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.
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = resolveFromStub();
|
||||
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 resolveFromStub();
|
||||
}
|
||||
|
||||
|
||||
private PyExpression resolveFromStub() {
|
||||
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));
|
||||
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user