mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-03 16:10:05 +08:00
542 lines
13 KiB
Python
Vendored
542 lines
13 KiB
Python
Vendored
"""
|
|
Testing of docstring related issues and especially ``jedi.docstrings``.
|
|
"""
|
|
|
|
import os
|
|
from textwrap import dedent
|
|
|
|
import pytest
|
|
|
|
import jedi
|
|
from ..helpers import test_dir
|
|
|
|
try:
|
|
import numpydoc # NOQA
|
|
except ImportError:
|
|
numpydoc_unavailable = True
|
|
else:
|
|
numpydoc_unavailable = False
|
|
|
|
try:
|
|
import numpy # NOQA
|
|
except ImportError:
|
|
numpy_unavailable = True
|
|
else:
|
|
numpy_unavailable = False
|
|
|
|
|
|
def test_function_doc(Script):
|
|
defs = Script("""
|
|
def func():
|
|
'''Docstring of `func`.'''
|
|
func""").infer()
|
|
assert defs[0].docstring() == 'func()\n\nDocstring of `func`.'
|
|
|
|
|
|
def test_class_doc(Script):
|
|
defs = Script("""
|
|
class TestClass():
|
|
'''Docstring of `TestClass`.'''
|
|
TestClass""").infer()
|
|
|
|
expected = 'Docstring of `TestClass`.'
|
|
assert defs[0].docstring(raw=True) == expected
|
|
assert defs[0].docstring() == 'TestClass()\n\n' + expected
|
|
|
|
|
|
def test_class_doc_with_init(Script):
|
|
d, = Script("""
|
|
class TestClass():
|
|
'''Docstring'''
|
|
def __init__(self, foo, bar=3): pass
|
|
TestClass""").infer()
|
|
|
|
assert d.docstring() == 'TestClass(foo, bar=3)\n\nDocstring'
|
|
|
|
|
|
def test_instance_doc(Script):
|
|
defs = Script("""
|
|
class TestClass():
|
|
'''Docstring of `TestClass`.'''
|
|
tc = TestClass()
|
|
tc""").infer()
|
|
assert defs[0].docstring() == 'Docstring of `TestClass`.'
|
|
|
|
|
|
def test_multiple_docstrings(Script):
|
|
d, = Script("""
|
|
def func():
|
|
'''Original docstring.'''
|
|
x = func
|
|
'''Docstring of `x`.'''
|
|
x""").help()
|
|
assert d.docstring() == 'Docstring of `x`.'
|
|
|
|
|
|
def test_completion(Script):
|
|
assert not Script('''
|
|
class DocstringCompletion():
|
|
#? []
|
|
""" asdfas """''').complete()
|
|
|
|
|
|
def test_docstrings_type_dotted_import(Script):
|
|
s = """
|
|
def func(arg):
|
|
'''
|
|
:type arg: random.Random
|
|
'''
|
|
arg."""
|
|
names = [c.name for c in Script(s).complete()]
|
|
assert 'seed' in names
|
|
|
|
|
|
def test_docstrings_param_type(Script):
|
|
s = """
|
|
def func(arg):
|
|
'''
|
|
:param str arg: some description
|
|
'''
|
|
arg."""
|
|
names = [c.name for c in Script(s).complete()]
|
|
assert 'join' in names
|
|
|
|
|
|
def test_docstrings_type_str(Script):
|
|
s = """
|
|
def func(arg):
|
|
'''
|
|
:type arg: str
|
|
'''
|
|
arg."""
|
|
|
|
names = [c.name for c in Script(s).complete()]
|
|
assert 'join' in names
|
|
|
|
|
|
def test_docstring_instance(Script):
|
|
# The types hint that it's a certain kind
|
|
s = dedent("""
|
|
class A:
|
|
def __init__(self,a):
|
|
'''
|
|
:type a: threading.Thread
|
|
'''
|
|
|
|
if a is not None:
|
|
a.start()
|
|
|
|
self.a = a
|
|
|
|
|
|
def method_b(c):
|
|
'''
|
|
:type c: A
|
|
'''
|
|
|
|
c.""")
|
|
|
|
names = [c.name for c in Script(s).complete()]
|
|
assert 'a' in names
|
|
assert '__init__' in names
|
|
assert 'mro' not in names # Exists only for types.
|
|
|
|
|
|
def test_docstring_keyword(Script):
|
|
completions = Script('assert').complete()
|
|
assert 'assert' in completions[0].docstring()
|
|
|
|
|
|
def test_docstring_params_formatting(Script):
|
|
defs = Script("""
|
|
def func(param1,
|
|
param2,
|
|
param3):
|
|
pass
|
|
func""").infer()
|
|
assert defs[0].docstring() == 'func(param1, param2, param3)'
|
|
|
|
|
|
def test_import_function_docstring(Script):
|
|
code = "from stub_folder import with_stub; with_stub.stub_function"
|
|
path = os.path.join(test_dir, 'completion', 'import_function_docstring.py')
|
|
c, = Script(code, path=path).complete()
|
|
|
|
doc = 'stub_function(x: int, y: float) -> str\n\nPython docstring'
|
|
assert c.docstring() == doc
|
|
assert c.type == 'function'
|
|
func, = c.goto(prefer_stubs=True)
|
|
assert func.docstring() == doc
|
|
func, = c.goto()
|
|
assert func.docstring() == doc
|
|
|
|
|
|
# ---- Numpy Style Tests ---
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable,
|
|
reason='numpydoc module is unavailable')
|
|
def test_numpydoc_parameters():
|
|
s = dedent('''
|
|
def foobar(x, y):
|
|
"""
|
|
Parameters
|
|
----------
|
|
x : int
|
|
y : str
|
|
"""
|
|
y.''')
|
|
names = [c.name for c in jedi.Script(s).complete()]
|
|
assert 'isupper' in names
|
|
assert 'capitalize' in names
|
|
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable,
|
|
reason='numpydoc module is unavailable')
|
|
def test_numpydoc_parameters_set_of_values():
|
|
s = dedent('''
|
|
def foobar(x, y):
|
|
"""
|
|
Parameters
|
|
----------
|
|
x : {'foo', 'bar', 100500}, optional
|
|
"""
|
|
x.''')
|
|
names = [c.name for c in jedi.Script(s).complete()]
|
|
assert 'isupper' in names
|
|
assert 'capitalize' in names
|
|
assert 'numerator' in names
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable,
|
|
reason='numpydoc module is unavailable')
|
|
def test_numpydoc_parameters_set_single_value():
|
|
"""
|
|
This is found in numpy masked-array I'm not too sure what this means but should not crash
|
|
"""
|
|
s = dedent('''
|
|
def foobar(x, y):
|
|
"""
|
|
Parameters
|
|
----------
|
|
x : {var}, optional
|
|
"""
|
|
x.''')
|
|
names = [c.name for c in jedi.Script(s).complete()]
|
|
# just don't crash
|
|
assert names == []
|
|
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable,
|
|
reason='numpydoc module is unavailable')
|
|
def test_numpydoc_parameters_alternative_types():
|
|
s = dedent('''
|
|
def foobar(x, y):
|
|
"""
|
|
Parameters
|
|
----------
|
|
x : int or str or list
|
|
"""
|
|
x.''')
|
|
names = [c.name for c in jedi.Script(s).complete()]
|
|
assert 'isupper' in names
|
|
assert 'capitalize' in names
|
|
assert 'numerator' in names
|
|
assert 'append' in names
|
|
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable,
|
|
reason='numpydoc module is unavailable')
|
|
def test_numpydoc_invalid():
|
|
s = dedent('''
|
|
def foobar(x, y):
|
|
"""
|
|
Parameters
|
|
----------
|
|
x : int (str, py.path.local
|
|
"""
|
|
x.''')
|
|
|
|
assert not jedi.Script(s).complete()
|
|
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable,
|
|
reason='numpydoc module is unavailable')
|
|
def test_numpydoc_returns():
|
|
s = dedent('''
|
|
def foobar():
|
|
"""
|
|
Returns
|
|
----------
|
|
x : int
|
|
y : str
|
|
"""
|
|
return x
|
|
|
|
def bazbiz():
|
|
z = foobar()
|
|
z.''')
|
|
names = [c.name for c in jedi.Script(s).complete()]
|
|
assert 'isupper' in names
|
|
assert 'capitalize' in names
|
|
assert 'numerator' in names
|
|
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable,
|
|
reason='numpydoc module is unavailable')
|
|
def test_numpydoc_returns_set_of_values():
|
|
s = dedent('''
|
|
def foobar():
|
|
"""
|
|
Returns
|
|
----------
|
|
x : {'foo', 'bar', 100500}
|
|
"""
|
|
return x
|
|
|
|
def bazbiz():
|
|
z = foobar()
|
|
z.''')
|
|
names = [c.name for c in jedi.Script(s).complete()]
|
|
assert 'isupper' in names
|
|
assert 'capitalize' in names
|
|
assert 'numerator' in names
|
|
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable,
|
|
reason='numpydoc module is unavailable')
|
|
def test_numpydoc_returns_alternative_types():
|
|
s = dedent('''
|
|
def foobar():
|
|
"""
|
|
Returns
|
|
----------
|
|
int or list of str
|
|
"""
|
|
return x
|
|
|
|
def bazbiz():
|
|
z = foobar()
|
|
z.''')
|
|
names = [c.name for c in jedi.Script(s).complete()]
|
|
assert 'isupper' not in names
|
|
assert 'capitalize' not in names
|
|
assert 'numerator' in names
|
|
assert 'append' in names
|
|
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable,
|
|
reason='numpydoc module is unavailable')
|
|
def test_numpydoc_returns_list_of():
|
|
s = dedent('''
|
|
def foobar():
|
|
"""
|
|
Returns
|
|
----------
|
|
list of str
|
|
"""
|
|
return x
|
|
|
|
def bazbiz():
|
|
z = foobar()
|
|
z.''')
|
|
names = [c.name for c in jedi.Script(s).complete()]
|
|
assert 'append' in names
|
|
assert 'isupper' not in names
|
|
assert 'capitalize' not in names
|
|
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable,
|
|
reason='numpydoc module is unavailable')
|
|
def test_numpydoc_returns_obj():
|
|
s = dedent('''
|
|
def foobar(x, y):
|
|
"""
|
|
Returns
|
|
----------
|
|
int or random.Random
|
|
"""
|
|
return x + y
|
|
|
|
def bazbiz():
|
|
z = foobar(x, y)
|
|
z.''')
|
|
script = jedi.Script(s)
|
|
names = [c.name for c in script.complete()]
|
|
assert 'numerator' in names
|
|
assert 'seed' in names
|
|
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable,
|
|
reason='numpydoc module is unavailable')
|
|
def test_numpydoc_yields():
|
|
s = dedent('''
|
|
def foobar():
|
|
"""
|
|
Yields
|
|
----------
|
|
x : int
|
|
y : str
|
|
"""
|
|
return x
|
|
|
|
def bazbiz():
|
|
z = foobar():
|
|
z.''')
|
|
names = [c.name for c in jedi.Script(s).complete()]
|
|
assert 'isupper' in names
|
|
assert 'capitalize' in names
|
|
assert 'numerator' in names
|
|
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable or numpy_unavailable,
|
|
reason='numpydoc or numpy module is unavailable')
|
|
def test_numpy_returns():
|
|
s = dedent('''
|
|
import numpy
|
|
x = numpy.asarray([])
|
|
x.d'''
|
|
)
|
|
names = [c.name for c in jedi.Script(s).complete()]
|
|
assert 'diagonal' in names
|
|
|
|
|
|
@pytest.mark.skipif(numpydoc_unavailable or numpy_unavailable,
|
|
reason='numpydoc or numpy module is unavailable')
|
|
def test_numpy_comp_returns():
|
|
s = dedent('''
|
|
import numpy
|
|
x = numpy.array([])
|
|
x.d'''
|
|
)
|
|
names = [c.name for c in jedi.Script(s).complete()]
|
|
assert 'diagonal' in names
|
|
|
|
|
|
def test_decorator(Script):
|
|
code = dedent('''
|
|
def decorator(name=None):
|
|
def _decorate(func):
|
|
@wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
"""wrapper docstring"""
|
|
return func(*args, **kwargs)
|
|
return wrapper
|
|
return _decorate
|
|
|
|
|
|
@decorator('testing')
|
|
def check_user(f):
|
|
"""Nice docstring"""
|
|
pass
|
|
|
|
check_user''')
|
|
|
|
d, = Script(code).infer()
|
|
assert d.docstring(raw=True) == 'Nice docstring'
|
|
|
|
|
|
def test_method_decorator(Script):
|
|
code = dedent('''
|
|
def decorator(func):
|
|
@wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
"""wrapper docstring"""
|
|
return func(*args, **kwargs)
|
|
return wrapper
|
|
|
|
class Foo():
|
|
@decorator
|
|
def check_user(self, f):
|
|
"""Nice docstring"""
|
|
pass
|
|
|
|
Foo().check_user''')
|
|
|
|
d, = Script(code).infer()
|
|
assert d.docstring() == 'wrapper(f)\n\nNice docstring'
|
|
|
|
|
|
def test_partial(Script):
|
|
code = dedent('''
|
|
def foo():
|
|
'x y z'
|
|
from functools import partial
|
|
x = partial(foo)
|
|
x''')
|
|
|
|
for p in Script(code).infer():
|
|
assert p.docstring(raw=True) == 'x y z'
|
|
|
|
|
|
def test_basic_str_init_signature(Script, disable_typeshed):
|
|
# See GH #1414 and GH #1426
|
|
code = dedent('''
|
|
class Foo(str):
|
|
pass
|
|
Foo(''')
|
|
c, = Script(code).get_signatures()
|
|
assert c.name == 'Foo'
|
|
|
|
|
|
def test_doctest_result_completion(Script):
|
|
code = '''\
|
|
"""
|
|
comment
|
|
|
|
>>> something = 3
|
|
somethi
|
|
"""
|
|
something_else = 8
|
|
'''
|
|
c1, c2 = Script(code).complete(line=5)
|
|
assert c1.complete == 'ng'
|
|
assert c2.complete == 'ng_else'
|
|
|
|
|
|
def test_doctest_function_start(Script):
|
|
code = dedent('''\
|
|
def test(a, b):
|
|
"""
|
|
From GH #1585
|
|
|
|
>>> a = {}
|
|
>>> b = {}
|
|
>>> get_remainder(a, b) == {
|
|
... "foo": 10, "bar": 7
|
|
... }
|
|
"""
|
|
return
|
|
''')
|
|
assert Script(code).complete(7, 8)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"name, docstring", [
|
|
('prop1', 'Returns prop1.'),
|
|
('prop2', 'Returns None or ...'),
|
|
('prop3', 'Non-sense property.'),
|
|
('prop4', 'Django like property'),
|
|
]
|
|
)
|
|
def test_property(name, docstring, goto_or_complete):
|
|
code = dedent('''
|
|
from typing import Optional
|
|
class Test:
|
|
@property
|
|
def prop1(self) -> int:
|
|
"""Returns prop1."""
|
|
|
|
@property
|
|
def prop2(self) -> Optional[int]:
|
|
"""Returns None or ..."""
|
|
|
|
@property
|
|
def prop3(self) -> None:
|
|
"""Non-sense property."""
|
|
|
|
@cached_property # Not imported, but Jedi uses a heuristic
|
|
def prop4(self) -> None:
|
|
"""Django like property"""
|
|
''')
|
|
n, = goto_or_complete(code + 'Test().' + name)
|
|
assert n.docstring() == docstring
|