Closed #1925: [Napoleon] provides @property examples & recommends PEP 484 type hints in Napoleon docs

This commit is contained in:
Rob Ruana
2015-06-09 18:18:22 -07:00
parent 20cba249ef
commit 34add11b5d
5 changed files with 206 additions and 85 deletions

View File

@@ -12,11 +12,11 @@ Example:
$ python example_google.py
Section breaks are created by simply resuming unindented text. Section breaks
Section breaks are created by resuming unindented text. Section breaks
are also implicitly created anytime a new section starts.
Attributes:
module_level_variable (int): Module level variables may be documented in
module_level_variable1 (int): Module level variables may be documented in
either the ``Attributes`` section of the module docstring, or in an
inline docstring immediately following the variable.
@@ -25,11 +25,18 @@ Attributes:
with it.
.. _Google Python Style Guide:
http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
http://google.github.io/styleguide/pyguide.html
"""
module_level_variable = 12345
module_level_variable1 = 12345
module_level_variable2 = 98765
"""int: Module level variable documented inline.
The docstring may span multiple lines. The type may optionally be specified
on the first line, separated by a colon.
"""
def module_level_function(param1, param2=None, *args, **kwargs):
@@ -39,22 +46,24 @@ def module_level_function(param1, param2=None, *args, **kwargs):
of each parameter is required. The type and description of each parameter
is optional, but should be included if not obvious.
If the parameter itself is optional, it should be noted by adding
", optional" to the type. If \*args or \*\*kwargs are accepted, they
should be listed as \*args and \*\*kwargs.
Parameter types -- if given -- should be specified according to
`PEP 484`_, though `PEP 484`_ conformance isn't required or enforced.
If \*args or \*\*kwargs are accepted,
they should be listed as \*args and \*\*kwargs.
The format for a parameter is::
name (type): description
The description may span multiple lines. Following
lines should be indented.
lines should be indented. The "(type)" is optional.
Multiple paragraphs are supported in parameter
descriptions.
Args:
param1 (int): The first parameter.
param2 (str, optional): The second parameter. Defaults to None.
param2 (Optional[str]): The second parameter. Defaults to None.
Second line of description should be indented.
*args: Variable length argument list.
**kwargs: Arbitrary keyword arguments.
@@ -81,6 +90,10 @@ def module_level_function(param1, param2=None, *args, **kwargs):
that are relevant to the interface.
ValueError: If `param2` is equal to `param1`.
.. _PEP 484:
https://www.python.org/dev/peps/pep-0484/
"""
if param1 == param2:
raise ValueError('param1 may not be equal to param2')
@@ -122,14 +135,14 @@ class ExampleError(Exception):
Args:
msg (str): Human readable string describing the exception.
code (int, optional): Error code, defaults to 2.
code (Optional[int]): Error code.
Attributes:
msg (str): Human readable string describing the exception.
code (int): Exception error code.
"""
def __init__(self, msg, code=2):
def __init__(self, msg, code):
self.msg = msg
self.code = code
@@ -137,17 +150,27 @@ class ExampleError(Exception):
class ExampleClass(object):
"""The summary line for a class docstring should fit on one line.
If the class has public attributes, they should be documented here
If the class has public attributes, they may be documented here
in an ``Attributes`` section and follow the same formatting as a
function's ``Args`` section.
function's ``Args`` section. Alternatively, attributes may be documented
inline with the attribute's declaration (see __init__ method below).
Properties created with the ``@property`` decorator should be documented
in the property's getter method.
Attribute and property types -- if given -- should be specified according
to `PEP 484`_, though `PEP 484`_ conformance isn't required or enforced.
Attributes:
attr1 (str): Description of `attr1`.
attr2 (list of str): Description of `attr2`.
attr3 (int): Description of `attr3`.
attr2 (Optional[int]): Description of `attr2`.
.. _PEP 484:
https://www.python.org/dev/peps/pep-0484/
"""
def __init__(self, param1, param2, param3=0):
def __init__(self, param1, param2, param3):
"""Example of docstring on the __init__ method.
The __init__ method may be documented in either the class level
@@ -161,14 +184,39 @@ class ExampleClass(object):
Args:
param1 (str): Description of `param1`.
param2 (list of str): Description of `param2`. Multiple
param2 (Optional[int]): Description of `param2`. Multiple
lines are supported.
param3 (int, optional): Description of `param3`, defaults to 0.
param3 (List[str]): Description of `param3`.
"""
self.attr1 = param1
self.attr2 = param2
self.attr3 = param3
self.attr3 = param3 #: Doc comment *inline* with attribute
#: List[str]: Doc comment *before* attribute, with type specified
self.attr4 = ["attr4"]
self.attr5 = None
"""Optional[str]: Docstring *after* attribute, with type specified"""
@property
def readonly_property(self):
"""str: Properties should be documented in their getter method"""
return "readonly_property"
@property
def readwrite_property(self):
"""List[str]: Properties with both a getter and setter should only
be documented in their getter method.
If the setter method contains notable behavior, it should be
mentioned here.
"""
return ["readwrite_property"]
@readwrite_property.setter
def readwrite_property(self, value):
value
def example_method(self, param1, param2):
"""Class methods are similar to regular functions.

