mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-08 06:44:46 +08:00
Make it possible to use __getitem__ in interpreter
This commit is contained in:
@@ -121,7 +121,13 @@ class AbstractInstanceValue(Value):
|
|||||||
return [s.bind(self) for s in call_funcs.get_signatures()]
|
return [s.bind(self) for s in call_funcs.get_signatures()]
|
||||||
|
|
||||||
def get_function_slot_names(self, name):
|
def get_function_slot_names(self, name):
|
||||||
# Searches for Python functions in classes.
|
# Python classes don't look at the dictionary of the instance when
|
||||||
|
# looking up `__call__`. This is something that has to do with Python's
|
||||||
|
# internal slot system (note: not __slots__, but C slots).
|
||||||
|
for filter in self.get_filters(include_self_names=False):
|
||||||
|
names = filter.get(name)
|
||||||
|
if names:
|
||||||
|
return names
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def execute_function_slots(self, names, *inferred_args):
|
def execute_function_slots(self, names, *inferred_args):
|
||||||
@@ -133,6 +139,17 @@ class AbstractInstanceValue(Value):
|
|||||||
def get_type_hint(self, add_class_info=True):
|
def get_type_hint(self, add_class_info=True):
|
||||||
return self.py__name__()
|
return self.py__name__()
|
||||||
|
|
||||||
|
def py__getitem__(self, index_value_set, contextualized_node):
|
||||||
|
names = self.get_function_slot_names('__getitem__')
|
||||||
|
if not names:
|
||||||
|
return super().py__getitem__(
|
||||||
|
index_value_set,
|
||||||
|
contextualized_node,
|
||||||
|
)
|
||||||
|
|
||||||
|
args = ValuesArguments([index_value_set])
|
||||||
|
return ValueSet.from_sets(name.infer().execute(args) for name in names)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s of %s>" % (self.__class__.__name__, self.class_value)
|
return "<%s of %s>" % (self.__class__.__name__, self.class_value)
|
||||||
|
|
||||||
@@ -237,17 +254,6 @@ class _BaseTreeInstance(AbstractInstanceValue):
|
|||||||
or self.get_function_slot_names('__getattribute__'))
|
or self.get_function_slot_names('__getattribute__'))
|
||||||
return self.execute_function_slots(names, name)
|
return self.execute_function_slots(names, name)
|
||||||
|
|
||||||
def py__getitem__(self, index_value_set, contextualized_node):
|
|
||||||
names = self.get_function_slot_names('__getitem__')
|
|
||||||
if not names:
|
|
||||||
return super().py__getitem__(
|
|
||||||
index_value_set,
|
|
||||||
contextualized_node,
|
|
||||||
)
|
|
||||||
|
|
||||||
args = ValuesArguments([index_value_set])
|
|
||||||
return ValueSet.from_sets(name.infer().execute(args) for name in names)
|
|
||||||
|
|
||||||
def py__iter__(self, contextualized_node=None):
|
def py__iter__(self, contextualized_node=None):
|
||||||
iter_slot_names = self.get_function_slot_names('__iter__')
|
iter_slot_names = self.get_function_slot_names('__iter__')
|
||||||
if not iter_slot_names:
|
if not iter_slot_names:
|
||||||
@@ -295,16 +301,6 @@ class _BaseTreeInstance(AbstractInstanceValue):
|
|||||||
else:
|
else:
|
||||||
return ValueSet([self])
|
return ValueSet([self])
|
||||||
|
|
||||||
def get_function_slot_names(self, name):
|
|
||||||
# Python classes don't look at the dictionary of the instance when
|
|
||||||
# looking up `__call__`. This is something that has to do with Python's
|
|
||||||
# internal slot system (note: not __slots__, but C slots).
|
|
||||||
for filter in self.get_filters(include_self_names=False):
|
|
||||||
names = filter.get(name)
|
|
||||||
if names:
|
|
||||||
return names
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
class TreeInstance(_BaseTreeInstance):
|
class TreeInstance(_BaseTreeInstance):
|
||||||
def __init__(self, inference_state, parent_context, class_value, arguments):
|
def __init__(self, inference_state, parent_context, class_value, arguments):
|
||||||
|
|||||||
@@ -599,6 +599,19 @@ def test_dict_getitem(code, types):
|
|||||||
assert [c.name for c in comps] == types
|
assert [c.name for c in comps] == types
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('class_is_findable', [False, True])
|
||||||
|
def test__getitem__(class_is_findable):
|
||||||
|
class GetitemCls:
|
||||||
|
def __getitem__(self, key) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not class_is_findable:
|
||||||
|
GetitemCls.__name__ = 'asdf'
|
||||||
|
|
||||||
|
n, = jedi.Interpreter('GetitemCls()[0]', [locals()]).infer()
|
||||||
|
assert n.name == 'int'
|
||||||
|
|
||||||
|
|
||||||
def foo():
|
def foo():
|
||||||
raise KeyError
|
raise KeyError
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user