Skip to content

Commit

Permalink
Autocomplete inherited methods when overriding in child class. Fixes #…
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhalter committed Jul 31, 2016
1 parent 62e1841 commit 647a4db
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 3 deletions.
19 changes: 19 additions & 0 deletions jedi/api/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ def _get_context_completions(self):
elif nodes and nodes[-1] in ('as', 'def', 'class'):
# No completions for ``with x as foo`` and ``import x as foo``.
# Also true for defining names as a class or function.
leaf = self._module.get_leaf_for_position(self._position)
cls = leaf.get_parent_until(tree.Class)
if isinstance(cls, (tree.Class, tree.Function)):
# Complete the methods that are defined in the super classes.
cls = self._evaluator.wrap(cls)
return list(self._get_class_context_completions(cls))
return []
elif symbol_names[-1] == 'trailer' and nodes[-1] == '.':
dot = self._module.get_leaf_for_position(self._position)
Expand Down Expand Up @@ -229,3 +235,16 @@ def _get_importer_names(self, names, level=0, only_modules=True):
names = [str(n) for n in names]
i = imports.Importer(self._evaluator, names, self._module, level)
return i.completion_names(self._evaluator, only_modules=only_modules)

def _get_class_context_completions(self, cls):
"""
Autocomplete inherited methods when overriding in child class.
"""
names_dicts = cls.names_dicts(search_global=False, is_instance=True)
# The first dict is the dictionary of class itself.
next(names_dicts)
for names_dict in names_dicts:
for values in names_dict.values():
for value in values:
if value.parent.type == 'funcdef':
yield value
7 changes: 4 additions & 3 deletions jedi/evaluate/compiled/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ def type(self):
return 'classdef'
elif inspect.ismodule(cls):
return 'file_input'
elif inspect.isbuiltin(cls) or inspect.ismethod(cls) \
or inspect.ismethoddescriptor(cls):
elif inspect.isbuiltin(cls) or inspect.ismethod(cls) or \
inspect.ismethoddescriptor(cls):
return 'funcdef'

@underscore_memoization
Expand All @@ -137,7 +137,8 @@ def _cls(self):
return self

def _get_class(self):
if not fake.is_class_instance(self.obj):
if not fake.is_class_instance(self.obj) or \
inspect.ismethoddescriptor(self.obj): # slots
return self.obj

try:
Expand Down
30 changes: 30 additions & 0 deletions test/blabla_test_documentation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# todo probably remove test_integration_keyword

def test_keyword_doc():
r = list(Script("or", 1, 1).goto_definitions())
assert len(r) == 1
assert len(r[0].doc) > 100

r = list(Script("asfdasfd", 1, 1).goto_definitions())
assert len(r) == 0

k = Script("fro").completions()[0]
imp_start = '\nThe ``import'
assert k.raw_doc.startswith(imp_start)
assert k.doc.startswith(imp_start)


def test_blablabla():
defs = Script("import").goto_definitions()
assert len(defs) == 1 and [1 for d in defs if d.doc]
# unrelated to #44


def test_operator_doc(self):
r = list(Script("a == b", 1, 3).goto_definitions())
assert len(r) == 1
assert len(r[0].doc) > 100

def test_lambda():
defs = Script('lambda x: x', column=0).goto_definitions()
assert [d.type for d in defs] == ['keyword']
22 changes: 22 additions & 0 deletions test/completion/context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class X():
def func(self, foo):
pass


class Y(X):
def actual_function(self):
pass

#? []
def actual_function
#? ['func']

This comment has been minimized.

Copy link
@fangjunzhou

fangjunzhou Dec 18, 2024

Should provide 'func(self, foo)' as one completion option. Ideally, an extra line with super().func(foo) should be added below.

This comment has been minimized.

Copy link
@PeterJCLaw

PeterJCLaw Dec 19, 2024

Collaborator

I think what you're asking for here is beyond the remit of Jedi. The behaviour you're describing is controlled by the language server and/or editor -- Jedi is primarily responsible for providing the information to enable the completions (which I believe it does just fine).

Have a look at microsoft/vscode-python#15858 and pappasam/jedi-language-server#124 to understand what each layer handles.

def f

#? []
def __class__

#? ['__repr__']
def __repr__

#? []
def mro

0 comments on commit 647a4db

Please sign in to comment.