Skip to content

Commit db5e7b1

Browse files
committed
fix(pytest-plugin[docs]): Fix docs build warnings from autofixtures in eval-rst
why: Two categories of warning were failing docs CI under sphinx-build -W. (1) _is_markdown_source checked the outer file's .md extension, returning True even for directives inside {eval-rst} blocks. Those directives use a docutils RST Body state whose nested_parse is pure RST — passing a {eval-rst} backtick fence to it caused spurious "Inline literal start-string without end-string" and "Unexpected indentation" warnings. The correct check is whether the directive was invoked natively by MyST, which is detectable via isinstance(directive.state, MockState). (2) The demo page documented spf_demo_fixtures twice (autofixtures:: block + doc-pytest-plugin section) without :no-index: on either, triggering 9 "duplicate object description" warnings. what: - Replace _is_markdown_source with _is_native_myst (MockState isinstance check); eval-rst-embedded directives now skip the {eval-rst} wrap - Add no_index parameter to _render_autofixtures_nodes to emit :no-index: on each generated autofixture directive when requested - Add "no-index" flag option to AutofixturesDirective; pass it through to _render_autofixtures_nodes - Add :no-index: to the demo autofixtures:: spf_demo_fixtures eval-rst block so doc-pytest-plugin remains the canonical fixture reference - Document :no-index: option in the autofixtures options table
1 parent 71ae109 commit db5e7b1

2 files changed

Lines changed: 33 additions & 17 deletions

File tree

docs/packages/sphinx-autodoc-pytest-fixtures.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pytest_external_fixture_links = {
5050

5151
```{eval-rst}
5252
.. autofixtures:: spf_demo_fixtures
53+
:no-index:
5354
```
5455

5556
### Plugin page helper
@@ -91,6 +92,7 @@ directly:
9192
|--------|---------|-------------|
9293
| `:order:` | `"source"` | `"source"` preserves module order; `"alpha"` sorts alphabetically |
9394
| `:exclude:` | (empty) | Comma-separated fixture names to skip |
95+
| `:no-index:` | (off) | Emit descriptions without registering fixtures in the domain index; use when the same module is documented twice on one page |
9496

9597
#### autofixture-index options
9698

packages/sphinx-autodoc-pytest-fixtures/src/sphinx_autodoc_pytest_fixtures/_directives.py

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from __future__ import annotations
44

55
import importlib
6-
import pathlib
76
import typing as t
87

98
from docutils import nodes
@@ -108,12 +107,34 @@ def _note_module_dependency(document: nodes.document, module: t.Any) -> None:
108107
env.note_dependency(module.__file__)
109108

110109

110+
def _is_native_myst(directive: SphinxDirective) -> bool:
111+
"""Return ``True`` when *directive* is invoked natively by MyST-parser.
112+
113+
MyST-parser passes a ``MockState`` to directives it invokes directly,
114+
whose ``nested_parse`` renders Markdown rather than RST. In that context
115+
the generated ``autofixture`` RST content must be wrapped in an
116+
``{eval-rst}`` fence so that MyST's nested renderer processes it as RST.
117+
118+
Directives invoked inside an ``{eval-rst}`` block use a regular docutils
119+
``Body`` state (RST ``nested_parse``), so no wrapping is needed —
120+
passing a backtick fence there would produce spurious ``[docutils]``
121+
inline-literal warnings.
122+
"""
123+
try:
124+
from myst_parser.mocking import MockState # noqa: PLC0415
125+
126+
return isinstance(directive.state, MockState)
127+
except ImportError:
128+
return False
129+
130+
111131
def _render_autofixtures_nodes(
112132
directive: SphinxDirective,
113133
*,
114134
modname: str,
115135
entries: list[tuple[str, str, t.Any]],
116136
order: str = "source",
137+
no_index: bool = False,
117138
) -> list[nodes.Node]:
118139
"""Render ``autofixture`` directives into doctree nodes.
119140
@@ -127,6 +148,10 @@ def _render_autofixtures_nodes(
127148
Public fixture entries as ``(attr_name, public_name, fixture_obj)``.
128149
order : str, optional
129150
``"source"`` keeps module order; ``"alpha"`` sorts by public name.
151+
no_index : bool, optional
152+
When ``True``, each generated ``autofixture`` directive gets
153+
``:no-index:`` so the fixtures are described but not registered in
154+
the Sphinx domain index.
130155
131156
Returns
132157
-------
@@ -139,10 +164,12 @@ def _render_autofixtures_nodes(
139164
lines: list[str] = []
140165
for _attr_name, public_name, _value in entries:
141166
lines.append(f".. autofixture:: {modname}.{public_name}")
167+
if no_index:
168+
lines.append(" :no-index:")
142169
lines.append("")
143170

144171
content = "\n".join(lines).strip()
145-
if _is_markdown_source(directive):
172+
if _is_native_myst(directive):
146173
content = f"```{{eval-rst}}\n{content}\n```"
147174

148175
return directive.parse_text_to_nodes(
@@ -151,21 +178,6 @@ def _render_autofixtures_nodes(
151178
)
152179

153180

154-
def _is_markdown_source(directive: SphinxDirective) -> bool:
155-
"""Return ``True`` when the current document source is Markdown/MyST."""
156-
source, _line = directive.get_source_info()
157-
if not source:
158-
source = getattr(directive.state.document, "current_source", "")
159-
if not source:
160-
return False
161-
162-
return pathlib.Path(source).suffix.lower() in {
163-
".md",
164-
".markdown",
165-
".myst",
166-
}
167-
168-
169181
class PyFixtureDirective(PyFunction):
170182
"""Sphinx directive for documenting pytest fixtures: ``.. py:fixture::``.
171183
@@ -590,6 +602,7 @@ class AutofixturesDirective(SphinxDirective):
590602
option_spec: t.ClassVar[dict[str, t.Any]] = {
591603
"order": directives.unchanged,
592604
"exclude": directives.unchanged,
605+
"no-index": directives.flag,
593606
}
594607

595608
def run(self) -> list[nodes.Node]:
@@ -618,6 +631,7 @@ def run(self) -> list[nodes.Node]:
618631
modname=modname,
619632
entries=entries,
620633
order=order,
634+
no_index="no-index" in self.options,
621635
)
622636

623637

0 commit comments

Comments
 (0)