forked from VimPlug/jedi
Move to using py__getitem__ and py__simple_getitem__
This change is necessary to handle more complex cases with py__getitem__
This commit is contained in:
@@ -67,7 +67,6 @@ from parso.python import tree
|
||||
import parso
|
||||
from parso import python_bytes_to_unicode
|
||||
|
||||
from jedi._compatibility import unicode
|
||||
from jedi import debug
|
||||
from jedi import parser_utils
|
||||
from jedi.evaluate.utils import unite
|
||||
@@ -84,8 +83,6 @@ from jedi.evaluate.context import ClassContext, FunctionContext, \
|
||||
from jedi.evaluate.context.iterable import CompForContext
|
||||
from jedi.evaluate.syntax_tree import eval_trailer, eval_expr_stmt, \
|
||||
eval_node, check_tuple_assignments
|
||||
from jedi.evaluate.helpers import EvaluatorIndexError, EvaluatorKeyError, \
|
||||
EvaluatorTypeError
|
||||
|
||||
|
||||
def _execute(context, arguments):
|
||||
|
||||
@@ -12,8 +12,7 @@ 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
|
||||
from jedi.evaluate.helpers import EvaluatorIndexError, EvaluatorTypeError, \
|
||||
EvaluatorKeyError, execute_evaluated
|
||||
from jedi.evaluate.helpers import SimpleGetItemNotFound, execute_evaluated
|
||||
|
||||
|
||||
class Context(BaseContext):
|
||||
@@ -172,9 +171,10 @@ def _get_item(context, index_contexts, contextualized_node):
|
||||
from jedi.evaluate.context.iterable import Slice, Sequence
|
||||
|
||||
# The actual getitem call.
|
||||
try:
|
||||
getitem = context.py__simple_getitem__
|
||||
except AttributeError:
|
||||
simple_getitem = getattr(context, 'py__simple_getitem__', None)
|
||||
getitem = getattr(context, 'py__getitem__', None)
|
||||
|
||||
if getitem is None and simple_getitem is None:
|
||||
from jedi.evaluate import analysis
|
||||
# TODO this context is probably not right.
|
||||
analysis.add(
|
||||
@@ -186,35 +186,29 @@ def _get_item(context, index_contexts, contextualized_node):
|
||||
return NO_CONTEXTS
|
||||
|
||||
result = ContextSet()
|
||||
for index in index_contexts:
|
||||
if isinstance(index, Slice):
|
||||
index = index.obj
|
||||
if isinstance(index, CompiledObject):
|
||||
try:
|
||||
index = index.get_safe_value()
|
||||
except ValueError:
|
||||
pass
|
||||
for index_context in index_contexts:
|
||||
if simple_getitem is not None:
|
||||
index = index_context
|
||||
if isinstance(index_context, Slice):
|
||||
index = index.obj
|
||||
if isinstance(index, CompiledObject):
|
||||
try:
|
||||
index = index.get_safe_value()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if type(index) not in (float, int, str, unicode, slice, bytes):
|
||||
# If the index is not clearly defined, we have to get all the
|
||||
# possiblities.
|
||||
if isinstance(context, Sequence) and context.array_type == 'dict':
|
||||
result |= context.dict_values()
|
||||
else:
|
||||
result |= iterate_contexts(ContextSet(context))
|
||||
continue
|
||||
else:
|
||||
try:
|
||||
result |= getitem(index)
|
||||
except EvaluatorIndexError:
|
||||
result |= iterate_contexts(ContextSet(context))
|
||||
except EvaluatorKeyError:
|
||||
# Must be a dict. Lists don't raise KeyErrors.
|
||||
result |= context.dict_values()
|
||||
except EvaluatorTypeError:
|
||||
# The type is wrong and therefore it makes no sense to do
|
||||
# anything anymore.
|
||||
result = NO_CONTEXTS
|
||||
if type(index) in (float, int, str, unicode, slice, bytes):
|
||||
try:
|
||||
result |= simple_getitem(index)
|
||||
continue
|
||||
except SimpleGetItemNotFound:
|
||||
pass
|
||||
|
||||
# The index was somehow not good enough or simply a wrong type.
|
||||
# Therefore we now iterate through all the contexts and just take
|
||||
# all results.
|
||||
if getitem is not None:
|
||||
result |= getitem(index_context, contextualized_node)
|
||||
return result
|
||||
|
||||
|
||||
|
||||
@@ -226,6 +226,11 @@ class DirectObjectAccess(object):
|
||||
def py__mro__accesses(self):
|
||||
return tuple(self._create_access_path(cls) for cls in self._obj.__mro__[1:])
|
||||
|
||||
def py__getitem__all_values(self):
|
||||
if isinstance(self._obj, dict):
|
||||
return [self._create_access_path(v) for v in self._obj.values()]
|
||||
return self.py__iter__list()
|
||||
|
||||
def py__simple_getitem__(self, index):
|
||||
if type(self._obj) not in (str, list, tuple, unicode, bytes, bytearray, dict):
|
||||
# Get rid of side effects, we won't call custom `__getitem__`s.
|
||||
@@ -416,9 +421,6 @@ class DirectObjectAccess(object):
|
||||
def negate(self):
|
||||
return self._create_access_path(-self._obj)
|
||||
|
||||
def dict_values(self):
|
||||
return [self._create_access_path(v) for v in self._obj.values()]
|
||||
|
||||
def is_super_class(self, exception):
|
||||
return issubclass(exception, self._obj)
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ from jedi.evaluate.base_context import Context, ContextSet
|
||||
from jedi.evaluate.lazy_context import LazyKnownContext
|
||||
from jedi.evaluate.compiled.access import _sentinel
|
||||
from jedi.evaluate.cache import evaluator_function_cache
|
||||
from jedi.evaluate.helpers import reraise_as_evaluator, execute_evaluated
|
||||
from jedi.evaluate.helpers import reraise_getitem_errors, execute_evaluated
|
||||
from . import fake
|
||||
|
||||
|
||||
@@ -155,13 +155,20 @@ class CompiledObject(Context):
|
||||
|
||||
@CheckAttribute(u'__getitem__')
|
||||
def py__simple_getitem__(self, index):
|
||||
with reraise_as_evaluator(IndexError, KeyError, TypeError):
|
||||
with reraise_getitem_errors(IndexError, KeyError, TypeError):
|
||||
access = self.access_handle.py__simple_getitem__(index)
|
||||
if access is None:
|
||||
return ContextSet()
|
||||
|
||||
return ContextSet(create_from_access_path(self.evaluator, access))
|
||||
|
||||
@CheckAttribute()
|
||||
def py__getitem__(self, index_context, contextualized_node):
|
||||
return ContextSet.from_iterable(
|
||||
create_from_access_path(self.evaluator, access)
|
||||
for access in self.access_handle.py__getitem__all_values()
|
||||
)
|
||||
|
||||
@CheckAttribute()
|
||||
def py__iter__(self):
|
||||
for access in self.access_handle.py__iter__list():
|
||||
@@ -197,12 +204,6 @@ class CompiledObject(Context):
|
||||
for type_ in docstrings.infer_return_types(self):
|
||||
yield type_
|
||||
|
||||
def dict_values(self):
|
||||
return ContextSet.from_iterable(
|
||||
create_from_access_path(self.evaluator, access)
|
||||
for access in self.access_handle.dict_values()
|
||||
)
|
||||
|
||||
def get_safe_value(self, default=_sentinel):
|
||||
try:
|
||||
return self.access_handle.get_safe_value()
|
||||
|
||||
@@ -30,8 +30,8 @@ from jedi.evaluate import recursion
|
||||
from jedi.evaluate.lazy_context import LazyKnownContext, LazyKnownContexts, \
|
||||
LazyTreeContext
|
||||
from jedi.evaluate.helpers import get_int_or_none, is_string, \
|
||||
predefine_names, evaluate_call_of_leaf, reraise_as_evaluator, \
|
||||
EvaluatorKeyError
|
||||
predefine_names, evaluate_call_of_leaf, reraise_getitem_errors, \
|
||||
SimpleGetItemNotFound
|
||||
from jedi.evaluate.utils import safe_property
|
||||
from jedi.evaluate.utils import to_list
|
||||
from jedi.evaluate.cache import evaluator_method_cache
|
||||
@@ -39,7 +39,7 @@ from jedi.evaluate.helpers import execute_evaluated
|
||||
from jedi.evaluate.filters import ParserTreeFilter, BuiltinOverwrite, \
|
||||
publish_method
|
||||
from jedi.evaluate.base_context import ContextSet, NO_CONTEXTS, Context, \
|
||||
TreeContext, ContextualizedNode
|
||||
TreeContext, ContextualizedNode, iterate_contexts
|
||||
from jedi.parser_utils import get_comp_fors
|
||||
|
||||
|
||||
@@ -202,11 +202,10 @@ class Sequence(BuiltinOverwrite, IterableMixin):
|
||||
def parent(self):
|
||||
return self.evaluator.builtins_module
|
||||
|
||||
def dict_values(self):
|
||||
return ContextSet.from_sets(
|
||||
self._defining_context.eval_node(v)
|
||||
for k, v in self._items()
|
||||
)
|
||||
def py__getitem__(self, index_context, contextualized_node):
|
||||
if self.array_type == 'dict':
|
||||
return self._dict_values()
|
||||
return iterate_contexts(ContextSet(self))
|
||||
|
||||
|
||||
class ListComprehension(ComprehensionMixin, Sequence):
|
||||
@@ -217,7 +216,7 @@ class ListComprehension(ComprehensionMixin, Sequence):
|
||||
return ContextSet(self)
|
||||
|
||||
all_types = list(self.py__iter__())
|
||||
with reraise_as_evaluator(IndexError, TypeError):
|
||||
with reraise_getitem_errors(IndexError, TypeError):
|
||||
lazy_context = all_types[index]
|
||||
return lazy_context.infer()
|
||||
|
||||
@@ -242,14 +241,14 @@ class DictComprehension(ComprehensionMixin, Sequence):
|
||||
if isinstance(k, compiled.CompiledObject):
|
||||
if k.get_safe_value(default=object()) == index:
|
||||
return values
|
||||
return self.dict_values()
|
||||
raise SimpleGetItemNotFound()
|
||||
|
||||
def dict_values(self):
|
||||
def _dict_values(self):
|
||||
return ContextSet.from_sets(values for keys, values in self._iterate())
|
||||
|
||||
@publish_method('values')
|
||||
def _imitate_values(self):
|
||||
lazy_context = LazyKnownContexts(self.dict_values())
|
||||
lazy_context = LazyKnownContexts(self._dict_values())
|
||||
return ContextSet(FakeSequence(self.evaluator, u'list', [lazy_context]))
|
||||
|
||||
@publish_method('items')
|
||||
@@ -298,13 +297,12 @@ class SequenceLiteralContext(Sequence):
|
||||
if isinstance(k, compiled.CompiledObject) \
|
||||
and k.execute_operation(compiled_obj_index, u'==').get_safe_value():
|
||||
return self._defining_context.eval_node(value)
|
||||
raise EvaluatorKeyError('No key found in dictionary %s.' % self)
|
||||
raise SimpleGetItemNotFound('No key found in dictionary %s.' % self)
|
||||
|
||||
# Can raise an IndexError
|
||||
if isinstance(index, slice):
|
||||
return ContextSet(self)
|
||||
else:
|
||||
with reraise_as_evaluator(TypeError, KeyError, IndexError):
|
||||
with reraise_getitem_errors(TypeError, KeyError, IndexError):
|
||||
node = self._items()[index]
|
||||
return self._defining_context.eval_node(node)
|
||||
|
||||
@@ -329,12 +327,11 @@ class SequenceLiteralContext(Sequence):
|
||||
for addition in check_array_additions(self._defining_context, self):
|
||||
yield addition
|
||||
|
||||
def _values(self):
|
||||
"""Returns a list of a list of node."""
|
||||
if self.array_type == u'dict':
|
||||
return ContextSet.from_sets(v for k, v in self._items())
|
||||
else:
|
||||
return self._items()
|
||||
def _dict_values(self):
|
||||
return ContextSet.from_sets(
|
||||
self._defining_context.eval_node(v)
|
||||
for k, v in self._items()
|
||||
)
|
||||
|
||||
def _items(self):
|
||||
c = self.atom.children
|
||||
@@ -387,7 +384,7 @@ class DictLiteralContext(SequenceLiteralContext):
|
||||
|
||||
@publish_method('values')
|
||||
def _imitate_values(self):
|
||||
lazy_context = LazyKnownContexts(self.dict_values())
|
||||
lazy_context = LazyKnownContexts(self._dict_values())
|
||||
return ContextSet(FakeSequence(self.evaluator, u'list', [lazy_context]))
|
||||
|
||||
@publish_method('items')
|
||||
@@ -420,7 +417,7 @@ class FakeSequence(_FakeArray):
|
||||
self._lazy_context_list = lazy_context_list
|
||||
|
||||
def py__simple_getitem__(self, index):
|
||||
with reraise_as_evaluator(IndexError, TypeError):
|
||||
with reraise_getitem_errors(IndexError, TypeError):
|
||||
lazy_context = self._lazy_context_list[index]
|
||||
return lazy_context.infer()
|
||||
|
||||
@@ -459,7 +456,7 @@ class FakeDict(_FakeArray):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
with reraise_as_evaluator(KeyError):
|
||||
with reraise_getitem_errors(KeyError):
|
||||
lazy_context = self._dct[index]
|
||||
return lazy_context.infer()
|
||||
|
||||
@@ -467,10 +464,10 @@ class FakeDict(_FakeArray):
|
||||
def _values(self):
|
||||
return ContextSet(FakeSequence(
|
||||
self.evaluator, u'tuple',
|
||||
[LazyKnownContexts(self.dict_values())]
|
||||
[LazyKnownContexts(self._dict_values())]
|
||||
))
|
||||
|
||||
def dict_values(self):
|
||||
def _dict_values(self):
|
||||
return ContextSet.from_sets(lazy_context.infer() for lazy_context in self._dct.values())
|
||||
|
||||
def exact_key_items(self):
|
||||
|
||||
@@ -218,25 +218,16 @@ def is_number(context):
|
||||
return _get_safe_value_or_none(context, (int, float)) is not None
|
||||
|
||||
|
||||
class EvaluatorTypeError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class EvaluatorIndexError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class EvaluatorKeyError(Exception):
|
||||
class SimpleGetItemNotFound(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@contextmanager
|
||||
def reraise_as_evaluator(*exception_classes):
|
||||
def reraise_getitem_errors(*exception_classes):
|
||||
try:
|
||||
yield
|
||||
except exception_classes as e:
|
||||
new_exc_cls = globals()['Evaluator' + e.__class__.__name__]
|
||||
raise new_exc_cls(e)
|
||||
raise SimpleGetItemNotFound(e)
|
||||
|
||||
|
||||
def execute_evaluated(context, *value_list):
|
||||
|
||||
@@ -30,7 +30,7 @@ b = [6,7]
|
||||
#? int()
|
||||
b[8-7]
|
||||
# Something unreasonable:
|
||||
#?
|
||||
#? int()
|
||||
b['']
|
||||
|
||||
# -----------------
|
||||
|
||||
Reference in New Issue
Block a user