Merge branch 'add-numpydoc-support' of git://github.com/immerrr/jedi into dev

This commit is contained in:
Dave Halter
2014-07-27 11:23:39 +02:00
5 changed files with 132 additions and 29 deletions

View File

@@ -6,7 +6,7 @@ Changelog
0.8.1 (2014-07-23) 0.8.1 (2014-07-23)
+++++++++++++++++++ +++++++++++++++++++
* Bugfix release, the last release forgot to include files that improve - Bugfix release, the last release forgot to include files that improve
autocompletion for builtin libraries. Fixed. autocompletion for builtin libraries. Fixed.
0.8.0 (2014-05-05) 0.8.0 (2014-05-05)
@@ -16,26 +16,27 @@ Changelog
drastically. Loading times are down as well (it takes basically as long as an drastically. Loading times are down as well (it takes basically as long as an
import). import).
- REPL completion is starting to become usable. - REPL completion is starting to become usable.
- Various small API changes. Generally this released focuses on stability and - Various small API changes. Generally this release focuses on stability and
refactoring of internal APIs. refactoring of internal APIs.
- Introducing operator precedence, which makes calculating correct Array indices - Introducing operator precedence, which makes calculating correct Array
and ``__getattr__`` strings possible. indices and ``__getattr__`` strings possible.
0.7.0 (2013-08-09) 0.7.0 (2013-08-09)
++++++++++++++++++ ++++++++++++++++++
- Switched from LGPL to MIT license - Switched from LGPL to MIT license.
- Added an Interpreter class to the API to make autocompletion in REPL possible. - Added an Interpreter class to the API to make autocompletion in REPL
- Added autocompletion support for namespace packages possible.
- Add sith.py, a new random testing method - Added autocompletion support for namespace packages.
- Add sith.py, a new random testing method.
0.6.0 (2013-05-14) 0.6.0 (2013-05-14)
++++++++++++++++++ ++++++++++++++++++
- Much faster parser with builtin part caching - Much faster parser with builtin part caching.
- A test suite, thanks @tkf - A test suite, thanks @tkf.
0.5 versions (2012) 0.5 versions (2012)
+++++++++++++++++++ +++++++++++++++++++
- Initial development - Initial development.

View File

@@ -119,10 +119,11 @@ http://sphinx-doc.org/domains.html#info-field-lists
:: ::
def myfunction(node): def myfunction(node, foo):
"""Do something with a ``node``. """Do something with a ``node``.
:type node: ProgramNode :type node: ProgramNode
:param str foo: foo parameter description
""" """
node.| # complete here node.| # complete here

View File

