1
0
forked from VimPlug/jedi

Separate getting docstrings and getting signatures for names, see discussion #1466

This commit is contained in:
Dave Halter
2020-01-01 22:58:52 +01:00
parent bb3a81c578
commit 0a53ce5136
6 changed files with 56 additions and 40 deletions

View File

@@ -241,7 +241,18 @@ class BaseDefinition(object):
""" """
if isinstance(self._name, ImportName) and fast: if isinstance(self._name, ImportName) and fast:
return '' return ''
return self._name.py__doc__(include_signatures=not raw) doc = self._name.py__doc__()
if raw:
return doc
signature_text = '\n'.join(
signature.to_string()
for signature in self._name.get_signatures()
)
if signature_text and doc:
return signature_text + '\n\n' + doc
else:
return signature_text + doc
@property @property
def description(self): def description(self):

View File

@@ -18,7 +18,7 @@ except ImportError:
class KeywordName(AbstractArbitraryName): class KeywordName(AbstractArbitraryName):
api_type = u'keyword' api_type = u'keyword'
def py__doc__(self, include_signatures=False): def py__doc__(self):
return imitate_pydoc(self.string_name) return imitate_pydoc(self.string_name)

View File

@@ -301,7 +301,7 @@ class CompiledName(AbstractNameDefinition):
self.parent_context = parent_context self.parent_context = parent_context
self.string_name = name self.string_name = name
def py__doc__(self, include_signatures=False): def py__doc__(self):
value, = self.infer() value, = self.infer()
return value.py__doc__() return value.py__doc__()

View File

