diff --git a/jedi/inference/compiled/access.py b/jedi/inference/compiled/access.py index 4177b3c8..3ceab8f1 100644 --- a/jedi/inference/compiled/access.py +++ b/jedi/inference/compiled/access.py @@ -211,7 +211,22 @@ class DirectObjectAccess: 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() + if isinstance(self._obj, (list, tuple)): + return [self._create_access_path(v) for v in self._obj] + + if self.is_instance(): + cls = DirectObjectAccess(self._inference_state, self._obj.__class__) + return cls.py__getitem__all_values() + + try: + getitem = self._obj.__getitem__ + except AttributeError: + pass + else: + annotation = DirectObjectAccess(self._inference_state, getitem).get_return_annotation() + if annotation is not None: + return [annotation] + return None def py__simple_getitem__(self, index): if type(self._obj) not in ALLOWED_GETITEM_TYPES: @@ -221,8 +236,14 @@ class DirectObjectAccess: return self._create_access_path(self._obj[index]) def py__iter__list(self): - if not hasattr(self._obj, '__getitem__'): + try: + iter_method = self._obj.__iter__ + except AttributeError: return None + else: + p = DirectObjectAccess(self._inference_state, iter_method).get_return_annotation() + if p is not None: + return [p] if type(self._obj) not in ALLOWED_GETITEM_TYPES: # Get rid of side effects, we won't call custom `__getitem__`s. diff --git a/jedi/inference/compiled/value.py b/jedi/inference/compiled/value.py index c4a9eb3f..7b61e717 100644 --- a/jedi/inference/compiled/value.py +++ b/jedi/inference/compiled/value.py @@ -166,7 +166,7 @@ class CompiledValue(Value): except AttributeError: return super().py__simple_getitem__(index) if access is None: - return NO_VALUES + return super().py__simple_getitem__(index) return ValueSet([create_from_access_path(self.inference_state, access)]) diff --git a/test/test_api/test_interpreter.py b/test/test_api/test_interpreter.py index b7be471f..4154c072 100644 --- a/test/test_api/test_interpreter.py +++ b/test/test_api/test_interpreter.py @@ -603,8 +603,11 @@ def test_dict_getitem(code, types): @pytest.mark.parametrize( 'code, expected', [ ('DunderCls()[0]', 'int'), + ('dunder[0]', 'int'), ('next(DunderCls())', 'float'), + ('next(dunder)', 'float'), ('for x in DunderCls(): x', 'str'), + #('for x in dunder: x', 'str'), ] ) def test_dunders(class_is_findable, code, expected): @@ -623,6 +626,8 @@ def test_dunders(class_is_findable, code, expected): if not class_is_findable: DunderCls.__name__ = 'asdf' + dunder = DunderCls() + n, = jedi.Interpreter(code, [locals()]).infer() assert n.name == expected