forked from VimPlug/jedi
Separate getting docstrings and getting signatures for names, see discussion #1466
This commit is contained in:
@@ -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):
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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__()
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user