Fixed possible incorrect indentation in generated documentation.

Closes #299.
This commit is contained in:
Ashley Whetter 2021-07-31 18:06:12 -07:00
parent 354535190c
commit 7d7f042805
8 changed files with 51 additions and 11 deletions

View File

@ -3,6 +3,16 @@ Changelog
Versions follow `Semantic Versioning <https://semver.org/>`_ (``<major>.<minor>.<patch>``).
v1.8.3 (TBC)
-------------------
Bug Fixes
^^^^^^^^^
* `#299 <https://github.com/readthedocs/sphinx-autoapi/issues/299>`: (Python)
Fixed incorrect indentation in generated documentation when a class with no
constructor has a summary line spanning multiple lines.
v1.8.2 (2021-07-26)
-------------------

View File

@ -8,7 +8,6 @@ import sphinx
import sphinx.util
from sphinx.util.console import darkgreen, bold
from sphinx.util.osutil import ensuredir
from sphinx.util.docstrings import prepare_docstring
import sphinx.util.logging
import unidecode
@ -190,7 +189,7 @@ class SphinxMapperBase:
)
def _wrapped_prepare(value):
return "\n".join(prepare_docstring(value))
return value
self.jinja_env.filters["prepare_docstring"] = _wrapped_prepare
if self.app.config.autoapi_prepare_jinja_env:

View File

@ -389,7 +389,8 @@ class PythonSphinxMapper(SphinxMapperBase):
# Some objects require children to establish their docstring
# or type annotations (eg classes with inheritance),
# so do this after all children have been created.
lines = sphinx.util.docstrings.prepare_docstring(obj.docstring)
lines = obj.docstring.splitlines()
lines.append("") # Add back the trailing newline that .splitlines removes
if lines and "autodoc-process-docstring" in self.app.events.events:
self.app.emit(
"autodoc-process-docstring", cls.type, obj.name, None, None, lines

View File

@ -49,7 +49,8 @@ class PythonPythonMapper(PythonMapperBase):
# Optional
self.children = []
self.docstring = obj["doc"]
self._docstring = obj["doc"]
self._docstring_resolved = False
self.imported = "original_path" in obj
self.inherited = obj.get("inherited", False)
"""Whether this was inherited from an ancestor of the parent class.
@ -79,6 +80,7 @@ class PythonPythonMapper(PythonMapperBase):
@docstring.setter
def docstring(self, value):
self._docstring = value
self._docstring_resolved = True
@property
def is_undoc_member(self):
@ -386,9 +388,9 @@ class PythonClass(PythonPythonMapper):
@property
def docstring(self):
docstring = super(PythonClass, self).docstring
docstring = super().docstring
if self._class_content in ("both", "init"):
if not self._docstring_resolved and self._class_content in ("both", "init"):
constructor_docstring = self.constructor_docstring
if constructor_docstring:
@ -401,7 +403,7 @@ class PythonClass(PythonPythonMapper):
@docstring.setter
def docstring(self, value):
self._docstring = value
super(PythonClass, self.__class__).docstring.fset(self, value)
@property
def methods(self):

View File

@ -4,9 +4,15 @@ import os
import astroid
import astroid.builder
import sphinx.util.docstrings
from . import astroid_utils
def _prepare_docstring(doc):
return "\n".join(sphinx.util.docstrings.prepare_docstring(doc))
class Parser:
def __init__(self):
self._name_stack = []
@ -72,7 +78,7 @@ class Parser:
"type": type_,
"name": target,
"full_name": self._get_full_name(target),
"doc": doc,
"doc": _prepare_docstring(doc),
"value": value,
"from_line_no": node.fromlineno,
"to_line_no": node.tolineno,
@ -93,7 +99,7 @@ class Parser:
"name": node.name,
"full_name": self._get_full_name(node.name),
"bases": basenames,
"doc": astroid_utils.get_class_docstring(node),
"doc": _prepare_docstring(astroid_utils.get_class_docstring(node)),
"from_line_no": node.fromlineno,
"to_line_no": node.tolineno,
"children": [],
@ -162,7 +168,7 @@ class Parser:
"name": node.name,
"full_name": self._get_full_name(node.name),
"args": astroid_utils.get_args_info(node.args),
"doc": astroid_utils.get_func_docstring(node),
"doc": _prepare_docstring(astroid_utils.get_func_docstring(node)),
"from_line_no": node.fromlineno,
"to_line_no": node.tolineno,
"return_annotation": astroid_utils.get_return_annotation(node),
@ -218,7 +224,7 @@ class Parser:
"type": type_,
"name": node.name,
"full_name": node.name,
"doc": node.doc or "",
"doc": _prepare_docstring(node.doc or ""),
"children": [],
"file_path": path,
"encoding": node.file_encoding,

View File

@ -18,3 +18,4 @@ extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_type = "python"
autoapi_dirs = ["example"]
autoapi_file_pattern = "*.py"
autoapi_python_class_content = "both"

View File

@ -111,3 +111,20 @@ class Bar(Foo):
class ClassWithNoInit:
pass
class One:
"""One."""
def __init__(self):
"""One __init__."""
super().__init__()
class MultilineOne(One):
"""This is a naughty summary line
that exists on two lines."""
class Two(One):
"""Two."""

View File

@ -94,6 +94,10 @@ class TestSimpleModule:
assert not os.path.exists("_build/text/autoapi/method_multiline")
# Inherited constructor docstrings should be included in a merged
# (autoapi_python_class_content="both") class docstring only once.
assert example_file.count("One __init__.") == 3
index_path = "_build/text/index.txt"
with io.open(index_path, encoding="utf8") as index_handle:
index_file = index_handle.read()