View File

@@ -23,12 +23,12 @@ Notes
This is an example of an indented section. It's like any other section,
but the body is indented to help it stand out from surrounding text.
If a section is indented, then a section break is created simply by
If a section is indented, then a section break is created by
resuming unindented text.
Attributes
----------
module_level_variable : int
module_level_variable1 : int
Module level variables may be documented in either the ``Attributes``
section of the module docstring, or in an inline docstring immediately
following the variable.
@@ -42,7 +42,14 @@ module_level_variable : int
"""
module_level_variable = 12345
module_level_variable1 = 12345
module_level_variable2 = 98765
"""int: Module level variable documented inline.
The docstring may span multiple lines. The type may optionally be specified
on the first line, separated by a colon.
"""
def module_level_function(param1, param2=None, *args, **kwargs):
@@ -52,8 +59,10 @@ def module_level_function(param1, param2=None, *args, **kwargs):
The name of each parameter is required. The type and description of each
parameter is optional, but should be included if not obvious.
If the parameter itself is optional, it should be noted by adding
", optional" to the type. If \*args or \*\*kwargs are accepted, they
Parameter types -- if given -- should be specified according to
`PEP 484`_, though `PEP 484`_ conformance isn't required or enforced.
If \*args or \*\*kwargs are accepted, they
should be listed as \*args and \*\*kwargs.
The format for a parameter is::
@@ -63,6 +72,7 @@ def module_level_function(param1, param2=None, *args, **kwargs):
The description may span multiple lines. Following lines
should be indented to match the first line of the description.
The ": type" is optional.
Multiple paragraphs are supported in parameter
descriptions.
@@ -71,8 +81,8 @@ def module_level_function(param1, param2=None, *args, **kwargs):
----------
param1 : int
The first parameter.
param2 : str, optional
The second parameter, defaults to None.
param2 : Optional[str]
The second parameter.
*args
Variable length argument list.
**kwargs
@@ -103,6 +113,10 @@ def module_level_function(param1, param2=None, *args, **kwargs):
ValueError
If `param2` is equal to `param1`.
.. _PEP 484:
https://www.python.org/dev/peps/pep-0484/
"""
if param1 == param2:
raise ValueError('param1 may not be equal to param2')
@@ -152,18 +166,18 @@ class ExampleError(Exception):
----------
msg : str
Human readable string describing the exception.
code : int, optional
Error code, defaults to 2.
code : Optional[int]
Numeric error code.
Attributes
----------
msg : str
Human readable string describing the exception.
code : int
Exception error code.
Numeric error code.
"""
def __init__(self, msg, code=2):
def __init__(self, msg, code):
self.msg = msg
self.code = code
@@ -171,21 +185,30 @@ class ExampleError(Exception):
class ExampleClass(object):
"""The summary line for a class docstring should fit on one line.
If the class has public attributes, they should be documented here
If the class has public attributes, they may be documented here
in an ``Attributes`` section and follow the same formatting as a
function's ``Parameters`` section.
function's ``Args`` section. Alternatively, attributes may be documented
inline with the attribute's declaration (see __init__ method below).
Properties created with the ``@property`` decorator should be documented
in the property's getter method.
Attribute and property types -- if given -- should be specified according
to `PEP 484`_, though `PEP 484`_ conformance isn't required or enforced.
Attributes
----------
attr1 : str
Description of `attr1`.
attr2 : list of str
attr2 : Optional[int]
Description of `attr2`.
attr3 : int
Description of `attr3`.
.. _PEP 484:
https://www.python.org/dev/peps/pep-0484/
"""
def __init__(self, param1, param2, param3=0):
def __init__(self, param1, param2, param3):
"""Example of docstring on the __init__ method.
The __init__ method may be documented in either the class level
@@ -202,16 +225,41 @@ class ExampleClass(object):
----------
param1 : str
Description of `param1`.
param2 : list of str
param2 : List[str]
Description of `param2`. Multiple
lines are supported.
param3 : int, optional
Description of `param3`, defaults to 0.
param3 : Optional[int]
Description of `param3`.
"""
self.attr1 = param1
self.attr2 = param2
self.attr3 = param3
self.attr3 = param3 #: Doc comment *inline* with attribute
#: List[str]: Doc comment *before* attribute, with type specified
self.attr4 = ["attr4"]
self.attr5 = None
"""Optional[str]: Docstring *after* attribute, with type specified"""
@property
def readonly_property(self):
"""str: Properties should be documented in their getter method"""
return "readonly_property"
@property
def readwrite_property(self):
"""List[str]: Properties with both a getter and setter should only
be documented in their getter method.
If the setter method contains notable behavior, it should be
mentioned here.
"""
return ["readwrite_property"]
@readwrite_property.setter
def readwrite_property(self, value):
value
def example_method(self, param1, param2):
"""Class methods are similar to regular functions.

