Tests and fixes for keyword completions

This commit is contained in:
Dave Halter
2019-05-29 01:26:38 +02:00
parent 4b3262622b
commit 0e5b17be85
4 changed files with 52 additions and 1 deletions

View File

@@ -4,6 +4,7 @@ These classes are the much bigger part of the whole API, because they contain
the interesting information about completion and goto operations. the interesting information about completion and goto operations.
""" """
import re import re
import warnings
from parso.python.tree import search_ancestor from parso.python.tree import search_ancestor
@@ -314,9 +315,14 @@ class BaseDefinition(object):
return '.'.join(path if path[0] else path[1:]) return '.'.join(path if path[0] else path[1:])
def is_stub(self): def is_stub(self):
if not self._name.is_context_name:
return False
return all(c.is_stub() for c in self._name.infer()) return all(c.is_stub() for c in self._name.infer())
def goto_stubs(self): def goto_stubs(self):
if not self._name.is_context_name:
return []
if self.is_stub(): if self.is_stub():
return [self] return [self]
@@ -326,10 +332,16 @@ class BaseDefinition(object):
] ]
def goto_assignments(self): def goto_assignments(self):
if not self._name.is_context_name:
return []
return [self if n == self._name else Definition(self._evaluator, n) return [self if n == self._name else Definition(self._evaluator, n)
for n in self._name.goto()] for n in self._name.goto()]
def infer(self): def infer(self):
if not self._name.is_context_name:
return []
tree_name = self._name.tree_name tree_name = self._name.tree_name
parent_context = self._name.parent_context parent_context = self._name.parent_context
# Param names are special because they are not handled by # Param names are special because they are not handled by
@@ -368,6 +380,9 @@ class BaseDefinition(object):
raise AttributeError('There are no params defined on this.') raise AttributeError('There are no params defined on this.')
def parent(self): def parent(self):
if not self._name.is_context_name:
return None
context = self._name.parent_context context = self._name.parent_context
if context is None: if context is None:
return None return None
@@ -393,7 +408,7 @@ class BaseDefinition(object):
:return str: Returns the line(s) of code or an empty string if it's a :return str: Returns the line(s) of code or an empty string if it's a
builtin. builtin.
""" """
if self.in_builtin_module(): if not self._name.is_context_name or self.in_builtin_module():
return '' return ''
lines = self._name.get_root_context().code_lines lines = self._name.get_root_context().code_lines
@@ -491,6 +506,8 @@ class Completion(BaseDefinition):
@memoize_method @memoize_method
def follow_definition(self): def follow_definition(self):
""" """
Deprecated!
Return the original definitions. I strongly recommend not using it for Return the original definitions. I strongly recommend not using it for
your completions, because it might slow down |jedi|. If you want to your completions, because it might slow down |jedi|. If you want to
read only a few objects (<=20), it might be useful, especially to get read only a few objects (<=20), it might be useful, especially to get
@@ -498,6 +515,14 @@ class Completion(BaseDefinition):
follows all results. This means with 1000 completions (e.g. numpy), follows all results. This means with 1000 completions (e.g. numpy),
it's just PITA-slow. it's just PITA-slow.
""" """
warnings.warn(
"Deprecated since version 0.14.0. Use .infer.",
DeprecationWarning,
stacklevel=2
)
if not self._name.is_context_name:
return []
defs = self._name.infer() defs = self._name.infer()
return [Definition(self._evaluator, d.name) for d in defs] return [Definition(self._evaluator, d.name) for d in defs]

View File

@@ -21,6 +21,7 @@ def get_operator(evaluator, string, pos):
class KeywordName(AbstractNameDefinition): class KeywordName(AbstractNameDefinition):
api_type = u'keyword' api_type = u'keyword'
is_context_name = False
def __init__(self, evaluator, name): def __init__(self, evaluator, name):
self.evaluator = evaluator self.evaluator = evaluator

View File

@@ -12,6 +12,10 @@ class AbstractNameDefinition(object):
string_name = None string_name = None
parent_context = None parent_context = None
tree_name = None tree_name = None
is_context_name = True
"""
Used for the Jedi API to know if it's a keyword or an actual name.
"""
@abstractmethod @abstractmethod
def infer(self): def infer(self):

View File

@@ -25,3 +25,24 @@ def test_keyword(Script, environment):
completions = Script("import", 1, 1).completions() completions = Script("import", 1, 1).completions()
assert len(completions) > 10 and 'if' in [c.name for c in completions] assert len(completions) > 10 and 'if' in [c.name for c in completions]
assert Script("assert").goto_definitions() == [] assert Script("assert").goto_definitions() == []
def test_keyword_attributes(Script):
def_, = Script('def').completions()
assert def_.name == 'def'
assert def_.complete == ''
assert def_.is_keyword is True
assert def_.is_stub() is False
assert def_.goto_stubs() == []
assert def_.goto_assignments() == []
assert def_.infer() == []
assert def_.parent() is None
assert def_.docstring()
assert def_.description == 'keyword def'
assert def_.get_line_code() == ''
assert def_.full_name == 'def'
assert def_.line is def_.column is None
assert def_.in_builtin_module() is True
assert def_.module_name in ('builtins', '__builtin__')
assert 'typeshed' in def_.module_path
assert def_.type == 'keyword'