mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-07 06:24:27 +08:00
follow_statement -> eval_statement
This commit is contained in:
@@ -242,7 +242,7 @@ class Script(object):
|
|||||||
else:
|
else:
|
||||||
# just parse one statement, take it and evaluate it
|
# just parse one statement, take it and evaluate it
|
||||||
stmt = self._get_under_cursor_stmt(goto_path)
|
stmt = self._get_under_cursor_stmt(goto_path)
|
||||||
scopes = self._evaluator.follow_statement(stmt)
|
scopes = self._evaluator.eval_statement(stmt)
|
||||||
return scopes
|
return scopes
|
||||||
|
|
||||||
def _get_under_cursor_stmt(self, cursor_txt):
|
def _get_under_cursor_stmt(self, cursor_txt):
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ class Completion(BaseDefinition):
|
|||||||
"""
|
"""
|
||||||
if self._followed_definitions is None:
|
if self._followed_definitions is None:
|
||||||
if self._definition.isinstance(pr.Statement):
|
if self._definition.isinstance(pr.Statement):
|
||||||
defs = self._evaluator.follow_statement(self._definition)
|
defs = self._evaluator.eval_statement(self._definition)
|
||||||
elif self._definition.isinstance(pr.Import):
|
elif self._definition.isinstance(pr.Import):
|
||||||
defs = imports.strip_imports(self._evaluator, [self._definition])
|
defs = imports.strip_imports(self._evaluator, [self._definition])
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ def follow_param(evaluator, param):
|
|||||||
p = Parser(param_str, None, user_position, no_docstr=True)
|
p = Parser(param_str, None, user_position, no_docstr=True)
|
||||||
if p.user_stmt is None:
|
if p.user_stmt is None:
|
||||||
return []
|
return []
|
||||||
return evaluator.follow_statement(p.user_stmt)
|
return evaluator.eval_statement(p.user_stmt)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
@@ -127,4 +127,4 @@ def find_return_types(evaluator, func):
|
|||||||
if p.user_stmt is None:
|
if p.user_stmt is None:
|
||||||
return []
|
return []
|
||||||
p.user_stmt.parent = func
|
p.user_stmt.parent = func
|
||||||
return list(evaluator.follow_statement(p.user_stmt))
|
return list(evaluator.eval_statement(p.user_stmt))
|
||||||
|
|||||||
@@ -11,23 +11,23 @@ Evaluation of Python code in |jedi| is based on three assumptions:
|
|||||||
* The programmer is not a total dick, e.g. like `this
|
* The programmer is not a total dick, e.g. like `this
|
||||||
<https://github.com/davidhalter/jedi/issues/24>`_ :-)
|
<https://github.com/davidhalter/jedi/issues/24>`_ :-)
|
||||||
|
|
||||||
That said, there's mainly one entry point in this script: ``follow_statement``.
|
That said, there's mainly one entry point in this script: ``eval_statement``.
|
||||||
This is where autocompletion starts. Everything you want to complete is either
|
This is where autocompletion starts. Everything you want to complete is either
|
||||||
a ``Statement`` or some special name like ``class``, which is easy to complete.
|
a ``Statement`` or some special name like ``class``, which is easy to complete.
|
||||||
|
|
||||||
Therefore you need to understand what follows after ``follow_statement``. Let's
|
Therefore you need to understand what follows after ``eval_statement``. Let's
|
||||||
make an example::
|
make an example::
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
datetime.date.toda# <-- cursor here
|
datetime.date.toda# <-- cursor here
|
||||||
|
|
||||||
First of all, this module doesn't care about completion. It really just cares
|
First of all, this module doesn't care about completion. It really just cares
|
||||||
about ``datetime.date``. At the end of the procedure ``follow_statement`` will
|
about ``datetime.date``. At the end of the procedure ``eval_statement`` will
|
||||||
return the ``datetime`` class.
|
return the ``datetime`` class.
|
||||||
|
|
||||||
To *visualize* this (simplified):
|
To *visualize* this (simplified):
|
||||||
|
|
||||||
- ``follow_statement`` - ``<Statement: datetime.date>``
|
- ``eval_statement`` - ``<Statement: datetime.date>``
|
||||||
|
|
||||||
- Unpacking of the statement into ``[[<Call: datetime.date>]]``
|
- Unpacking of the statement into ``[[<Call: datetime.date>]]``
|
||||||
- ``follow_call_list``, calls ``follow_call`` with ``<Call: datetime.date>``
|
- ``follow_call_list``, calls ``follow_call`` with ``<Call: datetime.date>``
|
||||||
@@ -50,7 +50,7 @@ import would contain another Statement like this::
|
|||||||
from foo import bar
|
from foo import bar
|
||||||
Date = bar.baz
|
Date = bar.baz
|
||||||
|
|
||||||
Well... You get it. Just another ``follow_statement`` recursion. It's really
|
Well... You get it. Just another ``eval_statement`` recursion. It's really
|
||||||
easy. Just that Python is not that easy sometimes. To understand tuple
|
easy. Just that Python is not that easy sometimes. To understand tuple
|
||||||
assignments and different class scopes, a lot more code had to be written. Yet
|
assignments and different class scopes, a lot more code had to be written. Yet
|
||||||
we're still not talking about Descriptors and Nested List Comprehensions, just
|
we're still not talking about Descriptors and Nested List Comprehensions, just
|
||||||
@@ -280,7 +280,7 @@ class Evaluator(object):
|
|||||||
#if r.docstr:
|
#if r.docstr:
|
||||||
#res_new.append(r)
|
#res_new.append(r)
|
||||||
|
|
||||||
scopes = self.follow_statement(r, seek_name=name_str)
|
scopes = self.eval_statement(r, seek_name=name_str)
|
||||||
add += remove_statements(scopes)
|
add += remove_statements(scopes)
|
||||||
|
|
||||||
if check_instance is not None:
|
if check_instance is not None:
|
||||||
@@ -310,7 +310,7 @@ class Evaluator(object):
|
|||||||
# one, remember `in`). And follow it.
|
# one, remember `in`). And follow it.
|
||||||
if not loop.inputs:
|
if not loop.inputs:
|
||||||
return []
|
return []
|
||||||
result = get_iterator_types(self.follow_statement(loop.inputs[0]))
|
result = get_iterator_types(self.eval_statement(loop.inputs[0]))
|
||||||
if len(loop.set_vars) > 1:
|
if len(loop.set_vars) > 1:
|
||||||
commands = loop.set_stmt.get_commands()
|
commands = loop.set_stmt.get_commands()
|
||||||
# loops with loop.set_vars > 0 only have one command
|
# loops with loop.set_vars > 0 only have one command
|
||||||
@@ -478,7 +478,7 @@ class Evaluator(object):
|
|||||||
|
|
||||||
@memoize_default(default=(), evaluator_is_first_arg=True)
|
@memoize_default(default=(), evaluator_is_first_arg=True)
|
||||||
@recursion.recursion_decorator
|
@recursion.recursion_decorator
|
||||||
def follow_statement(self, stmt, seek_name=None):
|
def eval_statement(self, stmt, seek_name=None):
|
||||||
"""
|
"""
|
||||||
The starting point of the completion. A statement always owns a call list,
|
The starting point of the completion. A statement always owns a call list,
|
||||||
which are the calls, that a statement does.
|
which are the calls, that a statement does.
|
||||||
@@ -488,9 +488,8 @@ class Evaluator(object):
|
|||||||
:param stmt: A `pr.Statement`.
|
:param stmt: A `pr.Statement`.
|
||||||
:param seek_name: A string.
|
:param seek_name: A string.
|
||||||
"""
|
"""
|
||||||
debug.dbg('follow_stmt %s (%s)' % (stmt, seek_name))
|
debug.dbg('eval_statement %s (%s)' % (stmt, seek_name))
|
||||||
commands = stmt.get_commands()
|
commands = stmt.get_commands()
|
||||||
debug.dbg('calls: %s' % commands)
|
|
||||||
|
|
||||||
result = self.follow_call_list(commands)
|
result = self.follow_call_list(commands)
|
||||||
|
|
||||||
@@ -526,11 +525,12 @@ class Evaluator(object):
|
|||||||
loop = evaluate_list_comprehension(nested_lc, loop)
|
loop = evaluate_list_comprehension(nested_lc, loop)
|
||||||
return loop
|
return loop
|
||||||
|
|
||||||
|
debug.dbg('follow_call_list: %s' % call_list)
|
||||||
result = []
|
result = []
|
||||||
calls_iterator = iter(call_list)
|
calls_iterator = iter(call_list)
|
||||||
for call in calls_iterator:
|
for call in calls_iterator:
|
||||||
if pr.Array.is_type(call, pr.Array.NOARRAY):
|
if pr.Array.is_type(call, pr.Array.NOARRAY):
|
||||||
r = list(itertools.chain.from_iterable(self.follow_statement(s)
|
r = list(itertools.chain.from_iterable(self.eval_statement(s)
|
||||||
for s in call))
|
for s in call))
|
||||||
call_path = call.generate_call_path()
|
call_path = call.generate_call_path()
|
||||||
next(call_path, None) # the first one has been used already
|
next(call_path, None) # the first one has been used already
|
||||||
@@ -541,7 +541,7 @@ class Evaluator(object):
|
|||||||
# Caveat: parents are being changed, but this doesn't matter,
|
# Caveat: parents are being changed, but this doesn't matter,
|
||||||
# because nothing else uses it.
|
# because nothing else uses it.
|
||||||
call.stmt.parent = loop
|
call.stmt.parent = loop
|
||||||
result += self.follow_statement(call.stmt)
|
result += self.eval_statement(call.stmt)
|
||||||
else:
|
else:
|
||||||
if isinstance(call, pr.Lambda):
|
if isinstance(call, pr.Lambda):
|
||||||
result.append(er.Function(self, call))
|
result.append(er.Function(self, call))
|
||||||
@@ -582,7 +582,9 @@ class Evaluator(object):
|
|||||||
return self.follow_call_path(path, s.parent, s.start_pos)
|
return self.follow_call_path(path, s.parent, s.start_pos)
|
||||||
|
|
||||||
def follow_call_path(self, path, scope, position):
|
def follow_call_path(self, path, scope, position):
|
||||||
"""Follows a path generated by `pr.StatementElement.generate_call_path()`"""
|
"""
|
||||||
|
Follows a path generated by `pr.StatementElement.generate_call_path()`.
|
||||||
|
"""
|
||||||
current = next(path)
|
current = next(path)
|
||||||
|
|
||||||
if isinstance(current, pr.Array):
|
if isinstance(current, pr.Array):
|
||||||
@@ -635,7 +637,7 @@ class Evaluator(object):
|
|||||||
current = next(path)
|
current = next(path)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
return None
|
return None
|
||||||
debug.dbg('follow %s in scope %s' % (current, scope))
|
debug.dbg('follow_path: %s in scope %s' % (current, scope))
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
if isinstance(current, pr.Array):
|
if isinstance(current, pr.Array):
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ def search_params(evaluator, param):
|
|||||||
for params in get_posibilities(evaluator, module, func_name):
|
for params in get_posibilities(evaluator, module, func_name):
|
||||||
for p in params:
|
for p in params:
|
||||||
if str(p) == param_name:
|
if str(p) == param_name:
|
||||||
result += evaluator.follow_statement(p.parent)
|
result += evaluator.eval_statement(p.parent)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
func = param.get_parent_until(pr.Function)
|
func = param.get_parent_until(pr.Function)
|
||||||
@@ -317,17 +317,17 @@ def _check_array_additions(evaluator, compare_array, module, is_list):
|
|||||||
continue # no params: just ignore it
|
continue # no params: just ignore it
|
||||||
if add_name in ['append', 'add']:
|
if add_name in ['append', 'add']:
|
||||||
for param in params:
|
for param in params:
|
||||||
result += evaluator.follow_statement(param)
|
result += evaluator.eval_statement(param)
|
||||||
elif add_name in ['insert']:
|
elif add_name in ['insert']:
|
||||||
try:
|
try:
|
||||||
second_param = params[1]
|
second_param = params[1]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
result += evaluator.follow_statement(second_param)
|
result += evaluator.eval_statement(second_param)
|
||||||
elif add_name in ['extend', 'update']:
|
elif add_name in ['extend', 'update']:
|
||||||
for param in params:
|
for param in params:
|
||||||
iterators = evaluator.follow_statement(param)
|
iterators = evaluator.eval_statement(param)
|
||||||
result += evaluate.get_iterator_types(iterators)
|
result += evaluate.get_iterator_types(iterators)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -411,7 +411,7 @@ class ArrayInstance(pr.Base):
|
|||||||
items = []
|
items = []
|
||||||
from jedi import evaluate
|
from jedi import evaluate
|
||||||
for stmt in self.var_args:
|
for stmt in self.var_args:
|
||||||
for typ in self._evaluator.follow_statement(stmt):
|
for typ in self._evaluator.eval_statement(stmt):
|
||||||
if isinstance(typ, evaluate.er.Instance) and len(typ.var_args):
|
if isinstance(typ, evaluate.er.Instance) and len(typ.var_args):
|
||||||
array = typ.var_args[0]
|
array = typ.var_args[0]
|
||||||
if isinstance(array, ArrayInstance):
|
if isinstance(array, ArrayInstance):
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ class Class(use_metaclass(CachedMetaClass, pr.IsScope)):
|
|||||||
# TODO care for mro stuff (multiple super classes).
|
# TODO care for mro stuff (multiple super classes).
|
||||||
for s in self.base.supers:
|
for s in self.base.supers:
|
||||||
# Super classes are statements.
|
# Super classes are statements.
|
||||||
for cls in self._evaluator.follow_statement(s):
|
for cls in self._evaluator.eval_statement(s):
|
||||||
if not isinstance(cls, Class):
|
if not isinstance(cls, Class):
|
||||||
debug.warning('Received non class, as a super class')
|
debug.warning('Received non class, as a super class')
|
||||||
continue # Just ignore other stuff (user input error).
|
continue # Just ignore other stuff (user input error).
|
||||||
@@ -343,7 +343,7 @@ class Function(use_metaclass(CachedMetaClass, pr.IsScope)):
|
|||||||
if not self.is_decorated:
|
if not self.is_decorated:
|
||||||
for dec in reversed(self.base_func.decorators):
|
for dec in reversed(self.base_func.decorators):
|
||||||
debug.dbg('decorator:', dec, f)
|
debug.dbg('decorator:', dec, f)
|
||||||
dec_results = set(self._evaluator.follow_statement(dec))
|
dec_results = set(self._evaluator.eval_statement(dec))
|
||||||
if not len(dec_results):
|
if not len(dec_results):
|
||||||
debug.warning('decorator not found: %s on %s' %
|
debug.warning('decorator not found: %s on %s' %
|
||||||
(dec, self.base_func))
|
(dec, self.base_func))
|
||||||
@@ -416,7 +416,7 @@ class Execution(Executable):
|
|||||||
return []
|
return []
|
||||||
else:
|
else:
|
||||||
if isinstance(stmt, pr.Statement):
|
if isinstance(stmt, pr.Statement):
|
||||||
return self._evaluator.follow_statement(stmt)
|
return self._evaluator.eval_statement(stmt)
|
||||||
else:
|
else:
|
||||||
return [stmt] # just some arbitrary object
|
return [stmt] # just some arbitrary object
|
||||||
|
|
||||||
@@ -512,7 +512,7 @@ class Execution(Executable):
|
|||||||
stmts = docstrings.find_return_types(self._evaluator, func)
|
stmts = docstrings.find_return_types(self._evaluator, func)
|
||||||
for r in self.returns:
|
for r in self.returns:
|
||||||
if r is not None:
|
if r is not None:
|
||||||
stmts += self._evaluator.follow_statement(r)
|
stmts += self._evaluator.eval_statement(r)
|
||||||
return stmts
|
return stmts
|
||||||
|
|
||||||
@memoize_default(default=())
|
@memoize_default(default=())
|
||||||
@@ -889,7 +889,7 @@ class Array(use_metaclass(CachedMetaClass, pr.Base, Iterable)):
|
|||||||
|
|
||||||
def _follow_values(self, values):
|
def _follow_values(self, values):
|
||||||
""" helper function for the index getters """
|
""" helper function for the index getters """
|
||||||
return list(itertools.chain.from_iterable(self._evaluator.follow_statement(v)
|
return list(itertools.chain.from_iterable(self._evaluator.eval_statement(v)
|
||||||
for v in values))
|
for v in values))
|
||||||
|
|
||||||
def get_defined_names(self):
|
def get_defined_names(self):
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ def test_complete_on_empty_import():
|
|||||||
assert 10 < len(Script("from . import", 1, 5, '').completions()) < 30
|
assert 10 < len(Script("from . import", 1, 5, '').completions()) < 30
|
||||||
assert 10 < len(Script("from . import classes", 1, 5, '').completions()) < 30
|
assert 10 < len(Script("from . import classes", 1, 5, '').completions()) < 30
|
||||||
assert len(Script("import").completions()) == 0
|
assert len(Script("import").completions()) == 0
|
||||||
if not is_py26:
|
if not is_py26: # python 2.6 doesn't always come with a library `import*`.
|
||||||
assert len(Script("import import", path='').completions()) > 0
|
assert len(Script("import import", path='').completions()) > 0
|
||||||
|
|
||||||
# 111
|
# 111
|
||||||
|
|||||||
Reference in New Issue
Block a user