View File

@@ -50,9 +50,9 @@ source code files.
.. _ReStructuredText: http://docutils.sourceforge.net/rst.html
.. _docstrings: http://www.python.org/dev/peps/pep-0287/
.. _Google Python Style Guide:
http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
http://google.github.io/styleguide/pyguide.html
.. _Google:
http://google-styleguide.googlecode.com/svn/trunk/pyguide.html#Comments
http://google.github.io/styleguide/pyguide.html#Comments
.. _NumPy:
https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
.. _Khan Academy:
@@ -113,6 +113,7 @@ All of the following section headers are supported:
* ``Warning``
* ``Warnings`` *(alias of Warning)*
* ``Warns``
* ``Yield`` *(alias of Yields)*
* ``Yields``
Google vs NumPy
@@ -178,6 +179,11 @@ not be mixed. Choose one style for your project and be consistent with it.
* :ref:`example_google`
* :ref:`example_numpy`
For Python type annotations, see `PEP 484`_.
.. _PEP 484:
https://www.python.org/dev/peps/pep-0484/
Configuration
=============

View File

@@ -28,16 +28,14 @@ _xref_regex = re.compile(r'(:\w+:\S+:`.+?`|:\S+:`.+?`|`.+?`)')
class GoogleDocstring(UnicodeMixin):
"""Parse Google style docstrings.
Convert Google style docstrings to reStructuredText.
"""Convert Google style docstrings to reStructuredText.
Parameters
----------
docstring : str or list of str
docstring : str or List[str]
The docstring to parse, given either as a string or split into
individual lines.
config : sphinx.ext.napoleon.Config or sphinx.config.Config, optional
config : Optional[sphinx.ext.napoleon.Config or sphinx.config.Config]
The configuration settings to use. If not given, defaults to the
config object on `app`; or if `app` is not given defaults to the
a new `sphinx.ext.napoleon.Config` object.
@@ -48,17 +46,17 @@ class GoogleDocstring(UnicodeMixin):
Other Parameters
----------------
app : sphinx.application.Sphinx, optional
app : Optional[sphinx.application.Sphinx]
Application object representing the Sphinx process.
what : str, optional
what : Optional[str]
A string specifying the type of the object to which the docstring
belongs. Valid values: "module", "class", "exception", "function",
"method", "attribute".
name : str, optional
name : Optional[str]
The fully qualified name of the object.
obj : module, class, exception, function, method, or attribute
The object to which the docstring belongs.
options : sphinx.ext.autodoc.Options, optional
options : Optional[sphinx.ext.autodoc.Options]
The options given to the directive: an object with attributes
inherited_members, undoc_members, show_inheritance and noindex that
are True if the flag option of same name was given to the auto
@@ -168,7 +166,7 @@ class GoogleDocstring(UnicodeMixin):
Returns
-------
list of str
List[str]
The lines of the docstring in a list.
"""
@@ -232,6 +230,15 @@ class GoogleDocstring(UnicodeMixin):
fields.append((_name, _type, _desc,))
return fields
def _consume_inline_attribute(self):
line = next(self._line_iter)
_type, colon, _desc = self._partition_field_on_colon(line)
if not colon:
_type, _desc = _desc, _type
_desc = [_desc] + self._dedent(self._consume_to_end())
_desc = self.__class__(_desc, self._config).lines()
return _type, _desc
def _consume_returns_section(self):
lines = self._dedent(self._consume_to_next_section())
if lines:
@@ -267,6 +274,12 @@ class GoogleDocstring(UnicodeMixin):
section = stripped_section
return section
def _consume_to_end(self):
lines = []
while self._line_iter.has_next():
lines.append(next(self._line_iter))
return lines
def _consume_to_next_section(self):
self._consume_empty()
lines = []
@@ -308,7 +321,7 @@ class GoogleDocstring(UnicodeMixin):
return [prefix]
def _format_field(self, _name, _type, _desc):
separator = any([s for s in _desc]) and ' --' or ''
separator = (_desc and _desc[0]) and ' --' or ''
if _name:
if _type:
if '`' in _type:
@@ -402,6 +415,11 @@ class GoogleDocstring(UnicodeMixin):
def _parse(self):
self._parsed_lines = self._consume_empty()
if self._name and (self._what == 'attribute' or self._what == 'data'):
self._parsed_lines.extend(self._parse_attribute_docstring())
return
while self._line_iter.has_next():
if self._is_section_header():
try:
@@ -422,6 +440,10 @@ class GoogleDocstring(UnicodeMixin):
lines = self._consume_to_next_section()
self._parsed_lines.extend(lines)
def _parse_attribute_docstring(self):
_type, _desc = self._consume_inline_attribute()
return self._format_field('', _type, _desc)
def _parse_attributes_section(self, section):
lines = []
for _name, _type, _desc in self._consume_fields():
@@ -431,15 +453,9 @@ class GoogleDocstring(UnicodeMixin):
if _type:
lines.append(':vartype %s: %s' % (_name, _type))
else:
lines.append('.. attribute:: ' + _name)
if _type:
lines.append('')
if '`' in _type:
lines.append(' %s' % _type)
else:
lines.append(' *%s*' % _type)
if _desc:
lines.extend([''] + self._indent(_desc, 3))
lines.extend(['.. attribute:: ' + _name, ''])
field = self._format_field('', _type, _desc)
lines.extend(self._indent(field, 3))
lines.append('')
if self._config.napoleon_use_ivar:
lines.append('')
@@ -630,16 +646,14 @@ class GoogleDocstring(UnicodeMixin):
class NumpyDocstring(GoogleDocstring):
"""Parse NumPy style docstrings.
Convert NumPy style docstrings to reStructuredText.
"""Convert NumPy style docstrings to reStructuredText.
Parameters
----------
docstring : str or list of str
docstring : str or List[str]
The docstring to parse, given either as a string or split into
individual lines.
config : sphinx.ext.napoleon.Config or sphinx.config.Config, optional
config : Optional[sphinx.ext.napoleon.Config or sphinx.config.Config]
The configuration settings to use. If not given, defaults to the
config object on `app`; or if `app` is not given defaults to the
a new `sphinx.ext.napoleon.Config` object.
@@ -650,17 +664,17 @@ class NumpyDocstring(GoogleDocstring):
Other Parameters
----------------
app : sphinx.application.Sphinx, optional
app : Optional[sphinx.application.Sphinx]
Application object representing the Sphinx process.
what : str, optional
what : Optional[str]
A string specifying the type of the object to which the docstring
belongs. Valid values: "module", "class", "exception", "function",
"method", "attribute".
name : str, optional
name : Optional[str]
The fully qualified name of the object.
obj : module, class, exception, function, method, or attribute
The object to which the docstring belongs.
options : sphinx.ext.autodoc.Options, optional
options : Optional[sphinx.ext.autodoc.Options]
The options given to the directive: an object with attributes
inherited_members, undoc_members, show_inheritance and noindex that
are True if the flag option of same name was given to the auto
@@ -722,7 +736,7 @@ class NumpyDocstring(GoogleDocstring):
Returns
-------
list of str
List[str]
The lines of the docstring in a list.
"""

