mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merges napoleon extension into mainline sphinx
This commit is contained in:
parent
dbd544d12b
commit
a00a096069
1
AUTHORS
1
AUTHORS
@ -32,6 +32,7 @@ Other contributors, listed alphabetically, are:
|
|||||||
* Christopher Perkins -- autosummary integration
|
* Christopher Perkins -- autosummary integration
|
||||||
* Benjamin Peterson -- unittests
|
* Benjamin Peterson -- unittests
|
||||||
* T. Powers -- HTML output improvements
|
* T. Powers -- HTML output improvements
|
||||||
|
* Rob Ruana -- napoleon extension
|
||||||
* Stefan Seefeld -- toctree improvements
|
* Stefan Seefeld -- toctree improvements
|
||||||
* Shibukawa Yoshiki -- pluggable search API and Japanese search
|
* Shibukawa Yoshiki -- pluggable search API and Japanese search
|
||||||
* Antonio Valentino -- qthelp builder
|
* Antonio Valentino -- qthelp builder
|
||||||
|
@ -5,8 +5,10 @@
|
|||||||
import re
|
import re
|
||||||
import sphinx
|
import sphinx
|
||||||
|
|
||||||
|
|
||||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
|
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
|
||||||
'sphinx.ext.autosummary', 'sphinx.ext.extlinks']
|
'sphinx.ext.autosummary', 'sphinx.ext.extlinks',
|
||||||
|
'sphinx.ext.napoleon']
|
||||||
|
|
||||||
master_doc = 'contents'
|
master_doc = 'contents'
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
|
223
doc/ext/example_google.py
Normal file
223
doc/ext/example_google.py
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Example Google style docstrings.
|
||||||
|
|
||||||
|
This module demonstrates documentation as specified by the `Google Python
|
||||||
|
Style Guide`_. Docstrings may extend over multiple lines. Sections are created
|
||||||
|
with a section header and a colon followed by a block of indented text.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
Examples can be given using either the ``Example`` or ``Examples``
|
||||||
|
sections. Sections support any reStructuredText formatting, including
|
||||||
|
literal blocks::
|
||||||
|
|
||||||
|
$ python example_google.py
|
||||||
|
|
||||||
|
Section breaks are created by simply 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
|
||||||
|
either the ``Attributes`` section of the module docstring, or in an
|
||||||
|
inline docstring immediately following the variable.
|
||||||
|
|
||||||
|
Either form is acceptable, but the two should not be mixed. Choose
|
||||||
|
one convention to document module level variables and be consistent
|
||||||
|
with it.
|
||||||
|
|
||||||
|
.. _Google Python Style Guide:
|
||||||
|
http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
module_level_variable = 12345
|
||||||
|
|
||||||
|
|
||||||
|
def module_level_function(param1, param2=None, *args, **kwargs):
|
||||||
|
"""This is an example of a module level function.
|
||||||
|
|
||||||
|
Function parameters should be documented in the ``Args`` section. 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
|
||||||
|
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.
|
||||||
|
|
||||||
|
Multiple paragraphs are supported in parameter
|
||||||
|
descriptions.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
param1 (int): The first parameter.
|
||||||
|
param2 (str, optional): The second parameter. Defaults to None.
|
||||||
|
Second line of description should be indented.
|
||||||
|
*args: Variable length argument list.
|
||||||
|
**kwargs: Arbitrary keyword arguments.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if successful, False otherwise.
|
||||||
|
|
||||||
|
The return type is optional and may be specified at the beginning of
|
||||||
|
the ``Returns`` section followed by a colon.
|
||||||
|
|
||||||
|
The ``Returns`` section may span multiple lines and paragraphs.
|
||||||
|
Following lines should be indented to match the first line.
|
||||||
|
|
||||||
|
The ``Returns`` section supports any reStructuredText formatting,
|
||||||
|
including literal blocks::
|
||||||
|
|
||||||
|
{
|
||||||
|
'param1': param1,
|
||||||
|
'param2': param2
|
||||||
|
}
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
AttributeError: The ``Raises`` section is a list of all exceptions
|
||||||
|
that are relevant to the interface.
|
||||||
|
ValueError: If `param2` is equal to `param1`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if param1 == param2:
|
||||||
|
raise ValueError('param1 may not be equal to param2')
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def example_generator(n):
|
||||||
|
"""Generators have a ``Yields`` section instead of a ``Returns`` section.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
n (int): The upper limit of the range to generate, from 0 to `n` - 1
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
int: The next number in the range of 0 to `n` - 1
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
Examples should be written in doctest format, and should illustrate how
|
||||||
|
to use the function.
|
||||||
|
|
||||||
|
>>> print [i for i in example_generator(4)]
|
||||||
|
[0, 1, 2, 3]
|
||||||
|
|
||||||
|
"""
|
||||||
|
for i in range(n):
|
||||||
|
yield i
|
||||||
|
|
||||||
|
|
||||||
|
class ExampleError(Exception):
|
||||||
|
"""Exceptions are documented in the same way as classes.
|
||||||
|
|
||||||
|
The __init__ method may be documented in either the class level
|
||||||
|
docstring, or as a docstring on the __init__ method itself.
|
||||||
|
|
||||||
|
Either form is acceptable, but the two should not be mixed. Choose one
|
||||||
|
convention to document the __init__ method and be consistent with it.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Do not include the `self` parameter in the ``Args`` section.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msg (str): Human readable string describing the exception.
|
||||||
|
code (int, optional): Error code, defaults to 2.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
msg (str): Human readable string describing the exception.
|
||||||
|
code (int): Exception error code.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, msg, code=2):
|
||||||
|
self.msg = msg
|
||||||
|
self.code = code
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
in an ``Attributes`` section and follow the same formatting as a
|
||||||
|
function's ``Args`` section.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
attr1 (str): Description of `attr1`.
|
||||||
|
attr2 (list of str): Description of `attr2`.
|
||||||
|
attr3 (int): Description of `attr3`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, param1, param2, param3=0):
|
||||||
|
"""Example of docstring on the __init__ method.
|
||||||
|
|
||||||
|
The __init__ method may be documented in either the class level
|
||||||
|
docstring, or as a docstring on the __init__ method itself.
|
||||||
|
|
||||||
|
Either form is acceptable, but the two should not be mixed. Choose one
|
||||||
|
convention to document the __init__ method and be consistent with it.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Do not include the `self` parameter in the ``Args`` section.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
param1 (str): Description of `param1`.
|
||||||
|
param2 (list of str): Description of `param2`. Multiple
|
||||||
|
lines are supported.
|
||||||
|
param3 (int, optional): Description of `param3`, defaults to 0.
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.attr1 = param1
|
||||||
|
self.attr2 = param2
|
||||||
|
self.attr3 = param3
|
||||||
|
|
||||||
|
def example_method(self, param1, param2):
|
||||||
|
"""Class methods are similar to regular functions.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Do not include the `self` parameter in the ``Args`` section.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
param1: The first parameter.
|
||||||
|
param2: The second parameter.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if successful, False otherwise.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __special__(self):
|
||||||
|
"""By default special members with docstrings are included.
|
||||||
|
|
||||||
|
Special members are any methods or attributes that start with and
|
||||||
|
end with a double underscore. Any special member with a docstring
|
||||||
|
will be included in the output.
|
||||||
|
|
||||||
|
This behavior can be disabled by changing the following setting in
|
||||||
|
Sphinx's conf.py::
|
||||||
|
|
||||||
|
napoleon_include_special_with_doc = False
|
||||||
|
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __special_without_docstring__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _private(self):
|
||||||
|
"""By default private members are not included.
|
||||||
|
|
||||||
|
Private members are any methods or attributes that start with an
|
||||||
|
underscore and are *not* special. By default they are not included
|
||||||
|
in the output.
|
||||||
|
|
||||||
|
This behavior can be changed such that private members *are* included
|
||||||
|
by changing the following setting in Sphinx's conf.py::
|
||||||
|
|
||||||
|
napoleon_include_private_with_doc = True
|
||||||
|
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _private_without_docstring(self):
|
||||||
|
pass
|
15
doc/ext/example_google.rst
Normal file
15
doc/ext/example_google.rst
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
:orphan:
|
||||||
|
|
||||||
|
.. _example_google:
|
||||||
|
|
||||||
|
Example Google Style Python Docstrings
|
||||||
|
======================================
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
:ref:`example_numpy`
|
||||||
|
|
||||||
|
Download: :download:`example_google.py <example_google.py>`
|
||||||
|
|
||||||
|
.. literalinclude:: example_google.py
|
||||||
|
:language: python
|
272
doc/ext/example_numpy.py
Normal file
272
doc/ext/example_numpy.py
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Example NumPy style docstrings.
|
||||||
|
|
||||||
|
This module demonstrates documentation as specified by the `NumPy
|
||||||
|
Documentation HOWTO`_. Docstrings may extend over multiple lines. Sections
|
||||||
|
are created with a section header followed by an underline of equal length.
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
Examples can be given using either the ``Example`` or ``Examples``
|
||||||
|
sections. Sections support any reStructuredText formatting, including
|
||||||
|
literal blocks::
|
||||||
|
|
||||||
|
$ python example_numpy.py
|
||||||
|
|
||||||
|
|
||||||
|
Section breaks are created with two blank lines. Section breaks are also
|
||||||
|
implicitly created anytime a new section starts. Section bodies *may* be
|
||||||
|
indented:
|
||||||
|
|
||||||
|
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
|
||||||
|
resuming unindented text.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
module_level_variable : 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.
|
||||||
|
|
||||||
|
Either form is acceptable, but the two should not be mixed. Choose
|
||||||
|
one convention to document module level variables and be consistent
|
||||||
|
with it.
|
||||||
|
|
||||||
|
.. _NumPy Documentation HOWTO:
|
||||||
|
https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
module_level_variable = 12345
|
||||||
|
|
||||||
|
|
||||||
|
def module_level_function(param1, param2=None, *args, **kwargs):
|
||||||
|
"""This is an example of a module level function.
|
||||||
|
|
||||||
|
Function parameters should be documented in the ``Parameters`` section.
|
||||||
|
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
|
||||||
|
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 to match the first line of the description.
|
||||||
|
|
||||||
|
Multiple paragraphs are supported in parameter
|
||||||
|
descriptions.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
param1 : int
|
||||||
|
The first parameter.
|
||||||
|
param2 : str, optional
|
||||||
|
The second parameter, defaults to None.
|
||||||
|
*args
|
||||||
|
Variable length argument list.
|
||||||
|
**kwargs
|
||||||
|
Arbitrary keyword arguments.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if successful, False otherwise.
|
||||||
|
|
||||||
|
The return type is not optional. The ``Returns`` section may span
|
||||||
|
multiple lines and paragraphs. Following lines should be indented to
|
||||||
|
match the first line of the description.
|
||||||
|
|
||||||
|
The ``Returns`` section supports any reStructuredText formatting,
|
||||||
|
including literal blocks::
|
||||||
|
|
||||||
|
{
|
||||||
|
'param1': param1,
|
||||||
|
'param2': param2
|
||||||
|
}
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
AttributeError
|
||||||
|
The ``Raises`` section is a list of all exceptions
|
||||||
|
that are relevant to the interface.
|
||||||
|
ValueError
|
||||||
|
If `param2` is equal to `param1`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if param1 == param2:
|
||||||
|
raise ValueError('param1 may not be equal to param2')
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def example_generator(n):
|
||||||
|
"""Generators have a ``Yields`` section instead of a ``Returns`` section.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
n : int
|
||||||
|
The upper limit of the range to generate, from 0 to `n` - 1
|
||||||
|
|
||||||
|
Yields
|
||||||
|
------
|
||||||
|
int
|
||||||
|
The next number in the range of 0 to `n` - 1
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
Examples should be written in doctest format, and should illustrate how
|
||||||
|
to use the function.
|
||||||
|
|
||||||
|
>>> print [i for i in example_generator(4)]
|
||||||
|
[0, 1, 2, 3]
|
||||||
|
|
||||||
|
"""
|
||||||
|
for i in range(n):
|
||||||
|
yield i
|
||||||
|
|
||||||
|
|
||||||
|
class ExampleError(Exception):
|
||||||
|
"""Exceptions are documented in the same way as classes.
|
||||||
|
|
||||||
|
The __init__ method may be documented in either the class level
|
||||||
|
docstring, or as a docstring on the __init__ method itself.
|
||||||
|
|
||||||
|
Either form is acceptable, but the two should not be mixed. Choose one
|
||||||
|
convention to document the __init__ method and be consistent with it.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
Do not include the `self` parameter in the ``Parameters`` section.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
msg : str
|
||||||
|
Human readable string describing the exception.
|
||||||
|
code : int, optional
|
||||||
|
Error code, defaults to 2.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
msg : str
|
||||||
|
Human readable string describing the exception.
|
||||||
|
code : int
|
||||||
|
Exception error code.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, msg, code=2):
|
||||||
|
self.msg = msg
|
||||||
|
self.code = code
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
in an ``Attributes`` section and follow the same formatting as a
|
||||||
|
function's ``Parameters`` section.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
attr1 : str
|
||||||
|
Description of `attr1`.
|
||||||
|
attr2 : list of str
|
||||||
|
Description of `attr2`.
|
||||||
|
attr3 : int
|
||||||
|
Description of `attr3`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, param1, param2, param3=0):
|
||||||
|
"""Example of docstring on the __init__ method.
|
||||||
|
|
||||||
|
The __init__ method may be documented in either the class level
|
||||||
|
docstring, or as a docstring on the __init__ method itself.
|
||||||
|
|
||||||
|
Either form is acceptable, but the two should not be mixed. Choose one
|
||||||
|
convention to document the __init__ method and be consistent with it.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
Do not include the `self` parameter in the ``Parameters`` section.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
param1 : str
|
||||||
|
Description of `param1`.
|
||||||
|
param2 : list of str
|
||||||
|
Description of `param2`. Multiple
|
||||||
|
lines are supported.
|
||||||
|
param3 : int, optional
|
||||||
|
Description of `param3`, defaults to 0.
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.attr1 = param1
|
||||||
|
self.attr2 = param2
|
||||||
|
self.attr3 = param3
|
||||||
|
|
||||||
|
def example_method(self, param1, param2):
|
||||||
|
"""Class methods are similar to regular functions.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
Do not include the `self` parameter in the ``Parameters`` section.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
param1
|
||||||
|
The first parameter.
|
||||||
|
param2
|
||||||
|
The second parameter.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if successful, False otherwise.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __special__(self):
|
||||||
|
"""By default special members with docstrings are included.
|
||||||
|
|
||||||
|
Special members are any methods or attributes that start with and
|
||||||
|
end with a double underscore. Any special member with a docstring
|
||||||
|
will be included in the output.
|
||||||
|
|
||||||
|
This behavior can be disabled by changing the following setting in
|
||||||
|
Sphinx's conf.py::
|
||||||
|
|
||||||
|
napoleon_include_special_with_doc = False
|
||||||
|
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __special_without_docstring__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _private(self):
|
||||||
|
"""By default private members are not included.
|
||||||
|
|
||||||
|
Private members are any methods or attributes that start with an
|
||||||
|
underscore and are *not* special. By default they are not included
|
||||||
|
in the output.
|
||||||
|
|
||||||
|
This behavior can be changed such that private members *are* included
|
||||||
|
by changing the following setting in Sphinx's conf.py::
|
||||||
|
|
||||||
|
napoleon_include_private_with_doc = True
|
||||||
|
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _private_without_docstring(self):
|
||||||
|
pass
|
15
doc/ext/example_numpy.rst
Normal file
15
doc/ext/example_numpy.rst
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
:orphan:
|
||||||
|
|
||||||
|
.. _example_numpy:
|
||||||
|
|
||||||
|
Example NumPy Style Python Docstrings
|
||||||
|
======================================
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
:ref:`example_google`
|
||||||
|
|
||||||
|
Download: :download:`example_numpy.py <example_numpy.py>`
|
||||||
|
|
||||||
|
.. literalinclude:: example_numpy.py
|
||||||
|
:language: python
|
365
doc/ext/napoleon.rst
Normal file
365
doc/ext/napoleon.rst
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
:mod:`sphinx.ext.napoleon` -- Support for NumPy and Google style docstrings
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. module:: sphinx.ext.napoleon
|
||||||
|
:synopsis: Support for NumPy and Google style docstrings
|
||||||
|
|
||||||
|
.. moduleauthor:: Rob Ruana
|
||||||
|
|
||||||
|
.. versionadded:: 1.3
|
||||||
|
|
||||||
|
Napoleon - *Marching toward legible docstrings*
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
Are you tired of writing docstrings that look like this::
|
||||||
|
|
||||||
|
:param path: The path of the file to wrap
|
||||||
|
:type path: str
|
||||||
|
:param field_storage: The :class:`FileStorage` instance to wrap
|
||||||
|
:type field_storage: FileStorage
|
||||||
|
:param temporary: Whether or not to delete the file when the File
|
||||||
|
instance is destructed
|
||||||
|
:type temporary: bool
|
||||||
|
:returns: A buffered writable file descriptor
|
||||||
|
:rtype: BufferedFileStorage
|
||||||
|
|
||||||
|
`ReStructuredText`_ is great, but it creates visually dense, hard to read
|
||||||
|
`docstrings`_. Compare the jumble above to the same thing rewritten
|
||||||
|
according to the `Google Python Style Guide`_::
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str): The path of the file to wrap
|
||||||
|
field_storage (FileStorage): The :class:`FileStorage` instance to wrap
|
||||||
|
temporary (bool): Whether or not to delete the file when the File
|
||||||
|
instance is destructed
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
BufferedFileStorage: A buffered writable file descriptor
|
||||||
|
|
||||||
|
Much more legible, no?
|
||||||
|
|
||||||
|
Napoleon is a `Sphinx extension`_ that allows you to write readable API
|
||||||
|
documentation in your source code. Napoleon understands both `NumPy`_ and
|
||||||
|
`Google`_ style docstrings - the style recommended by `Khan Academy`_.
|
||||||
|
|
||||||
|
.. _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
|
||||||
|
.. _Sphinx extension: http://sphinx-doc.org/extensions.html
|
||||||
|
.. _Google:
|
||||||
|
http://google-styleguide.googlecode.com/svn/trunk/pyguide.html#Comments
|
||||||
|
.. _NumPy:
|
||||||
|
https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
|
||||||
|
.. _Khan Academy:
|
||||||
|
https://sites.google.com/a/khanacademy.org/forge/for-developers/styleguide/python#TOC-Docstrings
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
---------------
|
||||||
|
|
||||||
|
1. After `setting up Sphinx`_ to build your docs, enable napoleon in the
|
||||||
|
Sphinx `conf.py` file::
|
||||||
|
|
||||||
|
# conf.py
|
||||||
|
|
||||||
|
# Add autodoc and napoleon to the extensions list
|
||||||
|
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon']
|
||||||
|
|
||||||
|
2. Use `sphinx-apidoc` to build your API documentation::
|
||||||
|
|
||||||
|
$ sphinx-apidoc -f -o docs/source projectdir
|
||||||
|
|
||||||
|
.. _setting up Sphinx: http://sphinx-doc.org/tutorial.html
|
||||||
|
|
||||||
|
Docstrings
|
||||||
|
----------
|
||||||
|
|
||||||
|
Napoleon interprets every docstring that `Sphinx autodoc`_ can find,
|
||||||
|
including docstrings on: ``modules``, ``classes``, ``attributes``,
|
||||||
|
``methods``, ``functions``, and ``variables``. Inside each docstring,
|
||||||
|
specially formatted `Sections`_ are parsed and converted to
|
||||||
|
reStructuredText.
|
||||||
|
|
||||||
|
All standard reStructuredText formatting still works as expected.
|
||||||
|
|
||||||
|
.. _Sphinx autodoc: http://sphinx-doc.org/ext/autodoc.html
|
||||||
|
|
||||||
|
|
||||||
|
.. _Sections:
|
||||||
|
|
||||||
|
Docstring Sections
|
||||||
|
------------------
|
||||||
|
|
||||||
|
All of the following section headers are supported:
|
||||||
|
|
||||||
|
* ``Args`` *(alias of Parameters)*
|
||||||
|
* ``Arguments`` *(alias of Parameters)*
|
||||||
|
* ``Attributes``
|
||||||
|
* ``Example``
|
||||||
|
* ``Examples``
|
||||||
|
* ``Keyword Args`` *(alias of Keyword Arguments)*
|
||||||
|
* ``Keyword Arguments``
|
||||||
|
* ``Methods``
|
||||||
|
* ``Note``
|
||||||
|
* ``Notes``
|
||||||
|
* ``Other Parameters``
|
||||||
|
* ``Parameters``
|
||||||
|
* ``Return`` *(alias of Returns)*
|
||||||
|
* ``Returns``
|
||||||
|
* ``Raises``
|
||||||
|
* ``References``
|
||||||
|
* ``See Also``
|
||||||
|
* ``Warning``
|
||||||
|
* ``Warnings`` *(alias of Warning)*
|
||||||
|
* ``Warns``
|
||||||
|
* ``Yields``
|
||||||
|
|
||||||
|
Google vs NumPy
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Napoleon supports two styles of docstrings: `Google`_ and `NumPy`_. The
|
||||||
|
main difference between the two styles is that Google uses indention to
|
||||||
|
separate sections, whereas NumPy uses underlines.
|
||||||
|
|
||||||
|
Google style::
|
||||||
|
|
||||||
|
def func(arg1, arg2):
|
||||||
|
"""Summary line.
|
||||||
|
|
||||||
|
Extended description of function.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
arg1 (int): Description of arg1
|
||||||
|
arg2 (str): Description of arg2
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: Description of return value
|
||||||
|
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
NumPy style::
|
||||||
|
|
||||||
|
def func(arg1, arg2):
|
||||||
|
"""Summary line.
|
||||||
|
|
||||||
|
Extended description of function.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
arg1 : int
|
||||||
|
Description of arg1
|
||||||
|
arg2 : str
|
||||||
|
Description of arg2
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
Description of return value
|
||||||
|
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
NumPy style tends to require more vertical space, whereas Google style
|
||||||
|
tends to use more horizontal space. Google style tends to be easier to
|
||||||
|
read for short and simple docstrings, whereas NumPy style tends be easier
|
||||||
|
to read for long and in-depth docstrings.
|
||||||
|
|
||||||
|
The `Khan Academy`_ recommends using Google style.
|
||||||
|
|
||||||
|
The choice between styles is largely aesthetic, but the two styles should
|
||||||
|
not be mixed. Choose one style for your project and be consistent with it.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
For complete examples:
|
||||||
|
|
||||||
|
* :ref:`example_google`
|
||||||
|
* :ref:`example_numpy`
|
||||||
|
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
=============
|
||||||
|
|
||||||
|
Listed below are all the settings used by napoleon and their default
|
||||||
|
values. These settings can be changed in the Sphinx `conf.py` file. Make
|
||||||
|
sure that both "sphinx.ext.autodoc" and "sphinx.ext.napoleon" are
|
||||||
|
enabled in `conf.py`::
|
||||||
|
|
||||||
|
# conf.py
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings
|
||||||
|
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon']
|
||||||
|
|
||||||
|
# Napoleon settings
|
||||||
|
napoleon_google_docstring = True
|
||||||
|
napoleon_numpy_docstring = True
|
||||||
|
napoleon_include_private_with_doc = False
|
||||||
|
napoleon_include_special_with_doc = True
|
||||||
|
napoleon_use_admonition_for_examples = False
|
||||||
|
napoleon_use_admonition_for_notes = False
|
||||||
|
napoleon_use_admonition_for_references = False
|
||||||
|
napoleon_use_ivar = False
|
||||||
|
napoleon_use_param = False
|
||||||
|
napoleon_use_rtype = False
|
||||||
|
|
||||||
|
.. _Google style:
|
||||||
|
http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
|
||||||
|
.. _NumPy style:
|
||||||
|
https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**napoleon_google_docstring** : bool, defaults to True
|
||||||
|
True to parse `Google style`_ docstrings. False to disable support
|
||||||
|
for Google style docstrings.
|
||||||
|
|
||||||
|
**napoleon_numpy_docstring** : bool, defaults to True
|
||||||
|
True to parse `NumPy style`_ docstrings. False to disable support
|
||||||
|
for NumPy style docstrings.
|
||||||
|
|
||||||
|
**napoleon_include_private_with_doc** : bool, defaults to False
|
||||||
|
True to include private members (like ``_membername``) with docstrings
|
||||||
|
in the documentation. False to fall back to Sphinx's default behavior.
|
||||||
|
|
||||||
|
**If True**::
|
||||||
|
|
||||||
|
def _included(self):
|
||||||
|
"""
|
||||||
|
This will be included in the docs because it has a docstring
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _skipped(self):
|
||||||
|
# This will NOT be included in the docs
|
||||||
|
pass
|
||||||
|
|
||||||
|
**napoleon_include_special_with_doc** : bool, defaults to True
|
||||||
|
True to include special members (like ``__membername__``) with
|
||||||
|
docstrings in the documentation. False to fall back to Sphinx's
|
||||||
|
default behavior.
|
||||||
|
|
||||||
|
**If True**::
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""
|
||||||
|
This will be included in the docs because it has a docstring
|
||||||
|
"""
|
||||||
|
return unicode(self).encode('utf-8')
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
# This will NOT be included in the docs
|
||||||
|
return unicode(self.__class__.__name__)
|
||||||
|
|
||||||
|
**napoleon_use_admonition_for_examples** : bool, defaults to False
|
||||||
|
True to use the ``.. admonition::`` directive for the **Example** and
|
||||||
|
**Examples** sections. False to use the ``.. rubric::`` directive
|
||||||
|
instead. One may look better than the other depending on what HTML
|
||||||
|
theme is used.
|
||||||
|
|
||||||
|
This `NumPy style`_ snippet will be converted as follows::
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
This is just a quick example
|
||||||
|
|
||||||
|
**If True**::
|
||||||
|
|
||||||
|
.. admonition:: Example
|
||||||
|
|
||||||
|
This is just a quick example
|
||||||
|
|
||||||
|
**If False**::
|
||||||
|
|
||||||
|
.. rubric:: Example
|
||||||
|
|
||||||
|
This is just a quick example
|
||||||
|
|
||||||
|
**napoleon_use_admonition_for_notes** : bool, defaults to False
|
||||||
|
True to use the ``.. admonition::`` directive for **Notes** sections.
|
||||||
|
False to use the ``.. rubric::`` directive instead.
|
||||||
|
|
||||||
|
.. note:: The singular **Note** section will always be converted to a
|
||||||
|
``.. note::`` directive.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
:attr:`napoleon_use_admonition_for_examples`
|
||||||
|
|
||||||
|
**napoleon_use_admonition_for_references** : bool, defaults to False
|
||||||
|
True to use the ``.. admonition::`` directive for **References**
|
||||||
|
sections. False to use the ``.. rubric::`` directive instead.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
:attr:`napoleon_use_admonition_for_examples`
|
||||||
|
|
||||||
|
**napoleon_use_ivar** : bool, defaults to False
|
||||||
|
True to use the ``:ivar:`` role for instance variables. False to use
|
||||||
|
the ``.. attribute::`` directive instead.
|
||||||
|
|
||||||
|
This `NumPy style`_ snippet will be converted as follows::
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
attr1 : int
|
||||||
|
Description of `attr1`
|
||||||
|
|
||||||
|
**If True**::
|
||||||
|
|
||||||
|
:ivar attr1: Description of `attr1`
|
||||||
|
:vartype attr1: int
|
||||||
|
|
||||||
|
**If False**::
|
||||||
|
|
||||||
|
.. attribute:: attr1
|
||||||
|
:annotation: int
|
||||||
|
|
||||||
|
Description of `attr1`
|
||||||
|
|
||||||
|
**napoleon_use_param** : bool, defaults to False
|
||||||
|
True to use a ``:param:`` role for each function parameter. False to
|
||||||
|
use a single ``:parameters:`` role for all the parameters.
|
||||||
|
|
||||||
|
This `NumPy style`_ snippet will be converted as follows::
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
arg1 : str
|
||||||
|
Description of `arg1`
|
||||||
|
arg2 : int, optional
|
||||||
|
Description of `arg2`, defaults to 0
|
||||||
|
|
||||||
|
**If True**::
|
||||||
|
|
||||||
|
:param arg1: Description of `arg1`
|
||||||
|
:type arg1: str
|
||||||
|
:param arg2: Description of `arg2`, defaults to 0
|
||||||
|
:type arg2: int, optional
|
||||||
|
|
||||||
|
**If False**::
|
||||||
|
|
||||||
|
:parameters: * **arg1** (*str*) --
|
||||||
|
Description of `arg1`
|
||||||
|
* **arg2** (*int, optional*) --
|
||||||
|
Description of `arg2`, defaults to 0
|
||||||
|
|
||||||
|
**napoleon_use_rtype** : bool, defaults to False
|
||||||
|
True to use the ``:rtype:`` role for the return type. False to output
|
||||||
|
the return type inline with the description.
|
||||||
|
|
||||||
|
This `NumPy style`_ snippet will be converted as follows::
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if successful, False otherwise
|
||||||
|
|
||||||
|
**If True**::
|
||||||
|
|
||||||
|
:returns: True if successful, False otherwise
|
||||||
|
:rtype: bool
|
||||||
|
|
||||||
|
**If False**::
|
||||||
|
|
||||||
|
:returns: *bool* -- True if successful, False otherwise
|
@ -54,6 +54,7 @@ These extensions are built in and can be activated by respective entries in the
|
|||||||
ext/viewcode
|
ext/viewcode
|
||||||
ext/linkcode
|
ext/linkcode
|
||||||
ext/oldcmarkup
|
ext/oldcmarkup
|
||||||
|
ext/napoleon
|
||||||
|
|
||||||
|
|
||||||
Third-party extensions
|
Third-party extensions
|
||||||
|
371
sphinx/ext/napoleon/__init__.py
Normal file
371
sphinx/ext/napoleon/__init__.py
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
sphinx.ext.napoleon
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Support for NumPy and Google style docstrings.
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring
|
||||||
|
|
||||||
|
|
||||||
|
class Config(object):
|
||||||
|
"""Sphinx napoleon extension settings in `conf.py`.
|
||||||
|
|
||||||
|
Listed below are all the settings used by napoleon and their default
|
||||||
|
values. These settings can be changed in the Sphinx `conf.py` file. Make
|
||||||
|
sure that both "sphinx.ext.autodoc" and "sphinx.ext.napoleon" are
|
||||||
|
enabled in `conf.py`::
|
||||||
|
|
||||||
|
# conf.py
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings
|
||||||
|
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon']
|
||||||
|
|
||||||
|
# Napoleon settings
|
||||||
|
napoleon_google_docstring = True
|
||||||
|
napoleon_numpy_docstring = True
|
||||||
|
napoleon_include_private_with_doc = False
|
||||||
|
napoleon_include_special_with_doc = True
|
||||||
|
napoleon_use_admonition_for_examples = False
|
||||||
|
napoleon_use_admonition_for_notes = False
|
||||||
|
napoleon_use_admonition_for_references = False
|
||||||
|
napoleon_use_ivar = False
|
||||||
|
napoleon_use_param = False
|
||||||
|
napoleon_use_rtype = False
|
||||||
|
|
||||||
|
.. _Google style:
|
||||||
|
http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
|
||||||
|
.. _NumPy style:
|
||||||
|
https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**napoleon_google_docstring** : bool, defaults to True
|
||||||
|
True to parse `Google style`_ docstrings. False to disable support
|
||||||
|
for Google style docstrings.
|
||||||
|
|
||||||
|
**napoleon_numpy_docstring** : bool, defaults to True
|
||||||
|
True to parse `NumPy style`_ docstrings. False to disable support
|
||||||
|
for NumPy style docstrings.
|
||||||
|
|
||||||
|
**napoleon_include_private_with_doc** : bool, defaults to False
|
||||||
|
True to include private members (like ``_membername``) with docstrings
|
||||||
|
in the documentation. False to fall back to Sphinx's default behavior.
|
||||||
|
|
||||||
|
**If True**::
|
||||||
|
|
||||||
|
def _included(self):
|
||||||
|
\"\"\"
|
||||||
|
This will be included in the docs because it has a docstring
|
||||||
|
\"\"\"
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _skipped(self):
|
||||||
|
# This will NOT be included in the docs
|
||||||
|
pass
|
||||||
|
|
||||||
|
**napoleon_include_special_with_doc** : bool, defaults to True
|
||||||
|
True to include special members (like ``__membername__``) with
|
||||||
|
docstrings in the documentation. False to fall back to Sphinx's
|
||||||
|
default behavior.
|
||||||
|
|
||||||
|
**If True**::
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
\"\"\"
|
||||||
|
This will be included in the docs because it has a docstring
|
||||||
|
\"\"\"
|
||||||
|
return unicode(self).encode('utf-8')
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
# This will NOT be included in the docs
|
||||||
|
return unicode(self.__class__.__name__)
|
||||||
|
|
||||||
|
**napoleon_use_admonition_for_examples** : bool, defaults to False
|
||||||
|
True to use the ``.. admonition::`` directive for the **Example** and
|
||||||
|
**Examples** sections. False to use the ``.. rubric::`` directive
|
||||||
|
instead. One may look better than the other depending on what HTML
|
||||||
|
theme is used.
|
||||||
|
|
||||||
|
This `NumPy style`_ snippet will be converted as follows::
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
This is just a quick example
|
||||||
|
|
||||||
|
**If True**::
|
||||||
|
|
||||||
|
.. admonition:: Example
|
||||||
|
|
||||||
|
This is just a quick example
|
||||||
|
|
||||||
|
**If False**::
|
||||||
|
|
||||||
|
.. rubric:: Example
|
||||||
|
|
||||||
|
This is just a quick example
|
||||||
|
|
||||||
|
**napoleon_use_admonition_for_notes** : bool, defaults to False
|
||||||
|
True to use the ``.. admonition::`` directive for **Notes** sections.
|
||||||
|
False to use the ``.. rubric::`` directive instead.
|
||||||
|
|
||||||
|
.. note:: The singular **Note** section will always be converted to a
|
||||||
|
``.. note::`` directive.
|
||||||
|
|
||||||
|
.. seealso:: :attr:`napoleon_use_admonition_for_examples`
|
||||||
|
|
||||||
|
**napoleon_use_admonition_for_references** : bool, defaults to False
|
||||||
|
True to use the ``.. admonition::`` directive for **References**
|
||||||
|
sections. False to use the ``.. rubric::`` directive instead.
|
||||||
|
|
||||||
|
.. seealso:: :attr:`napoleon_use_admonition_for_examples`
|
||||||
|
|
||||||
|
**napoleon_use_ivar** : bool, defaults to False
|
||||||
|
True to use the ``:ivar:`` role for instance variables. False to use
|
||||||
|
the ``.. attribute::`` directive instead.
|
||||||
|
|
||||||
|
This `NumPy style`_ snippet will be converted as follows::
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
attr1 : int
|
||||||
|
Description of `attr1`
|
||||||
|
|
||||||
|
**If True**::
|
||||||
|
|
||||||
|
:ivar attr1: Description of `attr1`
|
||||||
|
:vartype attr1: int
|
||||||
|
|
||||||
|
**If False**::
|
||||||
|
|
||||||
|
.. attribute:: attr1
|
||||||
|
:annotation: int
|
||||||
|
|
||||||
|
Description of `attr1`
|
||||||
|
|
||||||
|
**napoleon_use_param** : bool, defaults to False
|
||||||
|
True to use a ``:param:`` role for each function parameter. False to
|
||||||
|
use a single ``:parameters:`` role for all the parameters.
|
||||||
|
|
||||||
|
This `NumPy style`_ snippet will be converted as follows::
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
arg1 : str
|
||||||
|
Description of `arg1`
|
||||||
|
arg2 : int, optional
|
||||||
|
Description of `arg2`, defaults to 0
|
||||||
|
|
||||||
|
**If True**::
|
||||||
|
|
||||||
|
:param arg1: Description of `arg1`
|
||||||
|
:type arg1: str
|
||||||
|
:param arg2: Description of `arg2`, defaults to 0
|
||||||
|
:type arg2: int, optional
|
||||||
|
|
||||||
|
**If False**::
|
||||||
|
|
||||||
|
:parameters: * **arg1** (*str*) --
|
||||||
|
Description of `arg1`
|
||||||
|
* **arg2** (*int, optional*) --
|
||||||
|
Description of `arg2`, defaults to 0
|
||||||
|
|
||||||
|
**napoleon_use_rtype** : bool, defaults to False
|
||||||
|
True to use the ``:rtype:`` role for the return type. False to output
|
||||||
|
the return type inline with the description.
|
||||||
|
|
||||||
|
This `NumPy style`_ snippet will be converted as follows::
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if successful, False otherwise
|
||||||
|
|
||||||
|
**If True**::
|
||||||
|
|
||||||
|
:returns: True if successful, False otherwise
|
||||||
|
:rtype: bool
|
||||||
|
|
||||||
|
**If False**::
|
||||||
|
|
||||||
|
:returns: *bool* -- True if successful, False otherwise
|
||||||
|
|
||||||
|
"""
|
||||||
|
_config_values = {
|
||||||
|
'napoleon_google_docstring': (True, 'env'),
|
||||||
|
'napoleon_numpy_docstring': (True, 'env'),
|
||||||
|
'napoleon_include_private_with_doc': (False, 'env'),
|
||||||
|
'napoleon_include_special_with_doc': (True, 'env'),
|
||||||
|
'napoleon_use_admonition_for_examples': (False, 'env'),
|
||||||
|
'napoleon_use_admonition_for_notes': (False, 'env'),
|
||||||
|
'napoleon_use_admonition_for_references': (False, 'env'),
|
||||||
|
'napoleon_use_ivar': (False, 'env'),
|
||||||
|
'napoleon_use_param': (False, 'env'),
|
||||||
|
'napoleon_use_rtype': (False, 'env'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **settings):
|
||||||
|
for name, (default, rebuild) in self._config_values.iteritems():
|
||||||
|
setattr(self, name, default)
|
||||||
|
for name, value in settings.iteritems():
|
||||||
|
setattr(self, name, value)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
"""Sphinx extension setup function.
|
||||||
|
|
||||||
|
When the extension is loaded, Sphinx imports this module and executes
|
||||||
|
the ``setup()`` function, which in turn notifies Sphinx of everything
|
||||||
|
the extension offers.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
app : sphinx.application.Sphinx
|
||||||
|
Application object representing the Sphinx process
|
||||||
|
|
||||||
|
See Also
|
||||||
|
--------
|
||||||
|
The Sphinx documentation on `Extensions`_, the `Extension Tutorial`_, and
|
||||||
|
the `Extension API`_.
|
||||||
|
|
||||||
|
.. _Extensions: http://sphinx-doc.org/extensions.html
|
||||||
|
.. _Extension Tutorial: http://sphinx-doc.org/ext/tutorial.html
|
||||||
|
.. _Extension API: http://sphinx-doc.org/ext/appapi.html
|
||||||
|
|
||||||
|
"""
|
||||||
|
from sphinx.application import Sphinx
|
||||||
|
if not isinstance(app, Sphinx):
|
||||||
|
return # probably called by tests
|
||||||
|
|
||||||
|
app.connect('autodoc-process-docstring', _process_docstring)
|
||||||
|
app.connect('autodoc-skip-member', _skip_member)
|
||||||
|
|
||||||
|
for name, (default, rebuild) in Config._config_values.iteritems():
|
||||||
|
app.add_config_value(name, default, rebuild)
|
||||||
|
|
||||||
|
|
||||||
|
def _process_docstring(app, what, name, obj, options, lines):
|
||||||
|
"""Process the docstring for a given python object.
|
||||||
|
|
||||||
|
Called when autodoc has read and processed a docstring. `lines` is a list
|
||||||
|
of docstring lines that `_process_docstring` modifies in place to change
|
||||||
|
what Sphinx outputs.
|
||||||
|
|
||||||
|
The following settings in conf.py control what styles of docstrings will
|
||||||
|
be parsed:
|
||||||
|
|
||||||
|
* ``napoleon_google_docstring`` -- parse Google style docstrings
|
||||||
|
* ``napoleon_numpy_docstring`` -- parse NumPy style docstrings
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
app : sphinx.application.Sphinx
|
||||||
|
Application object representing the Sphinx process.
|
||||||
|
what : str
|
||||||
|
A string specifying the type of the object to which the docstring
|
||||||
|
belongs. Valid values: "module", "class", "exception", "function",
|
||||||
|
"method", "attribute".
|
||||||
|
name : 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
|
||||||
|
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
|
||||||
|
directive.
|
||||||
|
lines : list of str
|
||||||
|
The lines of the docstring, see above.
|
||||||
|
|
||||||
|
.. note:: `lines` is modified *in place*
|
||||||
|
|
||||||
|
"""
|
||||||
|
result_lines = lines
|
||||||
|
if app.config.napoleon_numpy_docstring:
|
||||||
|
docstring = NumpyDocstring(result_lines, app.config, app, what, name,
|
||||||
|
obj, options)
|
||||||
|
result_lines = docstring.lines()
|
||||||
|
if app.config.napoleon_google_docstring:
|
||||||
|
docstring = GoogleDocstring(result_lines, app.config, app, what, name,
|
||||||
|
obj, options)
|
||||||
|
result_lines = docstring.lines()
|
||||||
|
lines[:] = result_lines[:]
|
||||||
|
|
||||||
|
|
||||||
|
def _skip_member(app, what, name, obj, skip, options):
|
||||||
|
"""Determine if private and special class members are included in docs.
|
||||||
|
|
||||||
|
The following settings in conf.py determine if private and special class
|
||||||
|
members are included in the generated documentation:
|
||||||
|
|
||||||
|
* ``napoleon_include_private_with_doc`` --
|
||||||
|
include private members if they have docstrings
|
||||||
|
* ``napoleon_include_special_with_doc`` --
|
||||||
|
include special members if they have docstrings
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
app : sphinx.application.Sphinx
|
||||||
|
Application object representing the Sphinx process
|
||||||
|
what : str
|
||||||
|
A string specifying the type of the object to which the member
|
||||||
|
belongs. Valid values: "module", "class", "exception", "function",
|
||||||
|
"method", "attribute".
|
||||||
|
name : str
|
||||||
|
The name of the member.
|
||||||
|
obj : module, class, exception, function, method, or attribute.
|
||||||
|
For example, if the member is the __init__ method of class A, then
|
||||||
|
`obj` will be `A.__init__`.
|
||||||
|
skip : bool
|
||||||
|
A boolean indicating if autodoc will skip this member if `_skip_member`
|
||||||
|
does not override the decision
|
||||||
|
options : 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
|
||||||
|
directive.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if the member should be skipped during creation of the docs,
|
||||||
|
False if it should be included in the docs.
|
||||||
|
|
||||||
|
"""
|
||||||
|
has_doc = getattr(obj, '__doc__', False)
|
||||||
|
is_member = (what == 'class' or what == 'exception' or what == 'module')
|
||||||
|
if name != '__weakref__' and name != '__init__' and has_doc and is_member:
|
||||||
|
if what == 'class' or what == 'exception':
|
||||||
|
if sys.version_info[0] < 3:
|
||||||
|
cls = getattr(obj, 'im_class', getattr(obj, '__objclass__',
|
||||||
|
None))
|
||||||
|
cls_is_owner = (cls and hasattr(cls, name) and
|
||||||
|
name in cls.__dict__)
|
||||||
|
elif sys.version_info[1] >= 3 and hasattr(obj, '__qualname__'):
|
||||||
|
cls_path, _, _ = obj.__qualname__.rpartition('.')
|
||||||
|
if cls_path:
|
||||||
|
import importlib
|
||||||
|
import functools
|
||||||
|
|
||||||
|
mod = importlib.import_module(obj.__module__)
|
||||||
|
cls = functools.reduce(getattr, cls_path.split('.'), mod)
|
||||||
|
cls_is_owner = (cls and hasattr(cls, name) and
|
||||||
|
name in cls.__dict__)
|
||||||
|
else:
|
||||||
|
cls_is_owner = False
|
||||||
|
else:
|
||||||
|
cls_is_owner = True
|
||||||
|
|
||||||
|
if what == 'module' or cls_is_owner:
|
||||||
|
is_special = name.startswith('__') and name.endswith('__')
|
||||||
|
is_private = not is_special and name.startswith('_')
|
||||||
|
inc_special = app.config.napoleon_include_special_with_doc
|
||||||
|
inc_private = app.config.napoleon_include_private_with_doc
|
||||||
|
if (is_special and inc_special) or (is_private and inc_private):
|
||||||
|
return False
|
||||||
|
return skip
|
714
sphinx/ext/napoleon/docstring.py
Normal file
714
sphinx/ext/napoleon/docstring.py
Normal file
@ -0,0 +1,714 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
sphinx.ext.napoleon.docstring
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
Classes for docstring parsing and formatting.
|
||||||
|
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from sphinx.ext.napoleon.iterators import modify_iter
|
||||||
|
|
||||||
|
|
||||||
|
if sys.version_info[0] >= 3:
|
||||||
|
basestring = str
|
||||||
|
xrange = range
|
||||||
|
|
||||||
|
|
||||||
|
_directive_regex = re.compile(r'\.\. \S+::')
|
||||||
|
_field_parens_regex = re.compile(r'\s*(\w+)\s*\(\s*(.+?)\s*\)')
|
||||||
|
|
||||||
|
|
||||||
|
class GoogleDocstring(object):
|
||||||
|
"""Parse Google style docstrings.
|
||||||
|
|
||||||
|
Convert Google style docstrings to reStructuredText.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
docstring : str or list of 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
|
||||||
|
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.
|
||||||
|
|
||||||
|
See Also
|
||||||
|
--------
|
||||||
|
:class:`sphinx.ext.napoleon.Config`
|
||||||
|
|
||||||
|
Other Parameters
|
||||||
|
----------------
|
||||||
|
app : sphinx.application.Sphinx, optional
|
||||||
|
Application object representing the Sphinx process.
|
||||||
|
what : str, optional
|
||||||
|
A string specifying the type of the object to which the docstring
|
||||||
|
belongs. Valid values: "module", "class", "exception", "function",
|
||||||
|
"method", "attribute".
|
||||||
|
name : str, optional
|
||||||
|
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
|
||||||
|
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
|
||||||
|
directive.
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
>>> from sphinx.ext.napoleon import Config
|
||||||
|
>>> config = Config(napoleon_use_param=True, napoleon_use_rtype=True)
|
||||||
|
>>> docstring = '''One line summary.
|
||||||
|
...
|
||||||
|
... Extended description.
|
||||||
|
...
|
||||||
|
... Args:
|
||||||
|
... arg1(int): Description of `arg1`
|
||||||
|
... arg2(str): Description of `arg2`
|
||||||
|
... Returns:
|
||||||
|
... str: Description of return value.
|
||||||
|
... '''
|
||||||
|
>>> print(GoogleDocstring(docstring, config))
|
||||||
|
One line summary.
|
||||||
|
<BLANKLINE>
|
||||||
|
Extended description.
|
||||||
|
<BLANKLINE>
|
||||||
|
:param arg1: Description of `arg1`
|
||||||
|
:type arg1: int
|
||||||
|
:param arg2: Description of `arg2`
|
||||||
|
:type arg2: str
|
||||||
|
<BLANKLINE>
|
||||||
|
:returns: Description of return value.
|
||||||
|
:rtype: str
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, docstring, config=None, app=None, what='', name='',
|
||||||
|
obj=None, options=None):
|
||||||
|
self._config = config
|
||||||
|
self._app = app
|
||||||
|
if not self._config:
|
||||||
|
from sphinx.ext.napoleon import Config
|
||||||
|
self._config = self._app and self._app.config or Config()
|
||||||
|
self._what = what
|
||||||
|
self._name = name
|
||||||
|
self._obj = obj
|
||||||
|
self._opt = options
|
||||||
|
if isinstance(docstring, basestring):
|
||||||
|
docstring = docstring.splitlines()
|
||||||
|
self._lines = docstring
|
||||||
|
self._line_iter = modify_iter(docstring, modifier=lambda s: s.rstrip())
|
||||||
|
self._parsed_lines = []
|
||||||
|
self._is_in_section = False
|
||||||
|
self._section_indent = 0
|
||||||
|
if not hasattr(self, '_directive_sections'):
|
||||||
|
self._directive_sections = []
|
||||||
|
if not hasattr(self, '_sections'):
|
||||||
|
self._sections = {
|
||||||
|
'args': self._parse_parameters_section,
|
||||||
|
'arguments': self._parse_parameters_section,
|
||||||
|
'attributes': self._parse_attributes_section,
|
||||||
|
'example': self._parse_examples_section,
|
||||||
|
'examples': self._parse_examples_section,
|
||||||
|
'keyword args': self._parse_keyword_arguments_section,
|
||||||
|
'keyword arguments': self._parse_keyword_arguments_section,
|
||||||
|
'methods': self._parse_methods_section,
|
||||||
|
'note': self._parse_note_section,
|
||||||
|
'notes': self._parse_notes_section,
|
||||||
|
'other parameters': self._parse_other_parameters_section,
|
||||||
|
'parameters': self._parse_parameters_section,
|
||||||
|
'return': self._parse_returns_section,
|
||||||
|
'returns': self._parse_returns_section,
|
||||||
|
'raises': self._parse_raises_section,
|
||||||
|
'references': self._parse_references_section,
|
||||||
|
'see also': self._parse_see_also_section,
|
||||||
|
'warning': self._parse_warning_section,
|
||||||
|
'warnings': self._parse_warning_section,
|
||||||
|
'warns': self._parse_warns_section,
|
||||||
|
'yields': self._parse_yields_section,
|
||||||
|
}
|
||||||
|
self._parse()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""Return the parsed docstring in reStructuredText format.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
UTF-8 encoded version of the docstring.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if sys.version_info[0] >= 3:
|
||||||
|
return self.__unicode__()
|
||||||
|
else:
|
||||||
|
return self.__unicode__().encode('utf8')
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
"""Return the parsed docstring in reStructuredText format.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
unicode
|
||||||
|
Unicode version of the docstring.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return u'\n'.join(self.lines())
|
||||||
|
|
||||||
|
def lines(self):
|
||||||
|
"""Return the parsed lines of the docstring in reStructuredText format.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list of str
|
||||||
|
The lines of the docstring in a list.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return self._parsed_lines
|
||||||
|
|
||||||
|
def _consume_indented_block(self, indent=1):
|
||||||
|
lines = []
|
||||||
|
line = self._line_iter.peek()
|
||||||
|
while(not self._is_section_break()
|
||||||
|
and (not line or self._is_indented(line, indent))):
|
||||||
|
lines.append(self._line_iter.next())
|
||||||
|
line = self._line_iter.peek()
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def _consume_contiguous(self):
|
||||||
|
lines = []
|
||||||
|
while (self._line_iter.has_next()
|
||||||
|
and self._line_iter.peek()
|
||||||
|
and not self._is_section_header()):
|
||||||
|
lines.append(self._line_iter.next())
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def _consume_empty(self):
|
||||||
|
lines = []
|
||||||
|
line = self._line_iter.peek()
|
||||||
|
while self._line_iter.has_next() and not line:
|
||||||
|
lines.append(self._line_iter.next())
|
||||||
|
line = self._line_iter.peek()
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def _consume_field(self, parse_type=True, prefer_type=False):
|
||||||
|
line = self._line_iter.next()
|
||||||
|
_name, _, _desc = line.partition(':')
|
||||||
|
_name, _type, _desc = _name.strip(), '', _desc.strip()
|
||||||
|
match = _field_parens_regex.match(_name)
|
||||||
|
if parse_type and match:
|
||||||
|
_name = match.group(1)
|
||||||
|
_type = match.group(2)
|
||||||
|
if prefer_type and not _type:
|
||||||
|
_type, _name = _name, _type
|
||||||
|
indent = self._get_indent(line) + 1
|
||||||
|
_desc = [_desc] + self._dedent(self._consume_indented_block(indent))
|
||||||
|
_desc = self.__class__(_desc, self._config).lines()
|
||||||
|
return _name, _type, _desc
|
||||||
|
|
||||||
|
def _consume_fields(self, parse_type=True, prefer_type=False):
|
||||||
|
self._consume_empty()
|
||||||
|
fields = []
|
||||||
|
while not self._is_section_break():
|
||||||
|
_name, _type, _desc = self._consume_field(parse_type, prefer_type)
|
||||||
|
if _name or _type or _desc:
|
||||||
|
fields.append((_name, _type, _desc,))
|
||||||
|
return fields
|
||||||
|
|
||||||
|
def _consume_returns_section(self):
|
||||||
|
lines = self._dedent(self._consume_to_next_section())
|
||||||
|
if lines:
|
||||||
|
if ':' in lines[0]:
|
||||||
|
_type, _, _desc = lines[0].partition(':')
|
||||||
|
_name, _type, _desc = '', _type.strip(), _desc.strip()
|
||||||
|
match = _field_parens_regex.match(_type)
|
||||||
|
if match:
|
||||||
|
_name = match.group(1)
|
||||||
|
_type = match.group(2)
|
||||||
|
lines[0] = _desc
|
||||||
|
_desc = lines
|
||||||
|
else:
|
||||||
|
_name, _type, _desc = '', '', lines
|
||||||
|
_desc = self.__class__(_desc, self._config).lines()
|
||||||
|
return [(_name, _type, _desc,)]
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def _consume_section_header(self):
|
||||||
|
section = self._line_iter.next()
|
||||||
|
stripped_section = section.strip(':')
|
||||||
|
if stripped_section.lower() in self._sections:
|
||||||
|
section = stripped_section
|
||||||
|
return section
|
||||||
|
|
||||||
|
def _consume_to_next_section(self):
|
||||||
|
self._consume_empty()
|
||||||
|
lines = []
|
||||||
|
while not self._is_section_break():
|
||||||
|
lines.append(self._line_iter.next())
|
||||||
|
return lines + self._consume_empty()
|
||||||
|
|
||||||
|
def _dedent(self, lines, full=False):
|
||||||
|
if full:
|
||||||
|
return [line.lstrip() for line in lines]
|
||||||
|
else:
|
||||||
|
min_indent = self._get_min_indent(lines)
|
||||||
|
return [line[min_indent:] for line in lines]
|
||||||
|
|
||||||
|
def _format_admonition(self, admonition, lines):
|
||||||
|
lines = self._strip_empty(lines)
|
||||||
|
if len(lines) == 1:
|
||||||
|
return ['.. %s:: %s' % (admonition, lines[0].strip()), '']
|
||||||
|
elif lines:
|
||||||
|
lines = self._indent(self._dedent(lines), 3)
|
||||||
|
return ['.. %s::' % admonition, ''] + lines + ['']
|
||||||
|
else:
|
||||||
|
return ['.. %s::' % admonition, '']
|
||||||
|
|
||||||
|
def _format_block(self, prefix, lines, padding=None):
|
||||||
|
if lines:
|
||||||
|
if padding is None:
|
||||||
|
padding = ' ' * len(prefix)
|
||||||
|
result_lines = []
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if line:
|
||||||
|
if i == 0:
|
||||||
|
result_lines.append(prefix + line)
|
||||||
|
else:
|
||||||
|
result_lines.append(padding + line)
|
||||||
|
else:
|
||||||
|
result_lines.append('')
|
||||||
|
return result_lines
|
||||||
|
else:
|
||||||
|
return [prefix]
|
||||||
|
|
||||||
|
def _format_field(self, _name, _type, _desc):
|
||||||
|
separator = any([s for s in _desc]) and ' --' or ''
|
||||||
|
if _name:
|
||||||
|
if _type:
|
||||||
|
field = ['**%s** (*%s*)%s' % (_name, _type, separator)]
|
||||||
|
else:
|
||||||
|
field = ['**%s**%s' % (_name, separator)]
|
||||||
|
elif _type:
|
||||||
|
field = ['*%s*%s' % (_type, separator)]
|
||||||
|
else:
|
||||||
|
field = []
|
||||||
|
return field + _desc
|
||||||
|
|
||||||
|
def _format_fields(self, field_type, fields):
|
||||||
|
field_type = ':%s:' % field_type.strip()
|
||||||
|
padding = ' ' * len(field_type)
|
||||||
|
multi = len(fields) > 1
|
||||||
|
lines = []
|
||||||
|
for _name, _type, _desc in fields:
|
||||||
|
field = self._format_field(_name, _type, _desc)
|
||||||
|
if multi:
|
||||||
|
if lines:
|
||||||
|
lines.extend(self._format_block(padding + ' * ', field))
|
||||||
|
else:
|
||||||
|
lines.extend(self._format_block(field_type + ' * ', field))
|
||||||
|
else:
|
||||||
|
lines.extend(self._format_block(field_type + ' ', field))
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def _get_current_indent(self, peek_ahead=0):
|
||||||
|
line = self._line_iter.peek(peek_ahead + 1)[peek_ahead]
|
||||||
|
while line != self._line_iter.sentinel:
|
||||||
|
if line:
|
||||||
|
return self._get_indent(line)
|
||||||
|
peek_ahead += 1
|
||||||
|
line = self._line_iter.peek(peek_ahead + 1)[peek_ahead]
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def _get_indent(self, line):
|
||||||
|
for i, s in enumerate(line):
|
||||||
|
if not s.isspace():
|
||||||
|
return i
|
||||||
|
return len(line)
|
||||||
|
|
||||||
|
def _get_min_indent(self, lines):
|
||||||
|
min_indent = None
|
||||||
|
for line in lines:
|
||||||
|
if line:
|
||||||
|
indent = self._get_indent(line)
|
||||||
|
if min_indent is None:
|
||||||
|
min_indent = indent
|
||||||
|
elif indent < min_indent:
|
||||||
|
min_indent = indent
|
||||||
|
return min_indent or 0
|
||||||
|
|
||||||
|
def _indent(self, lines, n=4):
|
||||||
|
return [(' ' * n) + line for line in lines]
|
||||||
|
|
||||||
|
def _is_indented(self, line, indent=1):
|
||||||
|
for i, s in enumerate(line):
|
||||||
|
if i >= indent:
|
||||||
|
return True
|
||||||
|
elif not s.isspace():
|
||||||
|
return False
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _is_section_header(self):
|
||||||
|
section = self._line_iter.peek().lower()
|
||||||
|
if section.strip(':') in self._sections:
|
||||||
|
header_indent = self._get_indent(section)
|
||||||
|
section_indent = self._get_current_indent(peek_ahead=1)
|
||||||
|
return section_indent > header_indent
|
||||||
|
elif self._directive_sections:
|
||||||
|
if _directive_regex.match(section):
|
||||||
|
for directive_section in self._directive_sections:
|
||||||
|
if section.startswith(directive_section):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _is_section_break(self):
|
||||||
|
line = self._line_iter.peek()
|
||||||
|
return (not self._line_iter.has_next()
|
||||||
|
or self._is_section_header()
|
||||||
|
or (self._is_in_section
|
||||||
|
and line
|
||||||
|
and not self._is_indented(line, self._section_indent)))
|
||||||
|
|
||||||
|
def _parse(self):
|
||||||
|
self._parsed_lines = self._consume_empty()
|
||||||
|
while self._line_iter.has_next():
|
||||||
|
if self._is_section_header():
|
||||||
|
try:
|
||||||
|
section = self._consume_section_header()
|
||||||
|
self._is_in_section = True
|
||||||
|
self._section_indent = self._get_current_indent()
|
||||||
|
if _directive_regex.match(section):
|
||||||
|
lines = [section] + self._consume_to_next_section()
|
||||||
|
else:
|
||||||
|
lines = self._sections[section.lower()](section)
|
||||||
|
finally:
|
||||||
|
self._is_in_section = False
|
||||||
|
self._section_indent = 0
|
||||||
|
else:
|
||||||
|
if not self._parsed_lines:
|
||||||
|
lines = self._consume_contiguous() + self._consume_empty()
|
||||||
|
else:
|
||||||
|
lines = self._consume_to_next_section()
|
||||||
|
self._parsed_lines.extend(lines)
|
||||||
|
|
||||||
|
def _parse_attributes_section(self, section):
|
||||||
|
lines = []
|
||||||
|
for _name, _type, _desc in self._consume_fields():
|
||||||
|
if self._config.napoleon_use_ivar:
|
||||||
|
field = ':ivar %s: ' % _name
|
||||||
|
lines.extend(self._format_block(field, _desc))
|
||||||
|
if _type:
|
||||||
|
lines.append(':vartype %s: %s' % (_name, _type))
|
||||||
|
else:
|
||||||
|
lines.append('.. attribute:: ' + _name)
|
||||||
|
if _type:
|
||||||
|
lines.append(' :annotation: ' + _type)
|
||||||
|
if _desc:
|
||||||
|
lines.extend([''] + self._indent(_desc, 3))
|
||||||
|
lines.append('')
|
||||||
|
if self._config.napoleon_use_ivar:
|
||||||
|
lines.append('')
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def _parse_examples_section(self, section):
|
||||||
|
use_admonition = self._config.napoleon_use_admonition_for_examples
|
||||||
|
return self._parse_generic_section(section, use_admonition)
|
||||||
|
|
||||||
|
def _parse_generic_section(self, section, use_admonition):
|
||||||
|
lines = self._strip_empty(self._consume_to_next_section())
|
||||||
|
lines = self._dedent(lines)
|
||||||
|
if use_admonition:
|
||||||
|
header = '.. admonition:: %s' % section
|
||||||
|
lines = self._indent(lines, 3)
|
||||||
|
else:
|
||||||
|
header = '.. rubric:: %s' % section
|
||||||
|
if lines:
|
||||||
|
return [header, ''] + lines + ['']
|
||||||
|
else:
|
||||||
|
return [header, '']
|
||||||
|
|
||||||
|
def _parse_keyword_arguments_section(self, section):
|
||||||
|
return self._format_fields('Keyword Arguments', self._consume_fields())
|
||||||
|
|
||||||
|
def _parse_methods_section(self, section):
|
||||||
|
lines = []
|
||||||
|
for _name, _, _desc in self._consume_fields(parse_type=False):
|
||||||
|
lines.append('.. method:: %s' % _name)
|
||||||
|
if _desc:
|
||||||
|
lines.extend([''] + self._indent(_desc, 3))
|
||||||
|
lines.append('')
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def _parse_note_section(self, section):
|
||||||
|
lines = self._consume_to_next_section()
|
||||||
|
return self._format_admonition('note', lines)
|
||||||
|
|
||||||
|
def _parse_notes_section(self, section):
|
||||||
|
use_admonition = self._config.napoleon_use_admonition_for_notes
|
||||||
|
return self._parse_generic_section('Notes', use_admonition)
|
||||||
|
|
||||||
|
def _parse_other_parameters_section(self, section):
|
||||||
|
return self._format_fields('Other Parameters', self._consume_fields())
|
||||||
|
|
||||||
|
def _parse_parameters_section(self, section):
|
||||||
|
fields = self._consume_fields()
|
||||||
|
if self._config.napoleon_use_param:
|
||||||
|
lines = []
|
||||||
|
for _name, _type, _desc in fields:
|
||||||
|
field = ':param %s: ' % _name
|
||||||
|
lines.extend(self._format_block(field, _desc))
|
||||||
|
if _type:
|
||||||
|
lines.append(':type %s: %s' % (_name, _type))
|
||||||
|
return lines + ['']
|
||||||
|
else:
|
||||||
|
return self._format_fields('Parameters', fields)
|
||||||
|
|
||||||
|
def _parse_raises_section(self, section):
|
||||||
|
fields = self._consume_fields()
|
||||||
|
field_type = ':raises:'
|
||||||
|
padding = ' ' * len(field_type)
|
||||||
|
multi = len(fields) > 1
|
||||||
|
lines = []
|
||||||
|
for _name, _type, _desc in fields:
|
||||||
|
sep = _desc and ' -- ' or ''
|
||||||
|
if _name:
|
||||||
|
if ' ' in _name:
|
||||||
|
_name = '**%s**' % _name
|
||||||
|
else:
|
||||||
|
_name = ':exc:`%s`' % _name
|
||||||
|
if _type:
|
||||||
|
field = ['%s (*%s*)%s' % (_name, _type, sep)]
|
||||||
|
else:
|
||||||
|
field = ['%s%s' % (_name, sep)]
|
||||||
|
elif _type:
|
||||||
|
field = ['*%s*%s' % (_type, sep)]
|
||||||
|
else:
|
||||||
|
field = []
|
||||||
|
field = field + _desc
|
||||||
|
if multi:
|
||||||
|
if lines:
|
||||||
|
lines.extend(self._format_block(padding + ' * ', field))
|
||||||
|
else:
|
||||||
|
lines.extend(self._format_block(field_type + ' * ', field))
|
||||||
|
else:
|
||||||
|
lines.extend(self._format_block(field_type + ' ', field))
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def _parse_references_section(self, section):
|
||||||
|
use_admonition = self._config.napoleon_use_admonition_for_references
|
||||||
|
return self._parse_generic_section('References', use_admonition)
|
||||||
|
|
||||||
|
def _parse_returns_section(self, section):
|
||||||
|
fields = self._consume_returns_section()
|
||||||
|
multi = len(fields) > 1
|
||||||
|
if multi:
|
||||||
|
use_rtype = False
|
||||||
|
else:
|
||||||
|
use_rtype = self._config.napoleon_use_rtype
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
for _name, _type, _desc in fields:
|
||||||
|
if use_rtype:
|
||||||
|
field = self._format_field(_name, '', _desc)
|
||||||
|
else:
|
||||||
|
field = self._format_field(_name, _type, _desc)
|
||||||
|
|
||||||
|
if multi:
|
||||||
|
if lines:
|
||||||
|
lines.extend(self._format_block(' * ', field))
|
||||||
|
else:
|
||||||
|
lines.extend(self._format_block(':returns: * ', field))
|
||||||
|
else:
|
||||||
|
lines.extend(self._format_block(':returns: ', field))
|
||||||
|
if _type and use_rtype:
|
||||||
|
lines.append(':rtype: %s' % _type)
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def _parse_see_also_section(self, section):
|
||||||
|
lines = self._consume_to_next_section()
|
||||||
|
return self._format_admonition('seealso', lines)
|
||||||
|
|
||||||
|
def _parse_warning_section(self, section):
|
||||||
|
lines = self._consume_to_next_section()
|
||||||
|
return self._format_admonition('warning', lines)
|
||||||
|
|
||||||
|
def _parse_warns_section(self, section):
|
||||||
|
return self._format_fields('Warns', self._consume_fields())
|
||||||
|
|
||||||
|
def _parse_yields_section(self, section):
|
||||||
|
fields = self._consume_fields(prefer_type=True)
|
||||||
|
return self._format_fields('Yields', fields)
|
||||||
|
|
||||||
|
def _strip_empty(self, lines):
|
||||||
|
if lines:
|
||||||
|
start = -1
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if line:
|
||||||
|
start = i
|
||||||
|
break
|
||||||
|
if start == -1:
|
||||||
|
lines = []
|
||||||
|
end = -1
|
||||||
|
for i in reversed(xrange(len(lines))):
|
||||||
|
line = lines[i]
|
||||||
|
if line:
|
||||||
|
end = i
|
||||||
|
break
|
||||||
|
if start > 0 or end + 1 < len(lines):
|
||||||
|
lines = lines[start:end + 1]
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
class NumpyDocstring(GoogleDocstring):
|
||||||
|
"""Parse NumPy style docstrings.
|
||||||
|
|
||||||
|
Convert NumPy style docstrings to reStructuredText.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
docstring : str or list of 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
|
||||||
|
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.
|
||||||
|
|
||||||
|
See Also
|
||||||
|
--------
|
||||||
|
:class:`sphinx.ext.napoleon.Config`
|
||||||
|
|
||||||
|
Other Parameters
|
||||||
|
----------------
|
||||||
|
app : sphinx.application.Sphinx, optional
|
||||||
|
Application object representing the Sphinx process.
|
||||||
|
what : str, optional
|
||||||
|
A string specifying the type of the object to which the docstring
|
||||||
|
belongs. Valid values: "module", "class", "exception", "function",
|
||||||
|
"method", "attribute".
|
||||||
|
name : str, optional
|
||||||
|
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
|
||||||
|
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
|
||||||
|
directive.
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
>>> from sphinx.ext.napoleon import Config
|
||||||
|
>>> config = Config(napoleon_use_param=True, napoleon_use_rtype=True)
|
||||||
|
>>> docstring = '''One line summary.
|
||||||
|
...
|
||||||
|
... Extended description.
|
||||||
|
...
|
||||||
|
... Parameters
|
||||||
|
... ----------
|
||||||
|
... arg1 : int
|
||||||
|
... Description of `arg1`
|
||||||
|
... arg2 : str
|
||||||
|
... Description of `arg2`
|
||||||
|
... Returns
|
||||||
|
... -------
|
||||||
|
... str
|
||||||
|
... Description of return value.
|
||||||
|
... '''
|
||||||
|
>>> print(NumpyDocstring(docstring, config))
|
||||||
|
One line summary.
|
||||||
|
<BLANKLINE>
|
||||||
|
Extended description.
|
||||||
|
<BLANKLINE>
|
||||||
|
:param arg1: Description of `arg1`
|
||||||
|
:type arg1: int
|
||||||
|
:param arg2: Description of `arg2`
|
||||||
|
:type arg2: str
|
||||||
|
<BLANKLINE>
|
||||||
|
:returns: Description of return value.
|
||||||
|
:rtype: str
|
||||||
|
|
||||||
|
Methods
|
||||||
|
-------
|
||||||
|
__str__()
|
||||||
|
Return the parsed docstring in reStructuredText format.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
UTF-8 encoded version of the docstring.
|
||||||
|
|
||||||
|
__unicode__()
|
||||||
|
Return the parsed docstring in reStructuredText format.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
unicode
|
||||||
|
Unicode version of the docstring.
|
||||||
|
|
||||||
|
lines()
|
||||||
|
Return the parsed lines of the docstring in reStructuredText format.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list of str
|
||||||
|
The lines of the docstring in a list.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, docstring, config=None, app=None, what='', name='',
|
||||||
|
obj=None, options=None):
|
||||||
|
self._directive_sections = ['.. index::']
|
||||||
|
super(NumpyDocstring, self).__init__(docstring, config, app, what,
|
||||||
|
name, obj, options)
|
||||||
|
|
||||||
|
def _consume_field(self, parse_type=True, prefer_type=False):
|
||||||
|
line = self._line_iter.next()
|
||||||
|
if parse_type:
|
||||||
|
_name, _, _type = line.partition(':')
|
||||||
|
else:
|
||||||
|
_name, _type = line, ''
|
||||||
|
_name, _type = _name.strip(), _type.strip()
|
||||||
|
if prefer_type and not _type:
|
||||||
|
_type, _name = _name, _type
|
||||||
|
indent = self._get_indent(line)
|
||||||
|
_desc = self._dedent(self._consume_indented_block(indent + 1))
|
||||||
|
_desc = self.__class__(_desc, self._config).lines()
|
||||||
|
return _name, _type, _desc
|
||||||
|
|
||||||
|
def _consume_returns_section(self):
|
||||||
|
return self._consume_fields(prefer_type=True)
|
||||||
|
|
||||||
|
def _consume_section_header(self):
|
||||||
|
section = self._line_iter.next()
|
||||||
|
if not _directive_regex.match(section):
|
||||||
|
# Consume the header underline
|
||||||
|
self._line_iter.next()
|
||||||
|
return section
|
||||||
|
|
||||||
|
def _is_section_break(self):
|
||||||
|
line1, line2 = self._line_iter.peek(2)
|
||||||
|
return (not self._line_iter.has_next()
|
||||||
|
or self._is_section_header()
|
||||||
|
or ['', ''] == [line1, line2]
|
||||||
|
or (self._is_in_section
|
||||||
|
and line1
|
||||||
|
and not self._is_indented(line1, self._section_indent)))
|
||||||
|
|
||||||
|
def _is_section_header(self):
|
||||||
|
section, underline = self._line_iter.peek(2)
|
||||||
|
section = section.lower()
|
||||||
|
if section in self._sections and isinstance(underline, basestring):
|
||||||
|
pattern = r'[=\-`:\'"~^_*+#<>]{' + str(len(section)) + r'}$'
|
||||||
|
return bool(re.match(pattern, underline))
|
||||||
|
elif self._directive_sections:
|
||||||
|
if _directive_regex.match(section):
|
||||||
|
for directive_section in self._directive_sections:
|
||||||
|
if section.startswith(directive_section):
|
||||||
|
return True
|
||||||
|
return False
|
244
sphinx/ext/napoleon/iterators.py
Normal file
244
sphinx/ext/napoleon/iterators.py
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
sphinx.ext.napoleon.iterators
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
A collection of helpful iterators.
|
||||||
|
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
if sys.version_info[0] >= 3:
|
||||||
|
callable = lambda o: hasattr(o, '__call__')
|
||||||
|
|
||||||
|
|
||||||
|
class peek_iter(object):
|
||||||
|
"""An iterator object that supports peeking ahead.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
o : iterable or callable
|
||||||
|
`o` is interpreted very differently depending on the presence of
|
||||||
|
`sentinel`.
|
||||||
|
|
||||||
|
If `sentinel` is not given, then `o` must be a collection object
|
||||||
|
which supports either the iteration protocol or the sequence protocol.
|
||||||
|
|
||||||
|
If `sentinel` is given, then `o` must be a callable object.
|
||||||
|
|
||||||
|
sentinel : any value, optional
|
||||||
|
If given, the iterator will call `o` with no arguments for each
|
||||||
|
call to its `next` method; if the value returned is equal to
|
||||||
|
`sentinel`, :exc:`StopIteration` will be raised, otherwise the
|
||||||
|
value will be returned.
|
||||||
|
|
||||||
|
See Also
|
||||||
|
--------
|
||||||
|
`peek_iter` can operate as a drop in replacement for the built-in
|
||||||
|
`iter <http://docs.python.org/2/library/functions.html#iter>`_ function.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
sentinel
|
||||||
|
The value used to indicate the iterator is exhausted. If `sentinel`
|
||||||
|
was not given when the `peek_iter` was instantiated, then it will
|
||||||
|
be set to a new object instance: ``object()``.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""__init__(o, sentinel=None)"""
|
||||||
|
self._iterable = iter(*args)
|
||||||
|
self._cache = collections.deque()
|
||||||
|
if len(args) == 2:
|
||||||
|
self.sentinel = args[1]
|
||||||
|
else:
|
||||||
|
self.sentinel = object()
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self, n=None):
|
||||||
|
# note: prevent 2to3 to transform self.next() in next(self) which
|
||||||
|
# causes an infinite loop !
|
||||||
|
return getattr(self, 'next')(n)
|
||||||
|
|
||||||
|
def _fillcache(self, n):
|
||||||
|
"""Cache `n` items. If `n` is 0 or None, then 1 item is cached."""
|
||||||
|
if not n:
|
||||||
|
n = 1
|
||||||
|
try:
|
||||||
|
while len(self._cache) < n:
|
||||||
|
self._cache.append(self._iterable.next())
|
||||||
|
except StopIteration:
|
||||||
|
while len(self._cache) < n:
|
||||||
|
self._cache.append(self.sentinel)
|
||||||
|
|
||||||
|
def has_next(self):
|
||||||
|
"""Determine if iterator is exhausted.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if iterator has more items, False otherwise.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
Will never raise :exc:`StopIteration`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return self.peek() != self.sentinel
|
||||||
|
|
||||||
|
def next(self, n=None):
|
||||||
|
"""Get the next item or `n` items of the iterator.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
n : int or None
|
||||||
|
The number of items to retrieve. Defaults to None.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
item or list of items
|
||||||
|
The next item or `n` items of the iterator. If `n` is None, the
|
||||||
|
item itself is returned. If `n` is an int, the items will be
|
||||||
|
returned in a list. If `n` is 0, an empty list is returned.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
StopIteration
|
||||||
|
Raised if the iterator is exhausted, even if `n` is 0.
|
||||||
|
|
||||||
|
"""
|
||||||
|
self._fillcache(n)
|
||||||
|
if not n:
|
||||||
|
if self._cache[0] == self.sentinel:
|
||||||
|
raise StopIteration
|
||||||
|
if n is None:
|
||||||
|
result = self._cache.popleft()
|
||||||
|
else:
|
||||||
|
result = []
|
||||||
|
else:
|
||||||
|
if self._cache[n - 1] == self.sentinel:
|
||||||
|
raise StopIteration
|
||||||
|
result = [self._cache.popleft() for i in range(n)]
|
||||||
|
return result
|
||||||
|
|
||||||
|
def peek(self, n=None):
|
||||||
|
"""Preview the next item or `n` items of the iterator.
|
||||||
|
|
||||||
|
The iterator is not advanced when peek is called.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
item or list of items
|
||||||
|
The next item or `n` items of the iterator. If `n` is None, the
|
||||||
|
item itself is returned. If `n` is an int, the items will be
|
||||||
|
returned in a list. If `n` is 0, an empty list is returned.
|
||||||
|
|
||||||
|
If the iterator is exhausted, `peek_iter.sentinel` is returned,
|
||||||
|
or placed as the last item in the returned list.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
Will never raise :exc:`StopIteration`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
self._fillcache(n)
|
||||||
|
if n is None:
|
||||||
|
result = self._cache[0]
|
||||||
|
else:
|
||||||
|
result = [self._cache[i] for i in range(n)]
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class modify_iter(peek_iter):
|
||||||
|
"""An iterator object that supports modifying items as they are returned.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
o : iterable or callable
|
||||||
|
`o` is interpreted very differently depending on the presence of
|
||||||
|
`sentinel`.
|
||||||
|
|
||||||
|
If `sentinel` is not given, then `o` must be a collection object
|
||||||
|
which supports either the iteration protocol or the sequence protocol.
|
||||||
|
|
||||||
|
If `sentinel` is given, then `o` must be a callable object.
|
||||||
|
|
||||||
|
sentinel : any value, optional
|
||||||
|
If given, the iterator will call `o` with no arguments for each
|
||||||
|
call to its `next` method; if the value returned is equal to
|
||||||
|
`sentinel`, :exc:`StopIteration` will be raised, otherwise the
|
||||||
|
value will be returned.
|
||||||
|
|
||||||
|
modifier : callable, optional
|
||||||
|
The function that will be used to modify each item returned by the
|
||||||
|
iterator. `modifier` should take a single argument and return a
|
||||||
|
single value. Defaults to ``lambda x: x``.
|
||||||
|
|
||||||
|
If `sentinel` is not given, `modifier` must be passed as a keyword
|
||||||
|
argument.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
modifier : callable
|
||||||
|
`modifier` is called with each item in `o` as it is iterated. The
|
||||||
|
return value of `modifier` is returned in lieu of the item.
|
||||||
|
|
||||||
|
Values returned by `peek` as well as `next` are affected by
|
||||||
|
`modifier`. However, `modify_iter.sentinel` is never passed through
|
||||||
|
`modifier`; it will always be returned from `peek` unmodified.
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
>>> a = [" A list ",
|
||||||
|
... " of strings ",
|
||||||
|
... " with ",
|
||||||
|
... " extra ",
|
||||||
|
... " whitespace. "]
|
||||||
|
>>> modifier = lambda s: s.strip().replace('with', 'without')
|
||||||
|
>>> for s in modify_iter(a, modifier=modifier):
|
||||||
|
... print('"%s"' % s)
|
||||||
|
"A list"
|
||||||
|
"of strings"
|
||||||
|
"without"
|
||||||
|
"extra"
|
||||||
|
"whitespace."
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""__init__(o, sentinel=None, modifier=lambda x: x)"""
|
||||||
|
if 'modifier' in kwargs:
|
||||||
|
self.modifier = kwargs['modifier']
|
||||||
|
elif len(args) > 2:
|
||||||
|
self.modifier = args[2]
|
||||||
|
args = args[:2]
|
||||||
|
else:
|
||||||
|
self.modifier = lambda x: x
|
||||||
|
if not callable(self.modifier):
|
||||||
|
raise TypeError('modify_iter(o, modifier): '
|
||||||
|
'modifier must be callable')
|
||||||
|
super(modify_iter, self).__init__(*args)
|
||||||
|
|
||||||
|
def _fillcache(self, n):
|
||||||
|
"""Cache `n` modified items. If `n` is 0 or None, 1 item is cached.
|
||||||
|
|
||||||
|
Each item returned by the iterator is passed through the
|
||||||
|
`modify_iter.modified` function before being cached.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not n:
|
||||||
|
n = 1
|
||||||
|
try:
|
||||||
|
while len(self._cache) < n:
|
||||||
|
self._cache.append(self.modifier(self._iterable.next()))
|
||||||
|
except StopIteration:
|
||||||
|
while len(self._cache) < n:
|
||||||
|
self._cache.append(self.sentinel)
|
@ -8,7 +8,8 @@ sys.path.append(os.path.abspath('..'))
|
|||||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.jsmath', 'sphinx.ext.todo',
|
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.jsmath', 'sphinx.ext.todo',
|
||||||
'sphinx.ext.coverage', 'sphinx.ext.autosummary',
|
'sphinx.ext.coverage', 'sphinx.ext.autosummary',
|
||||||
'sphinx.ext.doctest', 'sphinx.ext.extlinks',
|
'sphinx.ext.doctest', 'sphinx.ext.extlinks',
|
||||||
'sphinx.ext.viewcode', 'sphinx.ext.oldcmarkup', 'ext']
|
'sphinx.ext.viewcode', 'sphinx.ext.oldcmarkup',
|
||||||
|
'sphinx.ext.napoleon', 'ext']
|
||||||
|
|
||||||
jsmath_path = 'dummy.js'
|
jsmath_path = 'dummy.js'
|
||||||
|
|
||||||
|
190
tests/test_napoleon.py
Normal file
190
tests/test_napoleon.py
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
test_napoleon
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Tests for :mod:`sphinx.ext.napoleon.__init__` module.
|
||||||
|
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from mock import Mock
|
||||||
|
from sphinx.application import Sphinx
|
||||||
|
from sphinx.ext.napoleon import (_process_docstring, _skip_member, Config,
|
||||||
|
setup)
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
def _private_doc():
|
||||||
|
"""module._private_doc.DOCSTRING"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _private_undoc():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def __special_doc__():
|
||||||
|
"""module.__special_doc__.DOCSTRING"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def __special_undoc__():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SampleClass(object):
|
||||||
|
def _private_doc(self):
|
||||||
|
"""SampleClass._private_doc.DOCSTRING"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _private_undoc(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __special_doc__(self):
|
||||||
|
"""SampleClass.__special_doc__.DOCSTRING"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __special_undoc__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SampleError(Exception):
|
||||||
|
def _private_doc(self):
|
||||||
|
"""SampleError._private_doc.DOCSTRING"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _private_undoc(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __special_doc__(self):
|
||||||
|
"""SampleError.__special_doc__.DOCSTRING"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __special_undoc__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessDocstringTest(TestCase):
|
||||||
|
def test_modify_in_place(self):
|
||||||
|
lines = ['Summary line.',
|
||||||
|
'',
|
||||||
|
'Args:',
|
||||||
|
' arg1: arg1 description']
|
||||||
|
app = Mock()
|
||||||
|
app.config = Config()
|
||||||
|
_process_docstring(app, 'class', 'SampleClass', SampleClass, Mock(),
|
||||||
|
lines)
|
||||||
|
|
||||||
|
expected = ['Summary line.',
|
||||||
|
'',
|
||||||
|
':Parameters: **arg1** --',
|
||||||
|
' arg1 description']
|
||||||
|
self.assertEqual(expected, lines)
|
||||||
|
|
||||||
|
|
||||||
|
class SetupTest(TestCase):
|
||||||
|
def test_unknown_app_type(self):
|
||||||
|
setup(object())
|
||||||
|
|
||||||
|
def test_add_config_values(self):
|
||||||
|
app = Mock(Sphinx)
|
||||||
|
setup(app)
|
||||||
|
for name, (default, rebuild) in Config._config_values.items():
|
||||||
|
has_config = False
|
||||||
|
for method_name, args, kwargs in app.method_calls:
|
||||||
|
if(method_name == 'add_config_value' and
|
||||||
|
args[0] == name):
|
||||||
|
has_config = True
|
||||||
|
if not has_config:
|
||||||
|
self.fail('Config value was not added to app %s' % name)
|
||||||
|
|
||||||
|
has_process_docstring = False
|
||||||
|
has_skip_member = False
|
||||||
|
for method_name, args, kwargs in app.method_calls:
|
||||||
|
if method_name == 'connect':
|
||||||
|
if(args[0] == 'autodoc-process-docstring' and
|
||||||
|
args[1] == _process_docstring):
|
||||||
|
has_process_docstring = True
|
||||||
|
elif(args[0] == 'autodoc-skip-member' and
|
||||||
|
args[1] == _skip_member):
|
||||||
|
has_skip_member = True
|
||||||
|
if not has_process_docstring:
|
||||||
|
self.fail('autodoc-process-docstring never connected')
|
||||||
|
if not has_skip_member:
|
||||||
|
self.fail('autodoc-skip-member never connected')
|
||||||
|
|
||||||
|
|
||||||
|
class SkipMemberTest(TestCase):
|
||||||
|
def assertSkip(self, what, member, obj, expect_skip, config_name):
|
||||||
|
skip = 'default skip'
|
||||||
|
app = Mock()
|
||||||
|
app.config = Config()
|
||||||
|
setattr(app.config, config_name, True)
|
||||||
|
if expect_skip:
|
||||||
|
self.assertEqual(skip, _skip_member(app, what, member, obj, skip,
|
||||||
|
Mock()))
|
||||||
|
else:
|
||||||
|
self.assertFalse(_skip_member(app, what, member, obj, skip,
|
||||||
|
Mock()))
|
||||||
|
setattr(app.config, config_name, False)
|
||||||
|
self.assertEqual(skip, _skip_member(app, what, member, obj, skip,
|
||||||
|
Mock()))
|
||||||
|
|
||||||
|
def test_class_private_doc(self):
|
||||||
|
self.assertSkip('class', '_private_doc',
|
||||||
|
SampleClass._private_doc, False,
|
||||||
|
'napoleon_include_private_with_doc')
|
||||||
|
|
||||||
|
def test_class_private_undoc(self):
|
||||||
|
self.assertSkip('class', '_private_undoc',
|
||||||
|
SampleClass._private_undoc, True,
|
||||||
|
'napoleon_include_private_with_doc')
|
||||||
|
|
||||||
|
def test_class_special_doc(self):
|
||||||
|
self.assertSkip('class', '__special_doc__',
|
||||||
|
SampleClass.__special_doc__, False,
|
||||||
|
'napoleon_include_special_with_doc')
|
||||||
|
|
||||||
|
def test_class_special_undoc(self):
|
||||||
|
self.assertSkip('class', '__special_undoc__',
|
||||||
|
SampleClass.__special_undoc__, True,
|
||||||
|
'napoleon_include_special_with_doc')
|
||||||
|
|
||||||
|
def test_exception_private_doc(self):
|
||||||
|
self.assertSkip('exception', '_private_doc',
|
||||||
|
SampleError._private_doc, False,
|
||||||
|
'napoleon_include_private_with_doc')
|
||||||
|
|
||||||
|
def test_exception_private_undoc(self):
|
||||||
|
self.assertSkip('exception', '_private_undoc',
|
||||||
|
SampleError._private_undoc, True,
|
||||||
|
'napoleon_include_private_with_doc')
|
||||||
|
|
||||||
|
def test_exception_special_doc(self):
|
||||||
|
self.assertSkip('exception', '__special_doc__',
|
||||||
|
SampleError.__special_doc__, False,
|
||||||
|
'napoleon_include_special_with_doc')
|
||||||
|
|
||||||
|
def test_exception_special_undoc(self):
|
||||||
|
self.assertSkip('exception', '__special_undoc__',
|
||||||
|
SampleError.__special_undoc__, True,
|
||||||
|
'napoleon_include_special_with_doc')
|
||||||
|
|
||||||
|
def test_module_private_doc(self):
|
||||||
|
self.assertSkip('module', '_private_doc', _private_doc, False,
|
||||||
|
'napoleon_include_private_with_doc')
|
||||||
|
|
||||||
|
def test_module_private_undoc(self):
|
||||||
|
self.assertSkip('module', '_private_undoc', _private_undoc, True,
|
||||||
|
'napoleon_include_private_with_doc')
|
||||||
|
|
||||||
|
def test_module_special_doc(self):
|
||||||
|
self.assertSkip('module', '__special_doc__', __special_doc__, False,
|
||||||
|
'napoleon_include_special_with_doc')
|
||||||
|
|
||||||
|
def test_module_special_undoc(self):
|
||||||
|
self.assertSkip('module', '__special_undoc__', __special_undoc__, True,
|
||||||
|
'napoleon_include_special_with_doc')
|
259
tests/test_napoleon_docstring.py
Normal file
259
tests/test_napoleon_docstring.py
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
test_napoleon_docstring
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Tests for :mod:`sphinx.ext.napoleon.docstring` module.
|
||||||
|
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import textwrap
|
||||||
|
from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
class BaseDocstringTest(TestCase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class GoogleDocstringTest(BaseDocstringTest):
|
||||||
|
docstrings = [(
|
||||||
|
"""Single line summary""",
|
||||||
|
"""Single line summary"""
|
||||||
|
), (
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Extended description
|
||||||
|
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Extended description
|
||||||
|
"""
|
||||||
|
), (
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Args:
|
||||||
|
arg1(str):Extended
|
||||||
|
description of arg1
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
:Parameters: **arg1** (*str*) --
|
||||||
|
Extended
|
||||||
|
description of arg1"""
|
||||||
|
), (
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Args:
|
||||||
|
arg1(str):Extended
|
||||||
|
description of arg1
|
||||||
|
arg2 ( int ) : Extended
|
||||||
|
description of arg2
|
||||||
|
|
||||||
|
Keyword Args:
|
||||||
|
kwarg1(str):Extended
|
||||||
|
description of kwarg1
|
||||||
|
kwarg2 ( int ) : Extended
|
||||||
|
description of kwarg2""",
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
:Parameters: * **arg1** (*str*) --
|
||||||
|
Extended
|
||||||
|
description of arg1
|
||||||
|
* **arg2** (*int*) --
|
||||||
|
Extended
|
||||||
|
description of arg2
|
||||||
|
|
||||||
|
:Keyword Arguments: * **kwarg1** (*str*) --
|
||||||
|
Extended
|
||||||
|
description of kwarg1
|
||||||
|
* **kwarg2** (*int*) --
|
||||||
|
Extended
|
||||||
|
description of kwarg2"""
|
||||||
|
), (
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
arg1(str):Extended
|
||||||
|
description of arg1
|
||||||
|
arg2 ( int ) : Extended
|
||||||
|
description of arg2
|
||||||
|
|
||||||
|
Keyword Arguments:
|
||||||
|
kwarg1(str):Extended
|
||||||
|
description of kwarg1
|
||||||
|
kwarg2 ( int ) : Extended
|
||||||
|
description of kwarg2""",
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
:Parameters: * **arg1** (*str*) --
|
||||||
|
Extended
|
||||||
|
description of arg1
|
||||||
|
* **arg2** (*int*) --
|
||||||
|
Extended
|
||||||
|
description of arg2
|
||||||
|
|
||||||
|
:Keyword Arguments: * **kwarg1** (*str*) --
|
||||||
|
Extended
|
||||||
|
description of kwarg1
|
||||||
|
* **kwarg2** (*int*) --
|
||||||
|
Extended
|
||||||
|
description of kwarg2"""
|
||||||
|
), (
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Return:
|
||||||
|
str:Extended
|
||||||
|
description of return value
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
:returns: *str* --
|
||||||
|
Extended
|
||||||
|
description of return value"""
|
||||||
|
), (
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str:Extended
|
||||||
|
description of return value
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
:returns: *str* --
|
||||||
|
Extended
|
||||||
|
description of return value"""
|
||||||
|
)]
|
||||||
|
|
||||||
|
def test_docstrings(self):
|
||||||
|
for docstring, expected in self.docstrings:
|
||||||
|
actual = str(GoogleDocstring(textwrap.dedent(docstring)))
|
||||||
|
expected = textwrap.dedent(expected)
|
||||||
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
|
|
||||||
|
class NumpyDocstringTest(BaseDocstringTest):
|
||||||
|
docstrings = [(
|
||||||
|
"""Single line summary""",
|
||||||
|
"""Single line summary"""
|
||||||
|
), (
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Extended description
|
||||||
|
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Extended description
|
||||||
|
"""
|
||||||
|
), (
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
arg1:str
|
||||||
|
Extended
|
||||||
|
description of arg1
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
:Parameters: **arg1** (*str*) --
|
||||||
|
Extended
|
||||||
|
description of arg1"""
|
||||||
|
), (
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
arg1:str
|
||||||
|
Extended
|
||||||
|
description of arg1
|
||||||
|
arg2 : int
|
||||||
|
Extended
|
||||||
|
description of arg2
|
||||||
|
|
||||||
|
Keyword Arguments
|
||||||
|
-----------------
|
||||||
|
kwarg1:str
|
||||||
|
Extended
|
||||||
|
description of kwarg1
|
||||||
|
kwarg2 : int
|
||||||
|
Extended
|
||||||
|
description of kwarg2
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
:Parameters: * **arg1** (*str*) --
|
||||||
|
Extended
|
||||||
|
description of arg1
|
||||||
|
* **arg2** (*int*) --
|
||||||
|
Extended
|
||||||
|
description of arg2
|
||||||
|
|
||||||
|
:Keyword Arguments: * **kwarg1** (*str*) --
|
||||||
|
Extended
|
||||||
|
description of kwarg1
|
||||||
|
* **kwarg2** (*int*) --
|
||||||
|
Extended
|
||||||
|
description of kwarg2"""
|
||||||
|
), (
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Return
|
||||||
|
------
|
||||||
|
str
|
||||||
|
Extended
|
||||||
|
description of return value
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
:returns: *str* --
|
||||||
|
Extended
|
||||||
|
description of return value"""
|
||||||
|
), (
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
Extended
|
||||||
|
description of return value
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
Single line summary
|
||||||
|
|
||||||
|
:returns: *str* --
|
||||||
|
Extended
|
||||||
|
description of return value"""
|
||||||
|
)]
|
||||||
|
|
||||||
|
def test_docstrings(self):
|
||||||
|
for docstring, expected in self.docstrings:
|
||||||
|
actual = str(NumpyDocstring(textwrap.dedent(docstring)))
|
||||||
|
expected = textwrap.dedent(expected)
|
||||||
|
self.assertEqual(expected, actual)
|
346
tests/test_napoleon_iterators.py
Normal file
346
tests/test_napoleon_iterators.py
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
test_napoleon_iterators
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Tests for :mod:`sphinx.ext.napoleon.iterators` module.
|
||||||
|
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sphinx.ext.napoleon.iterators import peek_iter, modify_iter
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
class BaseIteratorsTest(TestCase):
|
||||||
|
def assertEqualTwice(self, expected, func, *args):
|
||||||
|
self.assertEqual(expected, func(*args))
|
||||||
|
self.assertEqual(expected, func(*args))
|
||||||
|
|
||||||
|
def assertFalseTwice(self, func, *args):
|
||||||
|
self.assertFalse(func(*args))
|
||||||
|
self.assertFalse(func(*args))
|
||||||
|
|
||||||
|
def assertNext(self, it, expected, is_last):
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(expected, it.peek)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(expected, it.peek)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqual(expected, it.next())
|
||||||
|
if is_last:
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertRaisesTwice(StopIteration, it.next)
|
||||||
|
else:
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
|
||||||
|
def assertRaisesTwice(self, exc, func, *args):
|
||||||
|
self.assertRaises(exc, func, *args)
|
||||||
|
self.assertRaises(exc, func, *args)
|
||||||
|
|
||||||
|
def assertTrueTwice(self, func, *args):
|
||||||
|
self.assertTrue(func(*args))
|
||||||
|
self.assertTrue(func(*args))
|
||||||
|
|
||||||
|
|
||||||
|
class PeekIterTest(BaseIteratorsTest):
|
||||||
|
def test_init_with_sentinel(self):
|
||||||
|
a = iter(['1', '2', 'DONE'])
|
||||||
|
sentinel = 'DONE'
|
||||||
|
self.assertRaises(TypeError, peek_iter, a, sentinel)
|
||||||
|
|
||||||
|
def get_next():
|
||||||
|
return next(a)
|
||||||
|
it = peek_iter(get_next, sentinel)
|
||||||
|
self.assertEqual(it.sentinel, sentinel)
|
||||||
|
self.assertNext(it, '1', is_last=False)
|
||||||
|
self.assertNext(it, '2', is_last=True)
|
||||||
|
|
||||||
|
def test_iter(self):
|
||||||
|
a = ['1', '2', '3']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrue(it is it.__iter__())
|
||||||
|
|
||||||
|
a = []
|
||||||
|
b = [i for i in peek_iter(a)]
|
||||||
|
self.assertEqual([], b)
|
||||||
|
|
||||||
|
a = ['1']
|
||||||
|
b = [i for i in peek_iter(a)]
|
||||||
|
self.assertEqual(['1'], b)
|
||||||
|
|
||||||
|
a = ['1', '2']
|
||||||
|
b = [i for i in peek_iter(a)]
|
||||||
|
self.assertEqual(['1', '2'], b)
|
||||||
|
|
||||||
|
a = ['1', '2', '3']
|
||||||
|
b = [i for i in peek_iter(a)]
|
||||||
|
self.assertEqual(['1', '2', '3'], b)
|
||||||
|
|
||||||
|
def test_next_with_multi(self):
|
||||||
|
a = []
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertRaisesTwice(StopIteration, it.next, 2)
|
||||||
|
|
||||||
|
a = ['1']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertRaisesTwice(StopIteration, it.next, 2)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
|
||||||
|
a = ['1', '2']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqual(['1', '2'], it.next(2))
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
|
||||||
|
a = ['1', '2', '3']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqual(['1', '2'], it.next(2))
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertRaisesTwice(StopIteration, it.next, 2)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
|
||||||
|
a = ['1', '2', '3', '4']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqual(['1', '2'], it.next(2))
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqual(['3', '4'], it.next(2))
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertRaisesTwice(StopIteration, it.next, 2)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
|
||||||
|
def test_next_with_none(self):
|
||||||
|
a = []
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertRaisesTwice(StopIteration, it.next)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
|
||||||
|
a = ['1']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertEqual('1', it.__next__())
|
||||||
|
|
||||||
|
a = ['1']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertNext(it, '1', is_last=True)
|
||||||
|
|
||||||
|
a = ['1', '2']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertNext(it, '1', is_last=False)
|
||||||
|
self.assertNext(it, '2', is_last=True)
|
||||||
|
|
||||||
|
a = ['1', '2', '3']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertNext(it, '1', is_last=False)
|
||||||
|
self.assertNext(it, '2', is_last=False)
|
||||||
|
self.assertNext(it, '3', is_last=True)
|
||||||
|
|
||||||
|
def test_next_with_one(self):
|
||||||
|
a = []
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertRaisesTwice(StopIteration, it.next, 1)
|
||||||
|
|
||||||
|
a = ['1']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqual(['1'], it.next(1))
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertRaisesTwice(StopIteration, it.next, 1)
|
||||||
|
|
||||||
|
a = ['1', '2']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqual(['1'], it.next(1))
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqual(['2'], it.next(1))
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertRaisesTwice(StopIteration, it.next, 1)
|
||||||
|
|
||||||
|
def test_next_with_zero(self):
|
||||||
|
a = []
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertRaisesTwice(StopIteration, it.next, 0)
|
||||||
|
|
||||||
|
a = ['1']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([], it.next, 0)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([], it.next, 0)
|
||||||
|
|
||||||
|
a = ['1', '2']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([], it.next, 0)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([], it.next, 0)
|
||||||
|
|
||||||
|
def test_peek_with_multi(self):
|
||||||
|
a = []
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([it.sentinel, it.sentinel], it.peek, 2)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
|
||||||
|
a = ['1']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['1', it.sentinel], it.peek, 2)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['1', it.sentinel, it.sentinel], it.peek, 3)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
|
||||||
|
a = ['1', '2']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['1', '2'], it.peek, 2)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['1', '2', it.sentinel], it.peek, 3)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['1', '2', it.sentinel, it.sentinel], it.peek, 4)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
|
||||||
|
a = ['1', '2', '3']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['1', '2'], it.peek, 2)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['1', '2', '3'], it.peek, 3)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['1', '2', '3', it.sentinel], it.peek, 4)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqual('1', it.next())
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['2', '3'], it.peek, 2)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['2', '3', it.sentinel], it.peek, 3)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['2', '3', it.sentinel, it.sentinel], it.peek, 4)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
|
||||||
|
def test_peek_with_none(self):
|
||||||
|
a = []
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(it.sentinel, it.peek)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
|
||||||
|
a = ['1']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice('1', it.peek)
|
||||||
|
self.assertEqual('1', it.next())
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(it.sentinel, it.peek)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
|
||||||
|
a = ['1', '2']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice('1', it.peek)
|
||||||
|
self.assertEqual('1', it.next())
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice('2', it.peek)
|
||||||
|
self.assertEqual('2', it.next())
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(it.sentinel, it.peek)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
|
||||||
|
def test_peek_with_one(self):
|
||||||
|
a = []
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([it.sentinel], it.peek, 1)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
|
||||||
|
a = ['1']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['1'], it.peek, 1)
|
||||||
|
self.assertEqual('1', it.next())
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([it.sentinel], it.peek, 1)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
|
||||||
|
a = ['1', '2']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['1'], it.peek, 1)
|
||||||
|
self.assertEqual('1', it.next())
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice(['2'], it.peek, 1)
|
||||||
|
self.assertEqual('2', it.next())
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([it.sentinel], it.peek, 1)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
|
||||||
|
def test_peek_with_zero(self):
|
||||||
|
a = []
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertFalseTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([], it.peek, 0)
|
||||||
|
|
||||||
|
a = ['1']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([], it.peek, 0)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([], it.peek, 0)
|
||||||
|
|
||||||
|
a = ['1', '2']
|
||||||
|
it = peek_iter(a)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([], it.peek, 0)
|
||||||
|
self.assertTrueTwice(it.has_next)
|
||||||
|
self.assertEqualTwice([], it.peek, 0)
|
||||||
|
|
||||||
|
|
||||||
|
class ModifyIterTest(BaseIteratorsTest):
|
||||||
|
def test_init_with_sentinel_args(self):
|
||||||
|
a = iter(['1', '2', '3', 'DONE'])
|
||||||
|
sentinel = 'DONE'
|
||||||
|
|
||||||
|
def get_next():
|
||||||
|
return next(a)
|
||||||
|
it = modify_iter(get_next, sentinel, int)
|
||||||
|
expected = [1, 2, 3]
|
||||||
|
self.assertEqual(expected, [i for i in it])
|
||||||
|
|
||||||
|
def test_init_with_sentinel_kwargs(self):
|
||||||
|
a = iter([1, 2, 3, 4])
|
||||||
|
sentinel = 4
|
||||||
|
|
||||||
|
def get_next():
|
||||||
|
return next(a)
|
||||||
|
it = modify_iter(get_next, sentinel, modifier=str)
|
||||||
|
expected = ['1', '2', '3']
|
||||||
|
self.assertEqual(expected, [i for i in it])
|
||||||
|
|
||||||
|
def test_modifier_default(self):
|
||||||
|
a = ['', ' ', ' a ', 'b ', ' c', ' ', '']
|
||||||
|
it = modify_iter(a)
|
||||||
|
expected = ['', ' ', ' a ', 'b ', ' c', ' ', '']
|
||||||
|
self.assertEqual(expected, [i for i in it])
|
||||||
|
|
||||||
|
def test_modifier_not_callable(self):
|
||||||
|
self.assertRaises(TypeError, modify_iter, [1], modifier='not_callable')
|
||||||
|
|
||||||
|
def test_modifier_rstrip(self):
|
||||||
|
a = ['', ' ', ' a ', 'b ', ' c', ' ', '']
|
||||||
|
it = modify_iter(a, modifier=lambda s: s.rstrip())
|
||||||
|
expected = ['', '', ' a', 'b', ' c', '', '']
|
||||||
|
self.assertEqual(expected, [i for i in it])
|
||||||
|
|
||||||
|
def test_modifier_rstrip_unicode(self):
|
||||||
|
a = [u'', u' ', u' a ', u'b ', u' c', u' ', u'']
|
||||||
|
it = modify_iter(a, modifier=lambda s: s.rstrip())
|
||||||
|
expected = [u'', u'', u' a', u'b', u' c', u'', u'']
|
||||||
|
self.assertEqual(expected, [i for i in it])
|
Loading…
Reference in New Issue
Block a user