@@ -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
0 commit comments