1
0
forked from VimPlug/jedi

Start creating py__getitem__.

This commit is contained in:
Dave Halter
2015-12-04 12:08:29 +01:00
parent 76345c0b58
commit db060c70c9
7 changed files with 76 additions and 45 deletions

View File

@@ -147,7 +147,7 @@ class Evaluator(object):
types = self.eval_element(rhs)
if seek_name:
types = finder.check_tuple_assignments(types, seek_name)
types = finder.check_tuple_assignments(self, types, seek_name)
first_operation = stmt.first_operation()
if first_operation not in ('=', None) and not isinstance(stmt, er.InstanceElement): # TODO don't check for this.
@@ -352,21 +352,18 @@ class Evaluator(object):
trailer_op, node = trailer.children[:2]
if node == ')': # `arglist` is optional.
node = ()
new_types = set()
for typ in types:
debug.dbg('eval_trailer: %s in scope %s', trailer, typ)
if trailer_op == '.':
new_types |= self.find_types(typ, node)
elif trailer_op == '(':
new_types |= self.execute(typ, node, trailer)
elif trailer_op == '[':
try:
get = typ.get_index_types
except AttributeError:
debug.warning("TypeError: '%s' object is not subscriptable"
% typ)
else:
new_types |= get(self, node)
if trailer_op == '[':
for trailer_typ in self.eval_element(node):
new_types |= iterable.py__getitem__(self, types, trailer_typ, trailer_op)
else:
for typ in types:
debug.dbg('eval_trailer: %s in scope %s', trailer, typ)
if trailer_op == '.':
new_types |= self.find_types(typ, node)
elif trailer_op == '(':
new_types |= self.execute(typ, node, trailer)
return new_types
def execute_evaluated(self, obj, *args):

View File

@@ -20,6 +20,7 @@ CODES = {
'type-error-operation': (11, TypeError, None),
'type-error-not-iterable': (12, TypeError, None),
'type-error-isinstance': (13, TypeError, None),
'type-error-not-subscriptable': (13, TypeError, None),
}

View File

@@ -302,7 +302,7 @@ def _name_to_types(evaluator, name, scope):
if typ.isinstance(tree.ForStmt, tree.CompFor):
container_types = evaluator.eval_element(typ.children[3])
for_types = iterable.py__iter__types(evaluator, container_types, typ.children[3])
types = check_tuple_assignments(for_types, name)
types = check_tuple_assignments(evaluator, for_types, name)
elif isinstance(typ, tree.Param):
types = _eval_param(evaluator, typ, scope)
elif typ.isinstance(tree.ExprStmt):
@@ -542,26 +542,20 @@ def global_names_dict_generator(evaluator, scope, position):
yield names_dict, None
def check_tuple_assignments(types, name):
def check_tuple_assignments(evaluator, types, name):
"""
Checks if tuples are assigned.
"""
for index in name.assignment_indexes():
new_types = set()
for r in types:
for index, node in name.assignment_indexes():
iterated = iterable.py__iter__(evaluator, types, node)
all_types = set()
for _ in range(index + 1):
try:
func = r.get_exact_index_types
except AttributeError:
debug.warning("Invalid tuple lookup #%s of result %s in %s",
index, types, name)
else:
if isinstance(r, iterable.Array) and r.type == 'dict':
continue
try:
new_types |= func(index)
except IndexError:
pass
types = new_types
types = next(iterated)
all_types |= types
except StopIteration:
types = all_types
break
return types

View File

@@ -23,13 +23,12 @@ It is important to note that:
from jedi.common import unite, ignored, safe_property
from jedi import debug
from jedi import settings
from jedi._compatibility import use_metaclass, is_py3, unicode
from jedi._compatibility import use_metaclass, unicode
from jedi.parser import tree
from jedi.evaluate import compiled
from jedi.evaluate import helpers
from jedi.evaluate.cache import CachedMetaClass, memoize_default
from jedi.evaluate import analysis
from jedi.evaluate.precedence import literals_to_types
class IterableWrapper(tree.Base):
@@ -269,8 +268,8 @@ class Array(IterableWrapper, ArrayMixin):
result |= check_array_additions(self._evaluator, self)
return result
def get_exact_index_types(self, mixed_index):
""" Here the index is an int/str. Raises IndexError/KeyError """
def py__getitem__(self, index):
"""Here the index is an int/str. Raises IndexError/KeyError."""
if self.type == 'dict':
for key, values in self._items():
# Because we only want the key to be a string.
@@ -278,13 +277,13 @@ class Array(IterableWrapper, ArrayMixin):
for k in keys:
if isinstance(k, compiled.CompiledObject) \
and mixed_index == k.obj:
and index == k.obj:
for value in values:
return self._evaluator.eval_element(value)
raise KeyError('No key found in dictionary %s.' % self)
# Can raise an IndexError
return self._evaluator.eval_element(self._items()[mixed_index])
return self._evaluator.eval_element(self._items()[index])
def iter_content(self):
return self.values()
@@ -466,19 +465,20 @@ def unpack_tuple_to_dict(evaluator, types, exprlist):
raise NotImplementedError
def py__iter__(evaluator, types, node):
def py__iter__(evaluator, types, node=None):
debug.dbg('py__iter__')
for typ in types:
try:
iter_method = typ.py__iter__
except AttributeError:
analysis.add(evaluator, 'type-error-not-iterable', node)
if node is not None:
analysis.add(evaluator, 'type-error-not-iterable', node)
else:
for result in iter_method():
yield result
def py__iter__types(evaluator, types, node):
def py__iter__types(evaluator, types, node=None):
"""
Calls `py__iter__`, but ignores the ordering in the end and just returns
all types that it contains.
@@ -486,6 +486,33 @@ def py__iter__types(evaluator, types, node):
return unite(py__iter__(evaluator, types, node))
def py__getitem__(evaluator, types, index, node):
result = set()
# Index handling.
if isinstance(index, compiled.CompiledObject):
pure_index = index.obj
elif not type(index) in (float, int, str, unicode):
pure_index = index
else:
# If the index is not clearly defined, we have to get all the
# possiblities.
return py__iter__types(evaluator, types)
for typ in types:
# The actual getitem call.
try:
getitem = typ.py__getitem__
except AttributeError:
analysis.add(evaluator, 'type-error-not-subscriptable', node)
else:
try:
result |= getitem(pure_index)
except IndexError:
return py__iter__types(evaluator, set([typ]))
return result
def check_array_additions(evaluator, array):
""" Just a mapper function for the internal _check_array_additions """
if array.type not in ('list', 'set'):

View File

@@ -22,6 +22,9 @@ py__bool__() Returns True/False/None; None means that
there's no certainty.
py__bases__(evaluator) Returns a list of base classes.
py__mro__(evaluator) Returns a list of classes (the mro).
py__iter__() Returns a generator of a set of types.
py__getitem__(index: int/str) Returns a a set of types of the index.
Can raise an IndexError/KeyError.
py__getattribute__(evaluator, name) Returns a list of attribute values. The
name can be str or Name.
====================================== ========================================