View File

@@ -31,6 +31,9 @@ class NamedtupleSubclass(namedtuple('NamedtupleSubclass', ('attr1', 'attr2'))):
Quick description of attr1
attr2 : Another arbitrary type
Quick description of attr2
attr3 : Type
Adds a newline after the type
"""
# To avoid creating a dict, as a namedtuple doesn't have it:
@@ -50,21 +53,25 @@ class NamedtupleSubclassTest(BaseDocstringTest):
actual = str(NumpyDocstring(cleandoc(NamedtupleSubclass.__doc__),
config=config, app=None, what='class',
name='NamedtupleSubclass', obj=NamedtupleSubclass))
expected = dedent("""\
Sample namedtuple subclass
expected = """\
Sample namedtuple subclass
.. attribute:: attr1
.. attribute:: attr1
*Arbitrary type*
*Arbitrary type* --
Quick description of attr1
Quick description of attr1
.. attribute:: attr2
.. attribute:: attr2
*Another arbitrary type* --
Quick description of attr2
*Another arbitrary type*
.. attribute:: attr3
Quick description of attr2
""")
*Type*
""""""
Adds a newline after the type
"""
self.assertEqual(expected, actual)
@@ -305,8 +312,7 @@ Attributes:
expected = """\
.. attribute:: in_attr
:class:`numpy.ndarray`
:class:`numpy.ndarray` --
super-dooper attribute
"""
self.assertEqual(expected, actual)
@@ -320,8 +326,7 @@ Attributes:
expected = """\
.. attribute:: in_attr
*numpy.ndarray*
*numpy.ndarray* --
super-dooper attribute
"""
self.assertEqual(expected, actual)