mirror of
https://github.com/davidhalter/jedi.git
synced 2026-03-06 04:44:18 +08:00
Move py__getitem__ to the context module.
This commit is contained in:
@@ -80,7 +80,7 @@ from jedi.evaluate import helpers
|
|||||||
from jedi.evaluate.filters import TreeNameDefinition, ParamName
|
from jedi.evaluate.filters import TreeNameDefinition, ParamName
|
||||||
from jedi.evaluate.instance import AnonymousInstance, BoundMethod
|
from jedi.evaluate.instance import AnonymousInstance, BoundMethod
|
||||||
from jedi.evaluate.context import ContextualizedName, ContextualizedNode, \
|
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, \
|
from jedi.evaluate.syntax_tree import eval_trailer, eval_expr_stmt, \
|
||||||
eval_node, check_tuple_assignments
|
eval_node, check_tuple_assignments
|
||||||
from jedi import parser_utils
|
from jedi import parser_utils
|
||||||
@@ -217,7 +217,7 @@ class Evaluator(object):
|
|||||||
if type_ == 'for_stmt':
|
if type_ == 'for_stmt':
|
||||||
container_types = context.eval_node(def_.children[3])
|
container_types = context.eval_node(def_.children[3])
|
||||||
cn = ContextualizedNode(context, 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)
|
c_node = ContextualizedName(context, name)
|
||||||
return check_tuple_assignments(self, c_node, for_types)
|
return check_tuple_assignments(self, c_node, for_types)
|
||||||
if type_ in ('import_from', 'import_name'):
|
if type_ in ('import_from', 'import_name'):
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from parso.python.tree import ExprStmt, CompFor
|
from parso.python.tree import ExprStmt, CompFor
|
||||||
|
|
||||||
from jedi import debug
|
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.parser_utils import clean_scope_docstring, get_doc_with_call_signature
|
||||||
from jedi.common import BaseContextSet
|
from jedi.common import BaseContextSet
|
||||||
|
|
||||||
@@ -66,6 +66,14 @@ class Context(object):
|
|||||||
|
|
||||||
return self.evaluator.execute(self, arguments)
|
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):
|
def iterate(self, contextualized_node=None):
|
||||||
debug.dbg('iterate')
|
debug.dbg('iterate')
|
||||||
try:
|
try:
|
||||||
@@ -76,19 +84,51 @@ class Context(object):
|
|||||||
analysis.add(
|
analysis.add(
|
||||||
contextualized_node.context,
|
contextualized_node.context,
|
||||||
'type-error-not-iterable',
|
'type-error-not-iterable',
|
||||||
contextualized_node._node,
|
contextualized_node.node,
|
||||||
message="TypeError: '%s' object is not iterable" % self)
|
message="TypeError: '%s' object is not iterable" % self)
|
||||||
return iter([])
|
return iter([])
|
||||||
else:
|
else:
|
||||||
return iter_method()
|
return iter_method()
|
||||||
|
|
||||||
def execute_evaluated(self, *value_list):
|
def get_item(self, index_contexts, contextualized_node):
|
||||||
"""
|
from jedi.evaluate.compiled import CompiledObject
|
||||||
Execute a function with already executed arguments.
|
from jedi.evaluate.iterable import Slice, AbstractSequence
|
||||||
"""
|
result = ContextSet()
|
||||||
from jedi.evaluate.param import ValuesArguments
|
|
||||||
arguments = ValuesArguments([ContextSet(value) for value in value_list])
|
for index in index_contexts:
|
||||||
return self.execute(arguments)
|
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):
|
def eval_node(self, node):
|
||||||
return self.evaluator.eval_element(self, node)
|
return self.evaluator.eval_element(self, node)
|
||||||
@@ -142,6 +182,17 @@ class Context(object):
|
|||||||
return None
|
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):
|
class TreeContext(Context):
|
||||||
def __init__(self, evaluator, parent_context=None):
|
def __init__(self, evaluator, parent_context=None):
|
||||||
super(TreeContext, self).__init__(evaluator, parent_context)
|
super(TreeContext, self).__init__(evaluator, parent_context)
|
||||||
@@ -215,20 +266,20 @@ class MergedLazyContexts(AbstractLazyContext):
|
|||||||
class ContextualizedNode(object):
|
class ContextualizedNode(object):
|
||||||
def __init__(self, context, node):
|
def __init__(self, context, node):
|
||||||
self.context = context
|
self.context = context
|
||||||
self._node = node
|
self.node = node
|
||||||
|
|
||||||
def get_root_context(self):
|
def get_root_context(self):
|
||||||
return self.context.get_root_context()
|
return self.context.get_root_context()
|
||||||
|
|
||||||
def infer(self):
|
def infer(self):
|
||||||
return self.context.eval_node(self._node)
|
return self.context.eval_node(self.node)
|
||||||
|
|
||||||
|
|
||||||
class ContextualizedName(ContextualizedNode):
|
class ContextualizedName(ContextualizedNode):
|
||||||
# TODO merge with TreeNameDefinition?!
|
# TODO merge with TreeNameDefinition?!
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return self._node
|
return self.node
|
||||||
|
|
||||||
def assignment_indexes(self):
|
def assignment_indexes(self):
|
||||||
"""
|
"""
|
||||||
@@ -242,8 +293,8 @@ class ContextualizedName(ContextualizedNode):
|
|||||||
would result in ``[(1, xyz_node), (0, yz_node)]``.
|
would result in ``[(1, xyz_node), (0, yz_node)]``.
|
||||||
"""
|
"""
|
||||||
indexes = []
|
indexes = []
|
||||||
node = self._node.parent
|
node = self.node.parent
|
||||||
compare = self._node
|
compare = self.node
|
||||||
while node is not None:
|
while node is not None:
|
||||||
if node.type in ('testlist', 'testlist_comp', 'testlist_star_expr', 'exprlist'):
|
if node.type in ('testlist', 'testlist_comp', 'testlist_star_expr', 'exprlist'):
|
||||||
for i, child in enumerate(node.children):
|
for i, child in enumerate(node.children):
|
||||||
|
|||||||
@@ -613,74 +613,6 @@ def unpack_tuple_to_dict(context, types, exprlist):
|
|||||||
raise NotImplementedError
|
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):
|
def check_array_additions(context, sequence):
|
||||||
""" Just a mapper function for the internal _check_array_additions """
|
""" Just a mapper function for the internal _check_array_additions """
|
||||||
if sequence.array_type not in ('list', 'set'):
|
if sequence.array_type not in ('list', 'set'):
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from jedi._compatibility import unicode
|
|||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi import parser_utils
|
from jedi import parser_utils
|
||||||
from jedi.evaluate.context import ContextSet, NO_CONTEXTS, ContextualizedNode, \
|
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 compiled
|
||||||
from jedi.evaluate import pep0484
|
from jedi.evaluate import pep0484
|
||||||
from jedi.evaluate import recursion
|
from jedi.evaluate import recursion
|
||||||
@@ -119,7 +119,27 @@ def eval_trailer(context, base_contexts, trailer):
|
|||||||
|
|
||||||
if trailer_op == '[':
|
if trailer_op == '[':
|
||||||
from jedi.evaluate import iterable
|
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:
|
else:
|
||||||
debug.dbg('eval_trailer: %s in %s', trailer, base_contexts)
|
debug.dbg('eval_trailer: %s in %s', trailer, base_contexts)
|
||||||
if trailer_op == '.':
|
if trailer_op == '.':
|
||||||
@@ -475,7 +495,7 @@ def tree_name_to_contexts(evaluator, context, tree_name):
|
|||||||
types = context.predefined_names[node][tree_name.value]
|
types = context.predefined_names[node][tree_name.value]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
cn = ContextualizedNode(context, node.children[3])
|
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)
|
c_node = ContextualizedName(context, tree_name)
|
||||||
types = check_tuple_assignments(evaluator, c_node, for_types)
|
types = check_tuple_assignments(evaluator, c_node, for_types)
|
||||||
elif typ == 'expr_stmt':
|
elif typ == 'expr_stmt':
|
||||||
|
|||||||
Reference in New Issue
Block a user