@@ -12,30 +12,17 @@ from jedi.inference.helpers import deep_ast_copy, infer_call_of_leaf
from jedi.plugins import plugin_manager from jedi.plugins import plugin_manager
def _merge_name_docs(names, include_signatures): def _merge_name_docs(names):
doc = '' doc = ''
for name in names: for name in names:
if doc: if doc:
# In case we have multiple values, just return all of them # In case we have multiple values, just return all of them
# separated by a few dashes. # separated by a few dashes.
doc += '\n' + '-' * 30 + '\n' doc += '\n' + '-' * 30 + '\n'
doc += name.py__doc__(include_signatures) doc += name.py__doc__()
return doc return doc
def _merge_docs_and_signature(values, doc):
signature_text = '\n'.join(
signature.to_string()
for value in values
for signature in value.get_signatures()
)
if signature_text and doc:
return signature_text + '\n\n' + doc
else:
return signature_text + doc
class AbstractNameDefinition(object): class AbstractNameDefinition(object):
start_pos = None start_pos = None
string_name = None string_name = None
@@ -85,7 +72,10 @@ class AbstractNameDefinition(object):
def is_import(self): def is_import(self):
return False return False
def py__doc__(self, include_signatures=False): def get_signatures(self):
return []
def py__doc__(self):
return '' return ''
@property @property
@@ -226,12 +216,11 @@ class ValueNameMixin(object):
def infer(self): def infer(self):
return ValueSet([self._value]) return ValueSet([self._value])
def py__doc__(self, include_signatures=False): def py__doc__(self):
doc = self._value.py__doc__() return self._value.py__doc__()
if include_signatures: def get_signatures(self):
doc = _merge_docs_and_signature([self._value], doc) return self._value.get_signatures()
return doc
def _get_qualified_names(self): def _get_qualified_names(self):
return self._value.get_qualified_names() return self._value.get_qualified_names()
@@ -321,15 +310,20 @@ class TreeNameDefinition(AbstractTreeName):
node = node.parent node = node.parent
return indexes return indexes
def py__doc__(self, include_signatures=False): def py__doc__(self):
if self.api_type in ('function', 'class', 'module'): if self.api_type in ('function', 'class', 'module'):
# Make sure the names are not TreeNameDefinitions anymore. # Make sure the names are not TreeNameDefinitions anymore.
return _merge_name_docs([v.name for v in self.infer()], include_signatures) return _merge_name_docs([v.name for v in self.infer()])
if self.api_type == 'statement' and self.tree_name.is_definition(): if self.api_type == 'statement' and self.tree_name.is_definition():
return find_statement_documentation(self.tree_name.get_definition()) return find_statement_documentation(self.tree_name.get_definition())
assert False, self.api_type
return ''
return super(TreeNameDefinition, self).py__doc__(include_signatures) def get_signatures(self):
if self.api_type in ('function', 'class'):
return self.infer().get_signatures()
return []
class _ParamMixin(object): class _ParamMixin(object):
@@ -579,8 +573,11 @@ class ImportName(AbstractNameDefinition):
def api_type(self): def api_type(self):
return 'module' return 'module'
def py__doc__(self, include_signatures=False): def py__doc__(self):
return _merge_name_docs(self.goto(), include_signatures) return _merge_name_docs(self.goto())
def get_signatures(self):
return [sig for name in self.goto() for sig in name.get_signatures()]
class SubModuleName(ImportName): class SubModuleName(ImportName):
@@ -591,10 +588,6 @@ class NameWrapper(object):
def __init__(self, wrapped_name): def __init__(self, wrapped_name):
self._wrapped_name = wrapped_name self._wrapped_name = wrapped_name
@abstractmethod
def infer(self):
raise NotImplementedError
def __getattr__(self, name): def __getattr__(self, name):
return getattr(self._wrapped_name, name) return getattr(self._wrapped_name, name)
@@ -603,20 +596,22 @@ class NameWrapper(object):
class StubNameMixin(object): class StubNameMixin(object):
def py__doc__(self, include_signatures=False): def py__doc__(self):
from jedi.inference.gradual.conversion import convert_names from jedi.inference.gradual.conversion import convert_names
names = convert_names([self], prefer_stub_to_compiled=False) names = convert_names([self], prefer_stub_to_compiled=False)
if self in names: if self in names:
doc = super(StubNameMixin, self).py__doc__(include_signatures) return super(StubNameMixin, self).py__doc__()
else: else:
# We have signatures ourselves in stubs, so don't use signatures # We have signatures ourselves in stubs, so don't use signatures
# from the implementation. # from the implementation.
doc = _merge_name_docs(names, include_signatures=False) return _merge_name_docs(names)
if include_signatures and self.tree_name is not None:
def get_signatures(self):
if self.tree_name is not None:
parent = self.tree_name.parent parent = self.tree_name.parent
if parent.type in ('funcdef', 'classdef') and parent.name is self.tree_name: if parent.type in ('funcdef', 'classdef') and parent.name is self.tree_name:
doc = _merge_docs_and_signature(self.infer(), doc) return self.infer().get_signatures()
return doc return []
# From here on down we make looking up the sys.version_info fast. # From here on down we make looking up the sys.version_info fast.

View File

@@ -515,10 +515,13 @@ class LazyInstanceClassName(NameWrapper):
@iterator_to_value_set @iterator_to_value_set
def infer(self): def infer(self):
for result_value in super(LazyInstanceClassName, self).infer(): for result_value in self._wrapped_name.infer():
for c in result_value.py__get__(self._instance, self._instance.py__class__()): for c in result_value.py__get__(self._instance, self._instance.py__class__()):
yield c yield c
def get_signatures(self):
return self.infer().get_signatures()
class InstanceClassFilter(AbstractFilter): class InstanceClassFilter(AbstractFilter):
""" """

View File

@@ -145,6 +145,13 @@ def test_async(Script, environment):
assert 'hey' in names assert 'hey' in names
def test_method_doc_with_signature(Script):
code = 'f = open("")\nf.writelin'
c, = Script(code).complete()
assert c.name == 'writelines'
assert c.docstring() == 'writelines(lines: Iterable[AnyStr]) -> None'
def test_with_stmt_error_recovery(Script): def test_with_stmt_error_recovery(Script):
assert Script('with open('') as foo: foo.\na').complete(line=1) assert Script('with open('') as foo: foo.\na').complete(line=1)