1717import types
1818from io import StringIO
1919from pathlib import Path
20- from typing import TYPE_CHECKING , Any , Iterable , Optional , Tuple , Type
20+ from typing import TYPE_CHECKING , Any , Dict , Iterable , Optional , Tuple , Type
2121
2222import pytest
2323
24- import _pytest
2524from _pytest import outcomes
2625from _pytest .outcomes import OutcomeException
2726
@@ -43,6 +42,8 @@ def pytest_configure(config: pytest.Config) -> None:
4342
4443 Todo: Find a way to make these plugins cooperate without collecting twice.
4544 """
45+ setup ()
46+
4647 if config .pluginmanager .has_plugin ("doctest" ):
4748 config .pluginmanager .set_blocked ("doctest" )
4849
@@ -65,7 +66,11 @@ def pytest_collect_file(
6566def _is_doctest (config : pytest .Config , path : Path , parent : pytest .Collector ) -> bool :
6667 if path .suffix in (".rst" , ".md" ) and parent .session .isinitpath (path ):
6768 return True
68- globs = config .getoption ("doctestglob" ) or ["*.rst" , "*.md" ]
69+ globs = config .getoption (
70+ "doctestglob" ,
71+ default = ["*.rst" , "*.md" ],
72+ skip = True ,
73+ )
6974 for glob in globs :
7075 if path .match (path_pattern = glob ):
7176 return True
@@ -181,26 +186,38 @@ def _DocTestRunner__patched_linecache_getlines(
181186
182187class DocTestDocutilsFile (pytest .Module ):
183188 def collect (self ) -> Iterable ["DoctestItem" ]:
184- setup ()
189+ import _pytest .doctest
190+ from _pytest .doctest import DoctestItem
185191
186- encoding = self .config .getini ("doctest_encoding" )
192+ try :
193+ encoding = self .config .getini ("doctest_encoding" )
194+ except (KeyError , ValueError ):
195+ encoding = "utf-8"
187196 text = self .fspath .read_text (encoding )
188197
189198 # Uses internal doctest module parsing mechanism.
190199 finder = DocutilsDocTestFinder ()
191200
192- optionflags = _pytest .doctest .get_optionflags (self ) # type: ignore
201+ try :
202+ optionflags = _pytest .doctest .get_optionflags (self ) # type: ignore
203+ except ValueError :
204+ optionflags = 0
205+
206+ try :
207+ continue_on_failure = (
208+ _pytest .doctest ._get_continue_on_failure ( # type:ignore
209+ self .config
210+ )
211+ )
212+ except ValueError :
213+ continue_on_failure = True
193214
194215 runner = _get_runner (
195216 verbose = False ,
196217 optionflags = optionflags ,
197218 checker = _pytest .doctest ._get_checker (),
198- continue_on_failure = _pytest .doctest ._get_continue_on_failure ( # type:ignore
199- self .config
200- ),
219+ continue_on_failure = continue_on_failure ,
201220 )
202- from _pytest .doctest import DoctestItem
203-
204221 for test in finder .find (
205222 text ,
206223 str (self .fspath ),
@@ -209,3 +226,21 @@ def collect(self) -> Iterable["DoctestItem"]:
209226 yield DoctestItem .from_parent (
210227 self , name = test .name , runner = runner , dtest = test # type: ignore
211228 )
229+
230+
231+ @pytest .fixture (scope = "session" )
232+ def doctest_namespace () -> Dict [str , Any ]:
233+ """Fixture that returns a :py:class:`dict` that will be injected into the
234+ namespace of doctests.
235+
236+ Usually this fixture is used in conjunction with another ``autouse`` fixture:
237+
238+ .. code-block:: python
239+
240+ @pytest.fixture(autouse=True)
241+ def add_np(doctest_namespace):
242+ doctest_namespace["np"] = numpy
243+
244+ For more details: :ref:`doctest_namespace`.
245+ """
246+ return {}
0 commit comments