mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-06 22:14:27 +08:00
Infer doctests and signatures uniformly, fixes #1466
This commit is contained in:
@@ -350,7 +350,7 @@ class Script(object):
|
|||||||
|
|
||||||
:rtype: list of :class:`classes.Definition`
|
:rtype: list of :class:`classes.Definition`
|
||||||
"""
|
"""
|
||||||
definitions = self.goto(line, column)
|
definitions = self.goto(line, column, follow_imports=True)
|
||||||
if definitions:
|
if definitions:
|
||||||
return definitions
|
return definitions
|
||||||
leaf = self._module_node.get_leaf_for_position((line, column))
|
leaf = self._module_node.get_leaf_for_position((line, column))
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ class BaseDefinition(object):
|
|||||||
|
|
||||||
signature_text = '\n'.join(
|
signature_text = '\n'.join(
|
||||||
signature.to_string()
|
signature.to_string()
|
||||||
for signature in self._name.get_signatures()
|
for signature in self._get_signatures()
|
||||||
)
|
)
|
||||||
if signature_text and doc:
|
if signature_text and doc:
|
||||||
return signature_text + '\n\n' + doc
|
return signature_text + '\n\n' + doc
|
||||||
@@ -440,7 +440,8 @@ class BaseDefinition(object):
|
|||||||
return ''.join(lines[start_index:index + after + 1])
|
return ''.join(lines[start_index:index + after + 1])
|
||||||
|
|
||||||
def _get_signatures(self):
|
def _get_signatures(self):
|
||||||
return self._name.infer().get_signatures()
|
names = convert_names([self._name], prefer_stubs=True)
|
||||||
|
return [sig for name in names for sig in name.infer().get_signatures()]
|
||||||
|
|
||||||
def get_signatures(self):
|
def get_signatures(self):
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from abc import abstractmethod
|
|||||||
from parso.tree import search_ancestor
|
from parso.tree import search_ancestor
|
||||||
|
|
||||||
from jedi._compatibility import Parameter
|
from jedi._compatibility import Parameter
|
||||||
from jedi.parser_utils import find_statement_documentation
|
from jedi.parser_utils import find_statement_documentation, clean_scope_docstring
|
||||||
from jedi.inference.utils import unite
|
from jedi.inference.utils import unite
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||||
from jedi.inference import docstrings
|
from jedi.inference import docstrings
|
||||||
@@ -311,18 +311,22 @@ class TreeNameDefinition(AbstractTreeName):
|
|||||||
return indexes
|
return indexes
|
||||||
|
|
||||||
def py__doc__(self):
|
def py__doc__(self):
|
||||||
if self.api_type in ('function', 'class', 'module'):
|
api_type = self.api_type
|
||||||
|
if api_type in ('function', 'class'):
|
||||||
# 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()])
|
return clean_scope_docstring(self.tree_name.get_definition())
|
||||||
|
|
||||||
if self.api_type == 'statement' and self.tree_name.is_definition():
|
if api_type == 'module':
|
||||||
|
names = self.goto()
|
||||||
|
if self not in names:
|
||||||
|
return _merge_name_docs(names)
|
||||||
|
|
||||||
|
if 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())
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def get_signatures(self):
|
def get_signatures(self):
|
||||||
if self.api_type in ('function', 'class'):
|
return self.infer().get_signatures()
|
||||||
return self.infer().get_signatures()
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
class _ParamMixin(object):
|
class _ParamMixin(object):
|
||||||
@@ -597,7 +601,14 @@ class NameWrapper(object):
|
|||||||
class StubNameMixin(object):
|
class StubNameMixin(object):
|
||||||
def py__doc__(self):
|
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)
|
# Stubs are not complicated and we can just follow simple statements
|
||||||
|
# that have an equals in them, because they typically make something
|
||||||
|
# else public. See e.g. stubs for `requests`.
|
||||||
|
names = [self]
|
||||||
|
if self.api_type == 'statement' and '=' in self.tree_name.get_definition().children:
|
||||||
|
names = [v.name for v in self.infer()]
|
||||||
|
|
||||||
|
names = convert_names(names, prefer_stub_to_compiled=False)
|
||||||
if self in names:
|
if self in names:
|
||||||
return super(StubNameMixin, self).py__doc__()
|
return super(StubNameMixin, self).py__doc__()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
|
from . import module
|
||||||
|
|
||||||
|
func_with_stub = module.func_with_stub
|
||||||
|
|
||||||
both: int
|
both: int
|
||||||
stub_only: str
|
stub_only: str
|
||||||
|
|||||||
@@ -1 +1,5 @@
|
|||||||
in_sub_module: int
|
in_sub_module: int
|
||||||
|
|
||||||
|
|
||||||
|
def func_with_stub(b: int) -> float:
|
||||||
|
pass
|
||||||
|
|||||||
@@ -1,2 +1,7 @@
|
|||||||
|
from with_python import module as _module
|
||||||
|
|
||||||
|
func_without_stub = _module.func_without_stub
|
||||||
|
|
||||||
|
|
||||||
python_only = 1
|
python_only = 1
|
||||||
both = ''
|
both = ''
|
||||||
|
|||||||
@@ -1 +1,9 @@
|
|||||||
|
def func_without_stub(a):
|
||||||
|
'nostubdoc'
|
||||||
|
|
||||||
|
|
||||||
|
def func_with_stub(c):
|
||||||
|
'withstubdoc'
|
||||||
|
|
||||||
|
|
||||||
in_sub_module = ''
|
in_sub_module = ''
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ def test_help_no_returns(Script, code, kwargs):
|
|||||||
('X.x', 'Yeah '),
|
('X.x', 'Yeah '),
|
||||||
('X().x', 'Yeah '),
|
('X().x', 'Yeah '),
|
||||||
('X.y', 'f g '),
|
('X.y', 'f g '),
|
||||||
('X.z', ''),
|
('X.z', '<lambda>(x)'),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
def test_attribute_docstrings(goto_or_help, expected_doc, to_execute):
|
def test_attribute_docstrings(goto_or_help, expected_doc, to_execute):
|
||||||
@@ -70,7 +70,7 @@ def test_attribute_docstrings(goto_or_help, expected_doc, to_execute):
|
|||||||
""" Yeah """
|
""" Yeah """
|
||||||
y = 5
|
y = 5
|
||||||
"f g "
|
"f g "
|
||||||
z = lambda: 1
|
z = lambda x: 1
|
||||||
''')
|
''')
|
||||||
|
|
||||||
d, = goto_or_help(code + to_execute)
|
d, = goto_or_help(code + to_execute)
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ def test_multiple_docstrings(Script):
|
|||||||
x = func
|
x = func
|
||||||
'''Docstring of `x`.'''
|
'''Docstring of `x`.'''
|
||||||
x""").help()
|
x""").help()
|
||||||
assert d.docstring() == 'Docstring of `x`.'
|
assert d.docstring() == 'func()\n\nDocstring of `x`.'
|
||||||
|
|
||||||
|
|
||||||
def test_completion(Script):
|
def test_completion(Script):
|
||||||
@@ -168,15 +168,13 @@ def test_import_function_docstring(Script, skip_pre_python35):
|
|||||||
path = os.path.join(test_dir, 'completion', 'import_function_docstring.py')
|
path = os.path.join(test_dir, 'completion', 'import_function_docstring.py')
|
||||||
c, = Script(code, path=path).complete()
|
c, = Script(code, path=path).complete()
|
||||||
|
|
||||||
stub_signature = 'stub_function(x: int, y: float) -> str'
|
doc = 'stub_function(x: int, y: float) -> str\n\nPython docstring'
|
||||||
python_signature = 'stub_function(x: float, y)'
|
assert c.docstring() == doc
|
||||||
doc = '\n\nPython docstring'
|
|
||||||
assert c.docstring() == stub_signature + doc
|
|
||||||
assert c.type == 'function'
|
assert c.type == 'function'
|
||||||
func, = c.goto(prefer_stubs=True)
|
func, = c.goto(prefer_stubs=True)
|
||||||
assert func.docstring() == stub_signature + doc
|
assert func.docstring() == doc
|
||||||
func, = c.goto()
|
func, = c.goto()
|
||||||
assert func.docstring() == python_signature + doc
|
assert func.docstring() == doc
|
||||||
|
|
||||||
|
|
||||||
# ---- Numpy Style Tests ---
|
# ---- Numpy Style Tests ---
|
||||||
|
|||||||
@@ -25,3 +25,41 @@ def ScriptInStubFolder(Script):
|
|||||||
def test_find_stubs_infer(ScriptInStubFolder, code, expected):
|
def test_find_stubs_infer(ScriptInStubFolder, code, expected):
|
||||||
defs = ScriptInStubFolder(code).infer()
|
defs = ScriptInStubFolder(code).infer()
|
||||||
assert [d.name for d in defs] == expected
|
assert [d.name for d in defs] == expected
|
||||||
|
|
||||||
|
|
||||||
|
func_without_stub_sig = 'func_without_stub(a)'
|
||||||
|
func_without_stub_doc = func_without_stub_sig + '\n\nnostubdoc'
|
||||||
|
func_with_stub_doc = 'func_with_stub(b: int) -> float\n\nwithstubdoc'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
('code', 'expected'), [
|
||||||
|
('from with_python import stub_only', ''),
|
||||||
|
('from with_python import python_only', ''),
|
||||||
|
('from with_python import both', ''),
|
||||||
|
|
||||||
|
('import with_python; with_python.func_without_stub', func_without_stub_sig),
|
||||||
|
('import with_python.module; with_python.module.func_without_stub', func_without_stub_doc),
|
||||||
|
('from with_python import module; module.func_without_stub', func_without_stub_doc),
|
||||||
|
('from with_python.module import func_without_stub', func_without_stub_doc),
|
||||||
|
('from with_python.module import func_without_stub as f; f', func_without_stub_doc),
|
||||||
|
('from with_python.module import func_without_stub; func_without_stub',
|
||||||
|
func_without_stub_doc),
|
||||||
|
('from with_python import func_without_stub', func_without_stub_sig),
|
||||||
|
('from with_python import func_without_stub as f; f', func_without_stub_sig),
|
||||||
|
('from with_python import func_without_stub; func_without_stub', func_without_stub_sig),
|
||||||
|
|
||||||
|
('import with_python; with_python.func_with_stub', func_with_stub_doc),
|
||||||
|
('import with_python.module; with_python.module.func_with_stub', func_with_stub_doc),
|
||||||
|
('from with_python import module; module.func_with_stub', func_with_stub_doc),
|
||||||
|
('from with_python.module import func_with_stub', func_with_stub_doc),
|
||||||
|
('from with_python.module import func_with_stub as f; f', func_with_stub_doc),
|
||||||
|
('from with_python.module import func_with_stub; func_with_stub', func_with_stub_doc),
|
||||||
|
('from with_python import func_with_stub', func_with_stub_doc),
|
||||||
|
('from with_python import func_with_stub as f; f', func_with_stub_doc),
|
||||||
|
('from with_python import func_with_stub; func_with_stub', func_with_stub_doc),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_docstrings(ScriptInStubFolder, code, expected):
|
||||||
|
d, = ScriptInStubFolder(code).help()
|
||||||
|
assert d.docstring() == expected
|
||||||
|
|||||||
Reference in New Issue
Block a user