1
0
forked from VimPlug/jedi

Move py__getitem__ to the context module.

This commit is contained in:
Dave Halter
2017-09-28 14:10:32 +02:00
parent 30df79e234
commit 65ef6a3166
4 changed files with 90 additions and 87 deletions

View File

@@ -80,7 +80,7 @@ from jedi.evaluate import helpers
from jedi.evaluate.filters import TreeNameDefinition, ParamName
from jedi.evaluate.instance import AnonymousInstance, BoundMethod
from jedi.evaluate.context import ContextualizedName, ContextualizedNode, \
ContextSet, NO_CONTEXTS
ContextSet, NO_CONTEXTS, iterate_contexts
from jedi.evaluate.syntax_tree import eval_trailer, eval_expr_stmt, \
eval_node, check_tuple_assignments
from jedi import parser_utils
@@ -217,7 +217,7 @@ class Evaluator(object):
if type_ == 'for_stmt':
container_types = context.eval_node(def_.children[3])
cn = ContextualizedNode(context, def_.children[3])
for_types = iterable.iterate_contexts(self, container_types, cn)
for_types = iterate_contexts(container_types, cn)
c_node = ContextualizedName(context, name)
return check_tuple_assignments(self, c_node, for_types)
if type_ in ('import_from', 'import_name'):

View File

@@ -1,7 +1,7 @@
from parso.python.tree import ExprStmt, CompFor
from jedi import debug
from jedi._compatibility import Python3Method, zip_longest
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
@@ -66,6 +66,14 @@ class Context(object):
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:
@@ -76,19 +84,51 @@ class Context(object):
analysis.add(
contextualized_node.context,
'type-error-not-iterable',
contextualized_node._node,
contextualized_node.node,
message="TypeError: '%s' object is not iterable" % self)
return iter([])
else:
return iter_method()
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 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)
@@ -142,6 +182,17 @@ class Context(object):
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)
@@ -215,20 +266,20 @@ class MergedLazyContexts(AbstractLazyContext):
class ContextualizedNode(object):
def __init__(self, context, node):
self.context = context
self._node = node
self.node = node
def get_root_context(self):
return self.context.get_root_context()
def infer(self):
return self.context.eval_node(self._node)
return self.context.eval_node(self.node)
class ContextualizedName(ContextualizedNode):
# TODO merge with TreeNameDefinition?!
@property
def name(self):
return self._node
return self.node
def assignment_indexes(self):
"""
@@ -242,8 +293,8 @@ class ContextualizedName(ContextualizedNode):
would result in ``[(1, xyz_node), (0, yz_node)]``.
"""
indexes = []
node = self._node.parent
compare = self._node
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):

View File

@@ -613,74 +613,6 @@ def unpack_tuple_to_dict(context, types, exprlist):
raise NotImplementedError
def iterate_contexts(evaluator, 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)
)
def py__getitem__(evaluator, context, types, trailer):
from jedi.evaluate.representation import ClassContext
from jedi.evaluate.instance import TreeInstance
result = ContextSet()
trailer_op, node, trailer_cl = trailer.children
assert trailer_op == "["
assert trailer_cl == "]"
# TODO It's kind of stupid to cast this from a context set to a set.
types = set(types)
# special case: PEP0484 typing module, see
# https://github.com/davidhalter/jedi/issues/663
for typ in list(types):
if isinstance(typ, (ClassContext, TreeInstance)):
typing_module_types = pep0484.py__getitem__(context, typ, node)
if typing_module_types is not None:
types.remove(typ)
result |= typing_module_types
if not types:
# all consumed by special cases
return result
for index in create_index_types(evaluator, context, node):
if isinstance(index, (compiled.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.
for typ in list(types):
if isinstance(typ, AbstractSequence) and typ.array_type == 'dict':
types.remove(typ)
result |= typ.dict_values()
cs = ContextSet.from_set(types)
return result | iterate_contexts(evaluator, cs)
for typ in types:
# The actual getitem call.
try:
getitem = typ.py__getitem__
except AttributeError:
# TODO this context is probably not right.
analysis.add(context, 'type-error-not-subscriptable', trailer_op,
message="TypeError: '%s' object is not subscriptable" % typ)
else:
try:
result |= getitem(index)
except IndexError:
result |= iterate_contexts(evaluator, ContextSet(typ))
except KeyError:
# Must be a dict. Lists don't raise KeyErrors.
result |= typ.dict_values()
return result
def check_array_additions(context, sequence):
""" Just a mapper function for the internal _check_array_additions """
if sequence.array_type not in ('list', 'set'):

View File

@@ -10,7 +10,7 @@ from jedi._compatibility import unicode
from jedi import debug
from jedi import parser_utils
from jedi.evaluate.context import ContextSet, NO_CONTEXTS, ContextualizedNode, \
ContextualizedName, iterator_to_context_set
ContextualizedName, iterator_to_context_set, iterate_contexts
from jedi.evaluate import compiled
from jedi.evaluate import pep0484
from jedi.evaluate import recursion
@@ -119,7 +119,27 @@ def eval_trailer(context, base_contexts, trailer):
if trailer_op == '[':
from jedi.evaluate import iterable
return iterable.py__getitem__(context.evaluator, context, base_contexts, trailer)
from jedi.evaluate.representation import ClassContext
from jedi.evaluate.instance import TreeInstance
trailer_op, node, _ = trailer.children
# TODO It's kind of stupid to cast this from a context set to a set.
foo = set(base_contexts)
# special case: PEP0484 typing module, see
# https://github.com/davidhalter/jedi/issues/663
result = ContextSet()
for typ in list(foo):
if isinstance(typ, (ClassContext, TreeInstance)):
typing_module_types = pep0484.py__getitem__(context, typ, node)
if typing_module_types is not None:
foo.remove(typ)
result |= typing_module_types
return result | base_contexts.get_item(
iterable.create_index_types(context.evaluator, context, node),
ContextualizedNode(context, trailer)
)
else:
debug.dbg('eval_trailer: %s in %s', trailer, base_contexts)
if trailer_op == '.':
@@ -475,7 +495,7 @@ def tree_name_to_contexts(evaluator, context, tree_name):
types = context.predefined_names[node][tree_name.value]
except KeyError:
cn = ContextualizedNode(context, node.children[3])
for_types = iterable.iterate_contexts(evaluator, cn.infer(), cn)
for_types = iterate_contexts(cn.infer(), cn)
c_node = ContextualizedName(context, tree_name)
types = check_tuple_assignments(evaluator, c_node, for_types)
elif typ == 'expr_stmt':