@@ -12,9 +12,11 @@
from docutils import nodes
from docutils.nodes import Element, Node, Text
+from docutils.statemachine import StringList
import sphinx
from sphinx import addnodes
+from sphinx.directives import ObjectDescription
from sphinx.environment import BuildEnvironment
from sphinx.roles import XRefRole
from sphinx.util import docfields
@@ -28,6 +30,7 @@
MAKE_XREF_WORKAROUND = sphinx.version_info[:3] < (4, 1, 0)
+SOURCE_LOCATION_FIX = (5, 3, 0) <= sphinx.version_info[:3] < (6, 2, 0)
space_node: Callable[[str], Node]
@@ -156,3 +159,33 @@ class CompatTypedField(CompatFieldMixin, docfields.TypedField):
Field = CompatField
GroupedField = CompatGroupedField
TypedField = CompatTypedField
+
+
+class ParserFix(ObjectDescription):
+
+ _temp_content: StringList
+ _temp_offset: int
+ _temp_node: Optional[addnodes.desc_content]
+
+ def before_content(self) -> None:
+ # Work around a sphinx bug and parse the content ourselves.
+ self._temp_content = self.content
+ self._temp_offset = self.content_offset
+ self._temp_node = None
+
+ if SOURCE_LOCATION_FIX:
+ self._temp_node = addnodes.desc_content()
+ self.state.nested_parse(
+ self.content, self.content_offset, self._temp_node
+ )
+ # Sphinx will try to parse the content block itself,
+ # Give it nothingness to parse instead.
+ self.content = StringList()
+ self.content_offset = 0
+
+ def transform_content(self, contentnode: addnodes.desc_content) -> None:
+ # Sphinx workaround: Inject our parsed content and restore state.
+ if self._temp_node:
+ contentnode += self._temp_node.children
+ self.content = self._temp_content
+ self.content_offset = self._temp_offset
@@ -21,18 +21,17 @@
from docutils import nodes
from docutils.parsers.rst import directives
-from docutils.statemachine import StringList
from collapse import CollapseNode
from compat import (
Field,
GroupedField,
+ ParserFix,
TypedField,
keyword_node,
nested_parse,
space_node,
)
-import sphinx
from sphinx import addnodes
from sphinx.addnodes import desc_signature, pending_xref
from sphinx.directives import ObjectDescription
@@ -170,7 +169,7 @@ def since_validator(param: str) -> str:
Signature = str
-class QAPIObject(ObjectDescription[Signature]):
+class QAPIObject(ParserFix, ObjectDescription[Signature]):
"""
Description of a generic QAPI object.
@@ -436,31 +435,14 @@ def _validate_field(self, field: nodes.field) -> None:
)
logger.warning(msg, location=field)
- def before_content(self) -> None:
- # Work around a sphinx bug and parse the content ourselves.
- self._temp_content = self.content
- self._temp_offset = self.content_offset
- self._temp_node = None
-
- if (5, 3, 0) <= sphinx.version_info[:3] < (6, 2, 0):
- self._temp_node = addnodes.desc_content()
- self.state.nested_parse(
- self.content, self.content_offset, self._temp_node
- )
- # Sphinx will try to parse the content block itself,
- # Give it nothingness to parse instead.
- self.content = StringList()
- self.content_offset = 0
-
def transform_content(self, contentnode: addnodes.desc_content) -> None:
+ # This hook runs after before_content and the nested parse, but
+ # before the DocFieldTransformer is executed.
+ super().transform_content(contentnode)
+
+ # Bookmark this content_node for later use in after_content().
self.content_node = contentnode
- # Sphinx workaround: Inject our parsed content and restore state.
- if self._temp_node:
- contentnode += self._temp_node.children
- self.content = self._temp_content
- self.content_offset = self._temp_offset
-
self._add_infopips(contentnode)
self._merge_adjoining_field_lists(contentnode)
Signed-off-by: John Snow <jsnow@redhat.com> --- docs/sphinx/compat.py | 33 +++++++++++++++++++++++++++++++++ docs/sphinx/qapi-domain.py | 32 +++++++------------------------- 2 files changed, 40 insertions(+), 25 deletions(-)