Skip to content

Commit 728e6dd

Browse files
committed
Support doctest testsetup (#186)
1 parent 8d5404e commit 728e6dd

File tree

7 files changed

+87
-3
lines changed

7 files changed

+87
-3
lines changed

docs/src/about.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ Locally defined custom block parsers in :confval:`codeautolink_custom_blocks`
7979
cannot be passed to Pickle, which prevents parallel Sphinx builds.
8080
Please consider using an importable function instead.
8181

82+
Priority
83+
********
84+
The extension parses code blocks in the ``doctree-read`` Sphinx event.
85+
The priority is set to 490 to catch nodes removed by ``sphinx.ext.doctest``
86+
(priority 500). In other cases the priority of the extension is default.
87+
8288
Copying code blocks
8389
-------------------
8490
If you feel like code links make copying code a bit more difficult,

docs/src/examples.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,9 @@ activating the extension::
224224
]
225225

226226
``doctest`` and ``testcode`` blocks now work as expected.
227-
However, any test setup and teardown code is not taken into account.
227+
Code in :rst:dir:`testsetup` is considered to be the first block
228+
:rst:dir:`autolink-preface` before each matching test group.
229+
However, `skipif` is not supported.
228230

229231
.. doctest::
230232

docs/src/release_notes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ These release notes are based on
88
sphinx-codeautolink adheres to
99
`Semantic Versioning <https://semver.org>`_.
1010

11+
Unreleased
12+
----------
13+
- Support :rst:dir:`testsetup` from ``sphinx.ext.doctest`` as another
14+
type of preface (:issue:`186`)
15+
1116
0.17.1 (2025-02-24)
1217
-------------------
1318
- Add translations via i18n (:issue:`164`)

src/sphinx_codeautolink/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def setup(app: Sphinx):
6666

6767
app.connect("builder-inited", state.build_inited)
6868
app.connect("autodoc-process-docstring", state.autodoc_process_docstring)
69-
app.connect("doctree-read", state.parse_blocks)
69+
app.connect("doctree-read", state.parse_blocks, priority=490)
7070
app.connect("env-merge-info", state.merge_environments)
7171
app.connect("env-purge-doc", state.purge_doc_from_environment)
7272
app.connect("env-updated", state.create_references)

src/sphinx_codeautolink/extension/block.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ def __init__(
125125
self.global_preface = global_preface
126126
self.file_preface = []
127127
self.prefaces = []
128+
self.doctest_preface: dict[str, list[str]] = {}
128129
self.transformers = BUILTIN_BLOCKS.copy()
129130
self.transformers.update(custom_blocks)
130131
self.valid_blocks = self.transformers.keys()
@@ -198,10 +199,21 @@ def depart_section(self, node) -> None:
198199
"""Pop latest title."""
199200
self.title_stack.pop()
200201

201-
def visit_doctest_block(self, node):
202+
def visit_doctest_block(self, node: nodes.doctest_block):
202203
"""Visit a Python doctest block."""
203204
return self.parse_source(node, "pycon")
204205

206+
def visit_comment(self, node: nodes.comment):
207+
"""Visit an ext.doctest setup block."""
208+
if node.get("testnodetype") == "testsetup":
209+
groups = node["groups"]
210+
lines = [ln for c in node.children for ln in c.astext().split("\n")]
211+
for g in groups:
212+
if g == "*":
213+
self.doctest_preface = {"*": lines}
214+
else:
215+
self.doctest_preface[g] = lines
216+
205217
def visit_literal_block(self, node: nodes.literal_block):
206218
"""Visit a generic literal block."""
207219
return self.parse_source(node, node.get("language", self.highlight_lang))
@@ -213,6 +225,15 @@ def parse_source( # noqa: C901,PLR0912
213225
prefaces = self.prefaces
214226
self.prefaces = []
215227

228+
if node.get("testnodetype") == "doctest":
229+
groups = node["groups"]
230+
doctest_prefaces = [
231+
ln
232+
for g in groups
233+
for ln in self.doctest_preface.get(g, self.doctest_preface.get("*", []))
234+
]
235+
prefaces = doctest_prefaces + prefaces
236+
216237
skip = self.skip
217238
if skip == "next":
218239
self.skip = None
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
test_project.bar
2+
tp.bar
3+
test.Foo
4+
# split
5+
extensions.append("sphinx.ext.doctest")
6+
# split
7+
Test project
8+
============
9+
10+
.. testsetup::
11+
12+
import test_project
13+
14+
.. doctest::
15+
16+
>>> test_project.bar()
17+
18+
.. testsetup:: *
19+
20+
.. doctest::
21+
22+
>>> test_project.Foo()
23+
24+
.. testsetup:: thisgroup
25+
26+
import test_project as tp
27+
28+
import test_project as test
29+
30+
.. doctest:: thisgroup
31+
32+
>>> tp.bar()
33+
>>> test.Foo()
34+
35+
.. automodule:: test_project
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# split
2+
extensions.append("sphinx.ext.doctest")
3+
# split
4+
Test project
5+
============
6+
7+
.. testsetup:: specificgroup
8+
9+
import test_project
10+
11+
.. doctest::
12+
13+
>>> test_project.bar()
14+
15+
.. automodule:: test_project

0 commit comments

Comments
 (0)