1
0
forked from VimPlug/jedi

Move the base Context stuff to another module to keep context free for imports.

This commit is contained in:
Dave Halter
2017-09-30 16:46:07 +02:00
parent 3c2221ec2d
commit 3c75f27376
27 changed files with 62 additions and 60 deletions
+1 -3
View File
@@ -1,5 +1,3 @@
from jedi.evaluate.context.base import Context, iterate_contexts, \
TreeContext, ContextualizedName, ContextualizedNode, ContextSet, \
NO_CONTEXTS, iterator_to_context_set
from jedi.evaluate.context.lazy import AbstractLazyContext, LazyKnownContext, \
LazyKnownContexts, LazyTreeContext, LazyUnknownContext, get_merged_lazy_context
from jedi.evaluate.context.module import ModuleContext
-260
View File
@@ -1,260 +0,0 @@
from parso.python.tree import ExprStmt, CompFor
from jedi import debug
from jedi._compatibility import Python3Method, zip_longest, unicode
from jedi.parser_utils import clean_scope_docstring, get_doc_with_call_signature
from jedi.common import BaseContextSet, BaseContext
class Context(BaseContext):
"""
Should be defined, otherwise the API returns empty types.
"""
predefined_names = {}
tree_node = None
"""
To be defined by subclasses.
"""
@property
def api_type(self):
# By default just lower name of the class. Can and should be
# overwritten.
return self.__class__.__name__.lower()
@debug.increase_indent
def execute(self, arguments):
"""
In contrast to py__call__ this function is always available.
`hasattr(x, py__call__)` can also be checked to see if a context is
executable.
"""
if self.evaluator.is_analysis:
arguments.eval_all()
debug.dbg('execute: %s %s', self, arguments)
from jedi.evaluate import stdlib
try:
# Some stdlib functions like super(), namedtuple(), etc. have been
# hard-coded in Jedi to support them.
return stdlib.execute(self.evaluator, self, arguments)
except stdlib.NotInStdLib:
pass
try:
func = self.py__call__
except AttributeError:
debug.warning("no execution possible %s", self)
return NO_CONTEXTS
else:
context_set = func(arguments)
debug.dbg('execute result: %s in %s', context_set, self)
return context_set
return self.evaluator.execute(self, arguments)
def execute_evaluated(self, *value_list):
"""
Execute a function with already executed arguments.
"""
from jedi.evaluate.param import ValuesArguments
arguments = ValuesArguments([ContextSet(value) for value in value_list])
return self.execute(arguments)
def iterate(self, contextualized_node=None):
debug.dbg('iterate')
try:
iter_method = self.py__iter__
except AttributeError:
if contextualized_node is not None:
from jedi.evaluate import analysis
analysis.add(
contextualized_node.context,
'type-error-not-iterable',
contextualized_node.node,
message="TypeError: '%s' object is not iterable" % self)
return iter([])
else:
return iter_method()
def get_item(self, index_contexts, contextualized_node):
from jedi.evaluate.compiled import CompiledObject
from jedi.evaluate.iterable import Slice, AbstractSequence
result = ContextSet()
for index in index_contexts:
if isinstance(index, (CompiledObject, Slice)):
index = index.obj
if type(index) not in (float, int, str, unicode, slice, type(Ellipsis)):
# If the index is not clearly defined, we have to get all the
# possiblities.
if isinstance(self, AbstractSequence) and self.array_type == 'dict':
result |= self.dict_values()
else:
result |= iterate_contexts(ContextSet(self))
continue
# The actual getitem call.
try:
getitem = self.py__getitem__
except AttributeError:
from jedi.evaluate import analysis
# TODO this context is probably not right.
analysis.add(
contextualized_node.context,
'type-error-not-subscriptable',
contextualized_node.node,
message="TypeError: '%s' object is not subscriptable" % self
)
else:
try:
result |= getitem(index)
except IndexError:
result |= iterate_contexts(ContextSet(self))
except KeyError:
# Must be a dict. Lists don't raise KeyErrors.
result |= self.dict_values()
return result
def eval_node(self, node):
return self.evaluator.eval_element(self, node)
@Python3Method
def py__getattribute__(self, name_or_str, name_context=None, position=None,
search_global=False, is_goto=False,
analysis_errors=True):
"""
:param position: Position of the last statement -> tuple of line, column
"""
if name_context is None:
name_context = self
from jedi.evaluate import finder
f = finder.NameFinder(self.evaluator, self, name_context, name_or_str,
position, analysis_errors=analysis_errors)
filters = f.get_filters(search_global)
if is_goto:
return f.filter_name(filters)
return f.find(filters, attribute_lookup=not search_global)
return self.evaluator.find_types(
self, name_or_str, name_context, position, search_global, is_goto,
analysis_errors)
def create_context(self, node, node_is_context=False, node_is_object=False):
return self.evaluator.create_context(self, node, node_is_context, node_is_object)
def is_class(self):
return False
def py__bool__(self):
"""
Since Wrapper is a super class for classes, functions and modules,
the return value will always be true.
"""
return True
def py__doc__(self, include_call_signature=False):
try:
self.tree_node.get_doc_node
except AttributeError:
return ''
else:
if include_call_signature:
return get_doc_with_call_signature(self.tree_node)
else:
return clean_scope_docstring(self.tree_node)
return None
def iterate_contexts(contexts, contextualized_node=None):
"""
Calls `iterate`, on all contexts but ignores the ordering and just returns
all contexts that the iterate functions yield.
"""
return ContextSet.from_sets(
lazy_context.infer()
for lazy_context in contexts.iterate(contextualized_node)
)
class TreeContext(Context):
def __init__(self, evaluator, parent_context=None):
super(TreeContext, self).__init__(evaluator, parent_context)
self.predefined_names = {}
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self.tree_node)
class ContextualizedNode(object):
def __init__(self, context, node):
self.context = context
self.node = node
def get_root_context(self):
return self.context.get_root_context()
def infer(self):
return self.context.eval_node(self.node)
class ContextualizedName(ContextualizedNode):
# TODO merge with TreeNameDefinition?!
@property
def name(self):
return self.node
def assignment_indexes(self):
"""
Returns an array of tuple(int, node) of the indexes that are used in
tuple assignments.
For example if the name is ``y`` in the following code::
x, (y, z) = 2, ''
would result in ``[(1, xyz_node), (0, yz_node)]``.
"""
indexes = []
node = self.node.parent
compare = self.node
while node is not None:
if node.type in ('testlist', 'testlist_comp', 'testlist_star_expr', 'exprlist'):
for i, child in enumerate(node.children):
if child == compare:
indexes.insert(0, (int(i / 2), node))
break
else:
raise LookupError("Couldn't find the assignment.")
elif isinstance(node, (ExprStmt, CompFor)):
break
compare = node
node = node.parent
return indexes
class ContextSet(BaseContextSet):
def py__class__(self):
return ContextSet.from_iterable(c.py__class__() for c in self._set)
def iterate(self, contextualized_node=None):
from jedi.evaluate.context.lazy import get_merged_lazy_context
type_iters = [c.iterate(contextualized_node) for c in self._set]
for lazy_contexts in zip_longest(*type_iters):
yield get_merged_lazy_context(
[l for l in lazy_contexts if l is not None]
)
NO_CONTEXTS = ContextSet()
def iterator_to_context_set(func):
def wrapper(*args, **kwargs):
return ContextSet.from_iterable(func(*args, **kwargs))
return wrapper
+8 -9
View File
@@ -13,8 +13,9 @@ from jedi.evaluate import helpers
from jedi.evaluate import iterable
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \
ContextName, AbstractNameDefinition, ParamName
from jedi.evaluate import context
from jedi.evaluate.context import ContextualizedNode, NO_CONTEXTS, ContextSet
from jedi.evaluate.base_context import ContextualizedNode, NO_CONTEXTS, \
ContextSet, TreeContext
from jedi.evaluate.context import LazyKnownContexts, LazyKnownContext, LazyTreeContext
from jedi import parser_utils
from jedi.evaluate.parser_cache import get_yield_exprs
@@ -33,7 +34,7 @@ class LambdaName(AbstractNameDefinition):
return ContextSet(self._lambda_context)
class FunctionContext(use_metaclass(CachedMetaClass, context.TreeContext)):
class FunctionContext(use_metaclass(CachedMetaClass, TreeContext)):
"""
Needed because of decorators. Decorators are evaluated here.
"""
@@ -98,7 +99,7 @@ class FunctionContext(use_metaclass(CachedMetaClass, context.TreeContext)):
for param in self.tree_node.get_params()]
class FunctionExecutionContext(context.TreeContext):
class FunctionExecutionContext(TreeContext):
"""
This class is used to evaluate functions and their returns.
@@ -155,7 +156,7 @@ class FunctionExecutionContext(context.TreeContext):
def _eval_yield(self, yield_expr):
if yield_expr.type == 'keyword':
# `yield` just yields None.
yield context.LazyKnownContext(compiled.create(self.evaluator, None))
yield LazyKnownContext(compiled.create(self.evaluator, None))
return
node = yield_expr.children[1]
@@ -164,7 +165,7 @@ class FunctionExecutionContext(context.TreeContext):
for lazy_context in cn.infer().iterate(cn):
yield lazy_context
else:
yield context.LazyTreeContext(self, node)
yield LazyTreeContext(self, node)
@recursion.execution_recursion_decorator(default=iter([]))
def get_yield_values(self):
@@ -192,7 +193,7 @@ class FunctionExecutionContext(context.TreeContext):
else:
types = self.get_return_values(check_yields=True)
if types:
yield context.LazyKnownContexts(types)
yield LazyKnownContexts(types)
return
last_for_stmt = for_stmt
@@ -222,5 +223,3 @@ class FunctionExecutionContext(context.TreeContext):
@evaluator_method_cache()
def get_params(self):
return self.var_args.get_params(self)
+3 -2
View File
@@ -4,8 +4,9 @@ from jedi._compatibility import is_py3
from jedi import debug
from jedi.evaluate import compiled
from jedi.evaluate import filters
from jedi.evaluate.context import Context, LazyKnownContext, LazyKnownContexts, \
ContextSet, iterator_to_context_set, NO_CONTEXTS
from jedi.evaluate.base_context import Context, NO_CONTEXTS, ContextSet, \
iterator_to_context_set
from jedi.evaluate.context import LazyKnownContext, LazyKnownContexts
from jedi.evaluate.cache import evaluator_method_cache
from jedi.evaluate.param import AbstractArguments, AnonymousArguments
from jedi.cache import memoize_method
+5 -4
View File
@@ -43,8 +43,9 @@ from jedi.evaluate import compiled
from jedi.evaluate import param
from jedi.evaluate.filters import ParserTreeFilter, TreeNameDefinition, \
ContextName, AnonymousInstanceParamName
from jedi.evaluate import context
from jedi.evaluate.context import ContextSet, iterator_to_context_set
from jedi.evaluate.base_context import ContextSet, iterator_to_context_set, \
TreeContext
from jedi.evaluate.context import LazyKnownContext
def apply_py__get__(context, base_context):
@@ -84,7 +85,7 @@ class ClassFilter(ParserTreeFilter):
for name in names]
class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext)):
class ClassContext(use_metaclass(CachedMetaClass, TreeContext)):
"""
This class is not only important to extend `tree.Class`, it is also a
important for descriptors (if the descriptor methods are evaluated or not).
@@ -138,7 +139,7 @@ class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext)):
args = param.TreeArguments(self.evaluator, self, arglist)
return [value for key, value in args.unpack() if key is None]
else:
return [context.LazyKnownContext(compiled.create(self.evaluator, object))]
return [LazyKnownContext(compiled.create(self.evaluator, object))]
def py__call__(self, params):
from jedi.evaluate.context.instance import TreeInstance
+1 -1
View File
@@ -1,4 +1,4 @@
from jedi.evaluate.context import ContextSet, NO_CONTEXTS
from jedi.evaluate.base_context import ContextSet, NO_CONTEXTS
class AbstractLazyContext(object):
def __init__(self, data):
+1 -1
View File
@@ -10,7 +10,7 @@ from jedi.evaluate.cache import CachedMetaClass, evaluator_method_cache
from jedi.evaluate.filters import GlobalNameFilter, ContextNameMixin, \
AbstractNameDefinition, ParserTreeFilter, DictFilter
from jedi.evaluate import compiled
from jedi.evaluate.context import TreeContext
from jedi.evaluate.base_context import TreeContext
from jedi.evaluate.imports import SubModuleName, infer_import
class _ModuleAttributeName(AbstractNameDefinition):
+2 -3
View File
@@ -5,8 +5,7 @@ from jedi._compatibility import use_metaclass
from jedi.evaluate.cache import evaluator_method_cache, CachedMetaClass
from jedi.evaluate import imports
from jedi.evaluate.filters import DictFilter, AbstractNameDefinition
from jedi.evaluate import context
from jedi.evaluate.context import NO_CONTEXTS
from jedi.evaluate.base_context import NO_CONTEXTS, TreeContext
class ImplicitNSName(AbstractNameDefinition):
@@ -25,7 +24,7 @@ class ImplicitNSName(AbstractNameDefinition):
return self.implicit_ns_context
class ImplicitNamespaceContext(use_metaclass(CachedMetaClass, context.TreeContext)):
class ImplicitNamespaceContext(use_metaclass(CachedMetaClass, TreeContext)):
"""
Provides support for implicit namespace packages
"""