@@ -14,6 +14,7 @@ As an addition to parameter searching, this module also provides return
annotations. annotations.
""" """
from ast import literal_eval
import re import re
from itertools import chain from itertools import chain
from textwrap import dedent from textwrap import dedent
@@ -24,6 +25,7 @@ from jedi.common import indent_block
DOCSTRING_PARAM_PATTERNS = [ DOCSTRING_PARAM_PATTERNS = [
r'\s*:type\s+%s:\s*([^\n]+)', # Sphinx r'\s*:type\s+%s:\s*([^\n]+)', # Sphinx
r'\s*:param\s+(\w+)\s+%s:[^\n]+', # Sphinx param with type
r'\s*@type\s+%s:\s*([^\n]+)', # Epydoc r'\s*@type\s+%s:\s*([^\n]+)', # Epydoc
] ]
@@ -35,26 +37,44 @@ DOCSTRING_RETURN_PATTERNS = [
REST_ROLE_PATTERN = re.compile(r':[^`]+:`([^`]+)`') REST_ROLE_PATTERN = re.compile(r':[^`]+:`([^`]+)`')
@memoize_default(None, evaluator_is_first_arg=True) try:
def follow_param(evaluator, param): from numpydoc.docscrape import NumpyDocString
func = param.parent_function except ImportError:
param_str = _search_param_in_docstr(func.raw_doc, str(param.get_name())) def _search_param_in_numpydocstr(docstr, param_str):
return _evaluate_for_statement_string(evaluator, param_str, param.get_parent_until()) return []
else:
def _search_param_in_numpydocstr(docstr, param_str):
"""Search `docstr` (in numpydoc format) for type(-s) of `param_str`."""
params = NumpyDocString(docstr)._parsed_data['Parameters']
for p_name, p_type, p_descr in params:
if p_name == param_str:
m = re.match('([^,]+(,[^,]+)*?)(,[ ]*optional)?$', p_type)
if m:
p_type = m.group(1)
if p_type.startswith('{'):
types = set(type(x).__name__ for x in literal_eval(p_type))
return list(types)
else:
return [p_type]
return []
def _search_param_in_docstr(docstr, param_str): def _search_param_in_docstr(docstr, param_str):
""" """
Search `docstr` for a type of `param_str`. Search `docstr` for type(-s) of `param_str`.
>>> _search_param_in_docstr(':type param: int', 'param') >>> _search_param_in_docstr(':type param: int', 'param')
'int' ['int']
>>> _search_param_in_docstr('@type param: int', 'param') >>> _search_param_in_docstr('@type param: int', 'param')
'int' ['int']
>>> _search_param_in_docstr( >>> _search_param_in_docstr(
... ':type param: :class:`threading.Thread`', 'param') ... ':type param: :class:`threading.Thread`', 'param')
'threading.Thread' ['threading.Thread']
>>> _search_param_in_docstr('no document', 'param') is None >>> bool(_search_param_in_docstr('no document', 'param'))
True False
>>> _search_param_in_docstr(':param int param: some description', 'param')
['int']
""" """
# look at #40 to see definitions of those params # look at #40 to see definitions of those params
@@ -63,9 +83,10 @@ def _search_param_in_docstr(docstr, param_str):
for pattern in patterns: for pattern in patterns:
match = pattern.search(docstr) match = pattern.search(docstr)
if match: if match:
return _strip_rst_role(match.group(1)) return [_strip_rst_role(match.group(1))]
return None return (_search_param_in_numpydocstr(docstr, param_str) or
[])
def _strip_rst_role(type_str): def _strip_rst_role(type_str):
@@ -126,6 +147,17 @@ def _evaluate_for_statement_string(evaluator, string, module):
return list(chain.from_iterable(it)) or definitions return list(chain.from_iterable(it)) or definitions
@memoize_default(None, evaluator_is_first_arg=True)
def follow_param(evaluator, param):
func = param.parent_function
return [p
for param_str in _search_param_in_docstr(func.raw_doc,
str(param.get_name()))
for p in _evaluate_for_statement_string(evaluator, param_str,
param.get_parent_until())]
@memoize_default(None, evaluator_is_first_arg=True) @memoize_default(None, evaluator_is_first_arg=True)
def find_return_types(evaluator, func): def find_return_types(evaluator, func):
def search_return_in_docstr(code): def search_return_in_docstr(code):

View File

@@ -3,13 +3,14 @@
# ----------------- # -----------------
# sphinx style # sphinx style
# ----------------- # -----------------
def f(a, b, c, d): def f(a, b, c, d, x):
""" asdfasdf """ asdfasdf
:param a: blablabla :param a: blablabla
:type a: str :type a: str
:type b: (str, int) :type b: (str, int)
:type c: threading.Thread :type c: threading.Thread
:type d: :class:`threading.Thread` :type d: :class:`threading.Thread`
:param str x: blablabla
:rtype: dict :rtype: dict
""" """
#? str() #? str()
@@ -22,23 +23,28 @@ def f(a, b, c, d):
c.join c.join
#? ['join'] #? ['join']
d.join d.join
#? ['lower']
x.lower
#? dict() #? dict()
f() f()
# wrong declarations # wrong declarations
def f(a, b): def f(a, b, x):
""" """
:param a: Forgot type declaration :param a: Forgot type declaration
:type a: :type a:
:param b: Just something :param b: Just something
:type b: `` :type b: ``
:param x: Just something without type
:rtype: :rtype:
""" """
#? #?
a a
#? #?
b b
#?
x
#? #?
f() f()

View File

@@ -6,6 +6,13 @@ from textwrap import dedent
import jedi import jedi
from ..helpers import unittest from ..helpers import unittest
try:
import numpydoc
except ImportError:
numpydoc_unavailable = True
else:
numpydoc_unavailable = False
class TestDocstring(unittest.TestCase): class TestDocstring(unittest.TestCase):
def test_function_doc(self): def test_function_doc(self):
@@ -50,6 +57,16 @@ class TestDocstring(unittest.TestCase):
names = [c.name for c in jedi.Script(s).completions()] names = [c.name for c in jedi.Script(s).completions()]
assert 'start' in names assert 'start' in names
def test_docstrings_param_type(self):
s = """
def func(arg):
'''
:param str arg: some description
'''
arg."""
names = [c.name for c in jedi.Script(s).completions()]
assert 'join' in names
def test_docstrings_type_str(self): def test_docstrings_type_str(self):
s = """ s = """
def func(arg): def func(arg):
@@ -87,3 +104,49 @@ class TestDocstring(unittest.TestCase):
assert 'a' in names assert 'a' in names
assert '__init__' in names assert '__init__' in names
assert 'mro' not in names # Exists only for types. assert 'mro' not in names # Exists only for types.
@unittest.skipIf(numpydoc_unavailable, 'numpydoc module is unavailable')
def test_numpydoc_docstring(self):
s = dedent('''
def foobar(x, y):
"""
Parameters
----------
x : int
y : str
"""
y.''')
names = [c.name for c in jedi.Script(s).completions()]
assert 'isupper' in names
assert 'capitalize' in names
@unittest.skipIf(numpydoc_unavailable, 'numpydoc module is unavailable')
def test_numpydoc_docstring_set_of_values(self):
s = dedent('''
def foobar(x, y):
"""
Parameters
----------
x : {'foo', 'bar', 100500}, optional
"""
x.''')
names = [c.name for c in jedi.Script(s).completions()]
assert 'isupper' in names
assert 'capitalize' in names
assert 'numerator' in names
@unittest.skipIf(numpydoc_unavailable, 'numpydoc module is unavailable')
def test_numpydoc_alternative_types(self):
s = dedent('''
def foobar(x, y):
"""
Parameters
----------
x : int or str or list
"""
x.''')
names = [c.name for c in jedi.Script(s).completions()]
assert 'isupper' in names
assert 'capitalize' in names
assert 'numerator' in names
assert 'append' in names