mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-07 22:44:27 +08:00
goto done including 22 tests! vim plugin is not done yet
This commit is contained in:
11
evaluate.py
11
evaluate.py
@@ -33,6 +33,7 @@ import imports
|
|||||||
import helpers
|
import helpers
|
||||||
|
|
||||||
memoize_caches = []
|
memoize_caches = []
|
||||||
|
statement_path = []
|
||||||
|
|
||||||
|
|
||||||
class DecoratorNotFound(LookupError):
|
class DecoratorNotFound(LookupError):
|
||||||
@@ -69,9 +70,15 @@ class MultiLevelAttributeError(Exception):
|
|||||||
|
|
||||||
|
|
||||||
def clear_caches():
|
def clear_caches():
|
||||||
|
global memoize_caches
|
||||||
|
global statement_path
|
||||||
|
|
||||||
for m in memoize_caches:
|
for m in memoize_caches:
|
||||||
m.clear()
|
m.clear()
|
||||||
|
|
||||||
|
memoize_caches = []
|
||||||
|
statement_path = []
|
||||||
|
|
||||||
follow_statement.reset()
|
follow_statement.reset()
|
||||||
|
|
||||||
|
|
||||||
@@ -1038,6 +1045,8 @@ def follow_statement(stmt, seek_name=None):
|
|||||||
:param stmt: contains a statement
|
:param stmt: contains a statement
|
||||||
:param scope: contains a scope. If not given, takes the parent of stmt.
|
:param scope: contains a scope. If not given, takes the parent of stmt.
|
||||||
"""
|
"""
|
||||||
|
statement_path.append(stmt) # important to know for the goto function
|
||||||
|
|
||||||
debug.dbg('follow_stmt %s (%s)' % (stmt, seek_name))
|
debug.dbg('follow_stmt %s (%s)' % (stmt, seek_name))
|
||||||
call_list = stmt.get_assignment_calls()
|
call_list = stmt.get_assignment_calls()
|
||||||
debug.dbg('calls: %s' % call_list)
|
debug.dbg('calls: %s' % call_list)
|
||||||
@@ -1086,10 +1095,10 @@ def follow_call_list(call_list):
|
|||||||
result.append(call)
|
result.append(call)
|
||||||
# The string tokens are just operations (+, -, etc.)
|
# The string tokens are just operations (+, -, etc.)
|
||||||
elif not isinstance(call, str):
|
elif not isinstance(call, str):
|
||||||
# Ternary operators.
|
|
||||||
#if str(call.name) == 'for': <--- list comprehensions
|
#if str(call.name) == 'for': <--- list comprehensions
|
||||||
# print '\n\ndini mueter'
|
# print '\n\ndini mueter'
|
||||||
if str(call.name) == 'if':
|
if str(call.name) == 'if':
|
||||||
|
# Ternary operators.
|
||||||
while True:
|
while True:
|
||||||
call = next(calls_iterator)
|
call = next(calls_iterator)
|
||||||
try:
|
try:
|
||||||
|
|||||||
44
functions.py
44
functions.py
@@ -7,16 +7,10 @@ import modules
|
|||||||
import debug
|
import debug
|
||||||
import imports
|
import imports
|
||||||
|
|
||||||
__all__ = ['complete', 'get_completion_parts', 'get_definitions',
|
|
||||||
'set_debug_function']
|
|
||||||
|
|
||||||
|
|
||||||
class NotFoundError(Exception):
|
class NotFoundError(Exception):
|
||||||
""" A custom error to avoid catching the wrong errors """
|
""" A custom error to avoid catching the wrong exceptions """
|
||||||
def __init__(self, scope, path_tuple, message=None):
|
pass
|
||||||
super(NotFoundError, self).__init__(message)
|
|
||||||
self.scope = scope
|
|
||||||
self.path_tuple = path_tuple
|
|
||||||
|
|
||||||
|
|
||||||
class Completion(object):
|
class Completion(object):
|
||||||
@@ -175,14 +169,14 @@ def prepare_goto(source, position, source_path, module, goto_path,
|
|||||||
|
|
||||||
user_stmt = module.parser.user_stmt
|
user_stmt = module.parser.user_stmt
|
||||||
if isinstance(user_stmt, parsing.Import):
|
if isinstance(user_stmt, parsing.Import):
|
||||||
scopes = [imports.ImportPath(user_stmt, is_like_search)]
|
scopes = [imports.ImportPath2(user_stmt, is_like_search)]
|
||||||
else:
|
else:
|
||||||
# just parse one statement, take it and evaluate it
|
# just parse one statement, take it and evaluate it
|
||||||
r = parsing.PyFuzzyParser(goto_path, source_path)
|
r = parsing.PyFuzzyParser(goto_path, source_path)
|
||||||
try:
|
try:
|
||||||
stmt = r.top.statements[0]
|
stmt = r.top.statements[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise NotFoundError(scope, goto_path)
|
raise NotFoundError()
|
||||||
else:
|
else:
|
||||||
stmt.start_pos = position
|
stmt.start_pos = position
|
||||||
stmt.parent = scope
|
stmt.parent = scope
|
||||||
@@ -217,6 +211,36 @@ def get_definitions(source, line, column, source_path):
|
|||||||
return [Definition(s) for s in set(scopes)]
|
return [Definition(s) for s in set(scopes)]
|
||||||
|
|
||||||
|
|
||||||
|
def goto(source, line, column, source_path):
|
||||||
|
pos = (line, column)
|
||||||
|
f = modules.ModuleWithCursor(source_path, source=source, position=pos)
|
||||||
|
|
||||||
|
goto_path = f.get_path_under_cursor()
|
||||||
|
goto_path, dot, search_name = get_completion_parts(goto_path)
|
||||||
|
|
||||||
|
# define goto path the right way
|
||||||
|
if not dot:
|
||||||
|
goto_path = search_name
|
||||||
|
search_name = None
|
||||||
|
|
||||||
|
scopes = prepare_goto(source, pos, source_path, f, goto_path)
|
||||||
|
if not dot:
|
||||||
|
try:
|
||||||
|
definitions = [evaluate.statement_path[1]]
|
||||||
|
except IndexError:
|
||||||
|
definitions = scopes
|
||||||
|
else:
|
||||||
|
names = []
|
||||||
|
#print 's', scopes
|
||||||
|
for s in scopes:
|
||||||
|
names += s.get_defined_names()
|
||||||
|
definitions = [n.parent for n in names if n.names[-1] == search_name]
|
||||||
|
#print evaluate.statement_path
|
||||||
|
#print scopes, definitions
|
||||||
|
_clear_caches()
|
||||||
|
return definitions
|
||||||
|
|
||||||
|
|
||||||
def set_debug_function(func_cb):
|
def set_debug_function(func_cb):
|
||||||
"""
|
"""
|
||||||
You can define a callback debug function to get all the debug messages.
|
You can define a callback debug function to get all the debug messages.
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ class ImportPath(object):
|
|||||||
f = builtin.Parser(name=path)
|
f = builtin.Parser(name=path)
|
||||||
|
|
||||||
return f.parser.top, rest
|
return f.parser.top, rest
|
||||||
|
ImportPath2 = ImportPath
|
||||||
|
|
||||||
def strip_imports(scopes):
|
def strip_imports(scopes):
|
||||||
"""
|
"""
|
||||||
@@ -141,6 +142,8 @@ def strip_imports(scopes):
|
|||||||
result = []
|
result = []
|
||||||
for s in scopes:
|
for s in scopes:
|
||||||
if isinstance(s, parsing.Import):
|
if isinstance(s, parsing.Import):
|
||||||
|
# this is something like a statement following.
|
||||||
|
evaluate.statement_path.append(s)
|
||||||
try:
|
try:
|
||||||
result += ImportPath(s).follow()
|
result += ImportPath(s).follow()
|
||||||
except ModuleNotFound:
|
except ModuleNotFound:
|
||||||
|
|||||||
61
test/run.py
61
test/run.py
@@ -7,6 +7,7 @@ import traceback
|
|||||||
os.chdir(os.path.dirname(os.path.abspath(__file__)) + '/..')
|
os.chdir(os.path.dirname(os.path.abspath(__file__)) + '/..')
|
||||||
sys.path.append('.')
|
sys.path.append('.')
|
||||||
import functions
|
import functions
|
||||||
|
import evaluate
|
||||||
from _compatibility import unicode, BytesIO
|
from _compatibility import unicode, BytesIO
|
||||||
|
|
||||||
only_line = int(sys.argv[2]) if len(sys.argv) > 2 else None
|
only_line = int(sys.argv[2]) if len(sys.argv) > 2 else None
|
||||||
@@ -77,6 +78,56 @@ def run_definition_test(correct, source, line_nr, line, correct_start, path):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def run_goto_test(correct, source, line_nr, line, path):
|
||||||
|
"""
|
||||||
|
Runs tests for gotos.
|
||||||
|
Tests look like this:
|
||||||
|
>>> abc = 1
|
||||||
|
>>> #! ['abc=1']
|
||||||
|
>>> abc
|
||||||
|
|
||||||
|
Additionally it is possible to add a number which describes to position of
|
||||||
|
the test (otherwise it's just end of line.
|
||||||
|
>>> #! 2 ['abc=1']
|
||||||
|
>>> abc
|
||||||
|
|
||||||
|
For the tests the important things in the end are the positions.
|
||||||
|
|
||||||
|
Return if the test was a fail or not, with 1 for fail and 0 for success.
|
||||||
|
"""
|
||||||
|
r = re.match('^(\d+)\s*(.*)$', correct)
|
||||||
|
if r:
|
||||||
|
index = int(r.group(1))
|
||||||
|
correct = r.group(2)
|
||||||
|
else:
|
||||||
|
index = len(line)
|
||||||
|
try:
|
||||||
|
result = functions.goto(source, line_nr, index, path)
|
||||||
|
except Exception:
|
||||||
|
print('test @%s: %s' % (line_nr - 1, line))
|
||||||
|
print(traceback.format_exc())
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
lst = []
|
||||||
|
for r in result:
|
||||||
|
if isinstance(r, evaluate.InstanceElement):
|
||||||
|
r = r.var
|
||||||
|
if isinstance(r, (evaluate.Class, evaluate.Instance)):
|
||||||
|
r = 'class ' + str(r.name)
|
||||||
|
elif isinstance(r, (evaluate.Function, evaluate.parsing.Function)):
|
||||||
|
r = 'def ' + str(r.name)
|
||||||
|
else:
|
||||||
|
r = r.get_code().replace('\n', '')
|
||||||
|
lst.append(r)
|
||||||
|
comp_str = str(sorted(lst))
|
||||||
|
if comp_str != correct:
|
||||||
|
print('Solution @%s not right, received %s, wanted %s'\
|
||||||
|
% (line_nr - 1, comp_str, correct))
|
||||||
|
print result
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def run_test(source, f_name):
|
def run_test(source, f_name):
|
||||||
"""
|
"""
|
||||||
This is the completion test for some cases. The tests are not unit test
|
This is the completion test for some cases. The tests are not unit test
|
||||||
@@ -102,7 +153,9 @@ def run_test(source, f_name):
|
|||||||
# if a list is wanted, use the completion test, otherwise the
|
# if a list is wanted, use the completion test, otherwise the
|
||||||
# get_definition test
|
# get_definition test
|
||||||
path = completion_test_dir + os.path.sep + f_name
|
path = completion_test_dir + os.path.sep + f_name
|
||||||
if correct.startswith('['):
|
if test_type == '!':
|
||||||
|
fails += run_goto_test(correct, source, line_nr, line, path)
|
||||||
|
elif correct.startswith('['):
|
||||||
fails += run_completion_test(correct, source, line_nr, line,
|
fails += run_completion_test(correct, source, line_nr, line,
|
||||||
path)
|
path)
|
||||||
else:
|
else:
|
||||||
@@ -112,8 +165,10 @@ def run_test(source, f_name):
|
|||||||
tests += 1
|
tests += 1
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
r = re.search(r'(?:^|(?<=\s))#\?\s*([^\n]+)', line)
|
r = re.search(r'(?:^|(?<=\s))#([?!])\s*([^\n]+)', line)
|
||||||
correct = r.group(1)
|
# test_type is ? for completion and ! for goto
|
||||||
|
test_type = r.group(1)
|
||||||
|
correct = r.group(2)
|
||||||
start = r.start()
|
start = r.start()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
correct = None
|
correct = None
|
||||||
|
|||||||
Reference in New Issue
Block a user