1
0
forked from VimPlug/jedi

evaluate docstring, much better documentation

This commit is contained in:
David Halter
2012-08-30 12:54:33 +02:00
parent dd0cc343f8
commit e2a4e097f6

View File

@@ -69,6 +69,11 @@ class MultiLevelAttributeError(Exception):
def clear_caches():
"""
Clears all caches of this and related modules. Jedi caches many things,
that should be completed after each completion finishes. The only things
that stays is the module cache (which is not deleted here).
"""
global memoize_caches, statement_path, faked_scopes
for m in memoize_caches:
@@ -259,6 +264,10 @@ class Instance(Executable):
class InstanceElement(object):
"""
InstanceElement is a wrapper for any object, that is used as an instance
variable (e.g. self.variable or class methods).
"""
__metaclass__ = CachedMetaClass
def __init__(self, instance, var):
@@ -310,6 +319,10 @@ class InstanceElement(object):
class Class(parsing.Base):
"""
This class is not only important to extend `parsing.Class`, it is also a
important for descriptors (if the descriptor methods are evaluated or not).
"""
__metaclass__ = CachedMetaClass
def __init__(self, base):
@@ -366,6 +379,7 @@ class Class(parsing.Base):
class Function(parsing.Base):
"""
Needed because of decorators. Decorators are evaluated here.
"""
__metaclass__ = CachedMetaClass
@@ -438,15 +452,14 @@ class Execution(Executable):
This class is used to evaluate functions and their returns.
This is the most complicated class, because it contains the logic to
transfer parameters. This is even more complicated, because there may be
multiple call to functions and recursion has to be avoided.
transfer parameters. It is even more complicated, because there may be
multiple calls to functions and recursion has to be avoided. But this is
responsibility of the decorators.
"""
@memoize_default(default=[])
@helpers.ExecutionRecursionDecorator
def get_return_types(self, evaluate_generator=False):
"""
Get the return vars of a function.
"""
""" Get the return types of a function. """
stmts = []
if isinstance(self.base, Class):
# There maybe executions of executions.
@@ -644,6 +657,12 @@ class Execution(Executable):
return self.get_params() + parsing.Scope.get_set_vars(self)
def copy_properties(self, prop):
"""
Literally copies a property of a Function. Copying is very expensive,
because it is something like `copy.deepcopy`. However, these copied
objects can be used for the executions, as if they were in the
execution.
"""
# Copy all these lists into this local function.
attr = getattr(self.base, prop)
objects = []
@@ -685,6 +704,7 @@ class Execution(Executable):
class Generator(parsing.Base):
""" Cares for `yield` statements. """
__metaclass__ = CachedMetaClass
def __init__(self, func, var_args):
super(Generator, self).__init__()
@@ -814,6 +834,9 @@ class Array(parsing.Base):
class ArrayElement(object):
"""
A name, e.g. `list.append`, it is used to access to original array methods.
"""
def __init__(self, name):
super(ArrayElement, self).__init__()
self.name = name
@@ -828,15 +851,18 @@ class ArrayElement(object):
return "<%s of %s>" % (self.__class__.__name__, self.name)
def get_defined_names_for_position(obj, position=None, start_scope=None):
def get_defined_names_for_position(scope, position=None, start_scope=None):
"""
Deletes all names that are ahead of the position, except for some special
objects like instances, where the position doesn't matter.
:param position: the position as a line/column tuple, default is infinity.
"""
names = obj.get_defined_names()
names = scope.get_defined_names()
# Instances have special rules, always return all the possible completions,
# because class variables are always valid and the `self.` variables, too.
if not position or isinstance(obj, (Instance, Array)) \
or start_scope != obj \
if not position or isinstance(scope, (Instance, Array)) \
or start_scope != scope \
and isinstance(start_scope, (parsing.Function, Execution)):
return names
names_new = []
@@ -889,6 +915,10 @@ def get_names_for_scope(scope, position=None, star_search=True,
def get_scopes_for_name(scope, name_str, position=None, search_global=False):
"""
This is the search function. The most important part to debug.
`remove_statements` and `filter_statements` really are the core part of
this completion.
:param position: Position of the last statement -> tuple of line, column
:return: List of Names. Their parents are the scopes, they are defined in.
:rtype: list
@@ -945,6 +975,10 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
return res_new
def filter_name(scope_generator):
"""
Filters all variables of a scope (which are defined in the
`scope_generator`), until the name fits.
"""
def handle_for_loops(loop):
# Take the first statement (for has always only
# one, remember `in`). And follow it.
@@ -954,7 +988,11 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
result = assign_tuples(var_arr, result, name_str)
return result
def handle_non_arrays(name):
def process(name):
"""
Returns the parent of a name, which means the element which stands
behind a name.
"""
result = []
no_break_scope = False
if isinstance(scope, InstanceElement) \
@@ -1020,7 +1058,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
and isinstance(p.var, parsing.Class):
p = p.var
if name_str == name.get_code() and p not in break_scopes:
r, no_break_scope = handle_non_arrays(name)
r, no_break_scope = process(name)
result += r
# for comparison we need the raw class
s = scope.base if isinstance(scope, Class) else scope
@@ -1037,6 +1075,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
return result
def descriptor_check(result):
""" Processes descriptors """
res_new = []
for r in result:
if isinstance(scope, (Instance, Class)) \
@@ -1060,6 +1099,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
def get_iterator_types(inputs):
""" Returns the types of any iterator (arrays, yields, __iter__, etc). """
iterators = []
# Take the first statement (for has always only
# one, remember `in`). And follow it.
@@ -1148,7 +1188,13 @@ def assign_tuples(tup, results, seek_name):
@memoize_default(default=[])
def follow_statement(stmt, seek_name=None):
"""
:param stmt: contains a statement
The starting point of the completion. A statement always owns a call list,
which are the calls, that a statement does.
In case multiple names are defined in the statement, `seek_name` returns
the result for this name.
:param stmt: A `parsing.Statement`.
:param seek_name:
"""
statement_path.append(stmt) # important to know for the goto function
@@ -1283,6 +1329,9 @@ def follow_call_path(path, scope, position):
def follow_paths(path, results, position=None):
"""
In each result, `path` must be followed. Copies the path iterator.
"""
results_new = []
if results:
if len(results) > 1:
@@ -1302,7 +1351,11 @@ def follow_paths(path, results, position=None):
def follow_path(path, scope, position=None):
"""
Takes a generator and tries to complete the path.
Uses a generator and tries to complete the path, e.g.
>>> foo.bar.baz
`follow_path` is only responsible for completing `.bar.baz`, the rest is
done in the `follow_call` function.
"""
# Current is either an Array or a Scope.
try: