mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Closes #1429: Adds smarter Args parsing for Google style docstrings.
This commit is contained in:
parent
3e7ce5d3a1
commit
c430f7f4c6
@ -24,7 +24,8 @@ if sys.version_info[0] >= 3:
|
|||||||
|
|
||||||
|
|
||||||
_directive_regex = re.compile(r'\.\. \S+::')
|
_directive_regex = re.compile(r'\.\. \S+::')
|
||||||
_field_parens_regex = re.compile(r'\s*(\w+)\s*\(\s*(.+?)\s*\)')
|
_google_untyped_arg_regex = re.compile(r'\s*(\w+)\s*:\s*(.*)')
|
||||||
|
_google_typed_arg_regex = re.compile(r'\s*(\w+)\s*\(\s*(.+?)\s*\)\s*:\s*(.*)')
|
||||||
|
|
||||||
|
|
||||||
class GoogleDocstring(object):
|
class GoogleDocstring(object):
|
||||||
@ -213,12 +214,22 @@ class GoogleDocstring(object):
|
|||||||
|
|
||||||
def _consume_field(self, parse_type=True, prefer_type=False):
|
def _consume_field(self, parse_type=True, prefer_type=False):
|
||||||
line = self._line_iter.next()
|
line = self._line_iter.next()
|
||||||
_name, _, _desc = line.partition(':')
|
|
||||||
_name, _type, _desc = _name.strip(), '', _desc.strip()
|
match = None
|
||||||
match = _field_parens_regex.match(_name)
|
_name, _type, _desc = line.strip(), '', ''
|
||||||
if parse_type and match:
|
if parse_type:
|
||||||
_name = match.group(1)
|
match = _google_typed_arg_regex.match(line)
|
||||||
_type = match.group(2)
|
if match:
|
||||||
|
_name = match.group(1)
|
||||||
|
_type = match.group(2)
|
||||||
|
_desc = match.group(3)
|
||||||
|
|
||||||
|
if not match:
|
||||||
|
match = _google_untyped_arg_regex.match(line)
|
||||||
|
if match:
|
||||||
|
_name = match.group(1)
|
||||||
|
_desc = match.group(2)
|
||||||
|
|
||||||
if prefer_type and not _type:
|
if prefer_type and not _type:
|
||||||
_type, _name = _name, _type
|
_type, _name = _name, _type
|
||||||
indent = self._get_indent(line) + 1
|
indent = self._get_indent(line) + 1
|
||||||
@ -238,17 +249,21 @@ class GoogleDocstring(object):
|
|||||||
def _consume_returns_section(self):
|
def _consume_returns_section(self):
|
||||||
lines = self._dedent(self._consume_to_next_section())
|
lines = self._dedent(self._consume_to_next_section())
|
||||||
if lines:
|
if lines:
|
||||||
if ':' in lines[0]:
|
_name, _type, _desc = '', '', lines
|
||||||
_type, _, _desc = lines[0].partition(':')
|
match = _google_typed_arg_regex.match(lines[0])
|
||||||
_name, _type, _desc = '', _type.strip(), _desc.strip()
|
if match:
|
||||||
match = _field_parens_regex.match(_type)
|
_name = match.group(1)
|
||||||
|
_type = match.group(2)
|
||||||
|
_desc = match.group(3)
|
||||||
|
else:
|
||||||
|
match = _google_untyped_arg_regex.match(lines[0])
|
||||||
if match:
|
if match:
|
||||||
_name = match.group(1)
|
_type = match.group(1)
|
||||||
_type = match.group(2)
|
_desc = match.group(2)
|
||||||
|
if match:
|
||||||
lines[0] = _desc
|
lines[0] = _desc
|
||||||
_desc = lines
|
_desc = lines
|
||||||
else:
|
|
||||||
_name, _type, _desc = '', '', lines
|
|
||||||
_desc = self.__class__(_desc, self._config).lines()
|
_desc = self.__class__(_desc, self._config).lines()
|
||||||
return [(_name, _type, _desc,)]
|
return [(_name, _type, _desc,)]
|
||||||
else:
|
else:
|
||||||
|
@ -146,6 +146,19 @@ class GoogleDocstringTest(BaseDocstringTest):
|
|||||||
:returns: *str* --
|
:returns: *str* --
|
||||||
Extended
|
Extended
|
||||||
description of return value"""
|
description of return value"""
|
||||||
|
), (
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Extended
|
||||||
|
description of return value
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
:returns: Extended
|
||||||
|
description of return value"""
|
||||||
)]
|
)]
|
||||||
|
|
||||||
def test_docstrings(self):
|
def test_docstrings(self):
|
||||||
@ -155,6 +168,43 @@ class GoogleDocstringTest(BaseDocstringTest):
|
|||||||
expected = textwrap.dedent(expected)
|
expected = textwrap.dedent(expected)
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
def test_parameters_with_class_reference(self):
|
||||||
|
docstring = """\
|
||||||
|
Construct a new XBlock.
|
||||||
|
|
||||||
|
This class should only be used by runtimes.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
runtime (:class:`Runtime`): Use it to access the environment.
|
||||||
|
It is available in XBlock code as ``self.runtime``.
|
||||||
|
|
||||||
|
field_data (:class:`FieldData`): Interface used by the XBlock
|
||||||
|
fields to access their data from wherever it is persisted.
|
||||||
|
|
||||||
|
scope_ids (:class:`ScopeIds`): Identifiers needed to resolve scopes.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
actual = str(GoogleDocstring(docstring))
|
||||||
|
expected = """\
|
||||||
|
Construct a new XBlock.
|
||||||
|
|
||||||
|
This class should only be used by runtimes.
|
||||||
|
|
||||||
|
:param runtime: Use it to access the environment.
|
||||||
|
It is available in XBlock code as ``self.runtime``.
|
||||||
|
|
||||||
|
:type runtime: :class:`Runtime`
|
||||||
|
:param field_data: Interface used by the XBlock
|
||||||
|
fields to access their data from wherever it is persisted.
|
||||||
|
|
||||||
|
:type field_data: :class:`FieldData`
|
||||||
|
:param scope_ids: Identifiers needed to resolve scopes.
|
||||||
|
|
||||||
|
:type scope_ids: :class:`ScopeIds`
|
||||||
|
"""
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
|
||||||
class NumpyDocstringTest(BaseDocstringTest):
|
class NumpyDocstringTest(BaseDocstringTest):
|
||||||
docstrings = [(
|
docstrings = [(
|
||||||
@ -268,95 +318,98 @@ class NumpyDocstringTest(BaseDocstringTest):
|
|||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
def test_parameters_with_class_reference(self):
|
def test_parameters_with_class_reference(self):
|
||||||
docstring = """
|
docstring = """\
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
param1 : :class:`MyClass <name.space.MyClass>` instance
|
param1 : :class:`MyClass <name.space.MyClass>` instance
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
config = Config(napoleon_use_param=False)
|
config = Config(napoleon_use_param=False)
|
||||||
actual = str(NumpyDocstring(textwrap.dedent(docstring), config))
|
actual = str(NumpyDocstring(docstring, config))
|
||||||
expected = textwrap.dedent("""
|
expected = """\
|
||||||
:Parameters: **param1** (:class:`MyClass <name.space.MyClass>` instance)
|
:Parameters: **param1** (:class:`MyClass <name.space.MyClass>` instance)
|
||||||
""")
|
"""
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
config = Config(napoleon_use_param=True)
|
config = Config(napoleon_use_param=True)
|
||||||
actual = str(NumpyDocstring(textwrap.dedent(docstring), config))
|
actual = str(NumpyDocstring(docstring, config))
|
||||||
expected = textwrap.dedent("""
|
expected = """\
|
||||||
|
|
||||||
:type param1: :class:`MyClass <name.space.MyClass>` instance
|
:type param1: :class:`MyClass <name.space.MyClass>` instance
|
||||||
""")
|
"""
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
def test_parameters_without_class_reference(self):
|
def test_parameters_without_class_reference(self):
|
||||||
docstring = """
|
docstring = """\
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
param1 : MyClass instance
|
param1 : MyClass instance
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
config = Config(napoleon_use_param=False)
|
config = Config(napoleon_use_param=False)
|
||||||
actual = str(NumpyDocstring(textwrap.dedent(docstring), config))
|
actual = str(NumpyDocstring(docstring, config))
|
||||||
expected = textwrap.dedent("""
|
expected = """\
|
||||||
:Parameters: **param1** (*MyClass instance*)
|
:Parameters: **param1** (*MyClass instance*)
|
||||||
""")
|
"""
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
config = Config(napoleon_use_param=True)
|
config = Config(napoleon_use_param=True)
|
||||||
actual = str(NumpyDocstring(textwrap.dedent(docstring), config))
|
actual = str(NumpyDocstring(textwrap.dedent(docstring), config))
|
||||||
expected = textwrap.dedent("""
|
expected = """\
|
||||||
|
|
||||||
:type param1: MyClass instance
|
:type param1: MyClass instance
|
||||||
""")
|
"""
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
def test_see_also_refs(self):
|
def test_see_also_refs(self):
|
||||||
docstring = """
|
docstring = """\
|
||||||
numpy.multivariate_normal(mean, cov, shape=None, spam=None)
|
numpy.multivariate_normal(mean, cov, shape=None, spam=None)
|
||||||
|
|
||||||
See Also
|
See Also
|
||||||
--------
|
--------
|
||||||
some, other, funcs
|
some, other, funcs
|
||||||
otherfunc : relationship
|
otherfunc : relationship
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
actual = str(NumpyDocstring(textwrap.dedent(docstring)))
|
actual = str(NumpyDocstring(docstring))
|
||||||
|
|
||||||
expected = """
|
expected = """\
|
||||||
numpy.multivariate_normal(mean, cov, shape=None, spam=None)
|
numpy.multivariate_normal(mean, cov, shape=None, spam=None)
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
\n :obj:`some`, :obj:`other`, :obj:`funcs`
|
|
||||||
\n :obj:`otherfunc`
|
:obj:`some`, :obj:`other`, :obj:`funcs`
|
||||||
|
\n\
|
||||||
|
:obj:`otherfunc`
|
||||||
relationship
|
relationship
|
||||||
"""
|
"""
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
docstring = """
|
docstring = """\
|
||||||
numpy.multivariate_normal(mean, cov, shape=None, spam=None)
|
numpy.multivariate_normal(mean, cov, shape=None, spam=None)
|
||||||
|
|
||||||
See Also
|
See Also
|
||||||
--------
|
--------
|
||||||
some, other, funcs
|
some, other, funcs
|
||||||
otherfunc : relationship
|
otherfunc : relationship
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
config = Config()
|
config = Config()
|
||||||
app = Mock()
|
app = Mock()
|
||||||
actual = str(NumpyDocstring(textwrap.dedent(docstring),
|
actual = str(NumpyDocstring(docstring, config, app, "method"))
|
||||||
config, app, "method"))
|
|
||||||
|
|
||||||
expected = """
|
expected = """\
|
||||||
numpy.multivariate_normal(mean, cov, shape=None, spam=None)
|
numpy.multivariate_normal(mean, cov, shape=None, spam=None)
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
\n :meth:`some`, :meth:`other`, :meth:`funcs`
|
|
||||||
\n :meth:`otherfunc`
|
:meth:`some`, :meth:`other`, :meth:`funcs`
|
||||||
|
\n\
|
||||||
|
:meth:`otherfunc`
|
||||||
relationship
|
relationship
|
||||||
"""
|
"""
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
|
Loading…
Reference in New Issue
Block a user