From 953c19d641b3a3385515cd7ecd25599a716146bd Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 5 Sep 2022 17:56:44 -0500 Subject: [PATCH 1/2] ci(pytest): Ignore doctest (-p no:doctest) --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 0af1ef9..c08bde6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -15,7 +15,7 @@ sections = FUTURE,STDLIB,PYTEST,THIRDPARTY,FIRSTPARTY,LOCALFOLDER line_length = 88 [tool:pytest] -addopts = --tb=short --no-header --showlocals --doctest-modules +addopts = --tb=short --no-header --showlocals -p no:doctest doctest_optionflags = ELLIPSIS NORMALIZE_WHITESPACE testpaths = tests From 5f6cc1c361e00947940c263653224aaa26bbea25 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 5 Sep 2022 17:57:09 -0500 Subject: [PATCH 2/2] refactor(pytest-doctest-docutils): Make easier to run without options --- src/pytest_doctest_docutils.py | 57 +++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/src/pytest_doctest_docutils.py b/src/pytest_doctest_docutils.py index 38a8184..4d091e2 100644 --- a/src/pytest_doctest_docutils.py +++ b/src/pytest_doctest_docutils.py @@ -17,11 +17,10 @@ import types from io import StringIO from pathlib import Path -from typing import TYPE_CHECKING, Any, Iterable, Optional, Tuple, Type +from typing import TYPE_CHECKING, Any, Dict, Iterable, Optional, Tuple, Type import pytest -import _pytest from _pytest import outcomes from _pytest.outcomes import OutcomeException @@ -43,6 +42,8 @@ def pytest_configure(config: pytest.Config) -> None: Todo: Find a way to make these plugins cooperate without collecting twice. """ + setup() + if config.pluginmanager.has_plugin("doctest"): config.pluginmanager.set_blocked("doctest") @@ -65,7 +66,11 @@ def pytest_collect_file( def _is_doctest(config: pytest.Config, path: Path, parent: pytest.Collector) -> bool: if path.suffix in (".rst", ".md") and parent.session.isinitpath(path): return True - globs = config.getoption("doctestglob") or ["*.rst", "*.md"] + globs = config.getoption( + "doctestglob", + default=["*.rst", "*.md"], + skip=True, + ) for glob in globs: if path.match(path_pattern=glob): return True @@ -181,26 +186,38 @@ def _DocTestRunner__patched_linecache_getlines( class DocTestDocutilsFile(pytest.Module): def collect(self) -> Iterable["DoctestItem"]: - setup() + import _pytest.doctest + from _pytest.doctest import DoctestItem - encoding = self.config.getini("doctest_encoding") + try: + encoding = self.config.getini("doctest_encoding") + except (KeyError, ValueError): + encoding = "utf-8" text = self.fspath.read_text(encoding) # Uses internal doctest module parsing mechanism. finder = DocutilsDocTestFinder() - optionflags = _pytest.doctest.get_optionflags(self) # type: ignore + try: + optionflags = _pytest.doctest.get_optionflags(self) # type: ignore + except ValueError: + optionflags = 0 + + try: + continue_on_failure = ( + _pytest.doctest._get_continue_on_failure( # type:ignore + self.config + ) + ) + except ValueError: + continue_on_failure = True runner = _get_runner( verbose=False, optionflags=optionflags, checker=_pytest.doctest._get_checker(), - continue_on_failure=_pytest.doctest._get_continue_on_failure( # type:ignore - self.config - ), + continue_on_failure=continue_on_failure, ) - from _pytest.doctest import DoctestItem - for test in finder.find( text, str(self.fspath), @@ -209,3 +226,21 @@ def collect(self) -> Iterable["DoctestItem"]: yield DoctestItem.from_parent( self, name=test.name, runner=runner, dtest=test # type: ignore ) + + +@pytest.fixture(scope="session") +def doctest_namespace() -> Dict[str, Any]: + """Fixture that returns a :py:class:`dict` that will be injected into the + namespace of doctests. + + Usually this fixture is used in conjunction with another ``autouse`` fixture: + + .. code-block:: python + + @pytest.fixture(autouse=True) + def add_np(doctest_namespace): + doctest_namespace["np"] = numpy + + For more details: :ref:`doctest_namespace`. + """ + return {}