From 69cee504957ec938f8ea02ecf8e3beac14cb4383 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 5 Sep 2022 16:09:15 -0500 Subject: [PATCH 1/3] chore(pdd): Disable doctest to prevent collecting twice over --- src/pytest_doctest_docutils.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/pytest_doctest_docutils.py b/src/pytest_doctest_docutils.py index 8ca4292..c228fc5 100644 --- a/src/pytest_doctest_docutils.py +++ b/src/pytest_doctest_docutils.py @@ -23,20 +23,38 @@ import _pytest from _pytest import outcomes -from _pytest.doctest import DoctestItem from _pytest.outcomes import OutcomeException +from _pytest.warning_types import PytestConfigWarning from doctest_docutils import DocutilsDocTestFinder, setup if TYPE_CHECKING: from doctest import _Out + from _pytest.doctest import DoctestItem + logger = logging.getLogger(__name__) # Lazy definition of runner class RUNNER_CLASS = None +def pytest_configure(config: pytest.Config) -> None: + """Disable pytest.doctest to prevent running tests twice. + + Todo: Find a way to make these plugins cooperate without collecting twice. + """ + if config.pluginmanager.has_plugin("doctest"): + message = ( + "`pytest-doctest-docutils` is incompatible with `doctest`. " + "Please disable `doctest` via `-p no:doctest` in order to use " + "`pytest-doctest-docutils`." + ) + + config.pluginmanager.set_blocked("doctest") + config.issue_config_time_warning(PytestConfigWarning(message), stacklevel=3) + + def pytest_unconfigure() -> None: global RUNNER_CLASS @@ -170,7 +188,7 @@ def _DocTestRunner__patched_linecache_getlines( class DocTestDocutilsFile(pytest.Module): - def collect(self) -> Iterable[DoctestItem]: + def collect(self) -> Iterable["DoctestItem"]: setup() encoding = self.config.getini("doctest_encoding") @@ -189,6 +207,7 @@ def collect(self) -> Iterable[DoctestItem]: self.config ), ) + from _pytest.doctest import DoctestItem for test in finder.find( text, From aca7cac6a38ea23d41275f062ac500e7938bb008 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 5 Sep 2022 16:13:59 -0500 Subject: [PATCH 2/3] tests(pytest-doctest-docutils): Add initial tests --- tests/test_pytest_doctest_docutils.py | 178 ++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 tests/test_pytest_doctest_docutils.py diff --git a/tests/test_pytest_doctest_docutils.py b/tests/test_pytest_doctest_docutils.py new file mode 100644 index 0000000..c517f62 --- /dev/null +++ b/tests/test_pytest_doctest_docutils.py @@ -0,0 +1,178 @@ +import pathlib +import textwrap +import typing as t + +import pytest + +import _pytest.pytester + +FixtureFileDict = t.Dict[str, str] + + +class PytestDocTestFinderFixture(t.NamedTuple): + # pytest + test_id: str + + # Content + files: FixtureFileDict + tests_found: int + + +FIXTURES = [ + # + # Docutils + # + PytestDocTestFinderFixture( + test_id="reST-doctest_block", + files={ + "example.rst": textwrap.dedent( + """ +>>> 4 + 4 +8 + """ + ) + }, + tests_found=1, + ), + PytestDocTestFinderFixture( + test_id="reST-doctest_directive", + files={ + "example.rst": textwrap.dedent( + """ +.. doctest:: + + >>> 4 + 4 + 8 + """ + ) + }, + tests_found=1, + ), + # + # Markdown / myst-parser + # + PytestDocTestFinderFixture( + test_id="MyST-doctest_block", + files={ + "example.md": textwrap.dedent( + """ +``` +>>> 4 + 4 +8 +``` + """ + ) + }, + tests_found=1, + ), + PytestDocTestFinderFixture( + test_id="MyST-doctest_block-indented", + files={ + "example.md": textwrap.dedent( + """ +Here's a test: + + >>> 4 + 4 + 8 + """ + ) + }, + tests_found=1, + ), + PytestDocTestFinderFixture( + test_id="MyST-doctest_directive-colons", + files={ + "example.md": textwrap.dedent( + """ +:::{doctest} + + >>> 4 + 4 + 8 +::: + """ + ) + }, + tests_found=1, + ), + PytestDocTestFinderFixture( + test_id="MyST-doctest_directive-backticks", + files={ + "example.md": textwrap.dedent( + """ +```{doctest} + + >>> 4 + 4 + 8 +``` + """ + ) + }, + tests_found=1, + ), + PytestDocTestFinderFixture( + test_id="MyST-doctest_directive-eval-rst-colons", + files={ + "example.md": textwrap.dedent( + """ +:::{eval-rst} + + .. doctest:: + + >>> 4 + 4 + 8 +::: + """ + ) + }, + tests_found=1, + ), + PytestDocTestFinderFixture( + test_id="MyST-doctest_directive-eval-rst-backticks", + files={ + "example.md": textwrap.dedent( + """ +```{eval-rst} + + .. doctest:: + + >>> 4 + 4 + 8 +``` + """ + ) + }, + tests_found=1, + ), +] + + +@pytest.mark.parametrize( + PytestDocTestFinderFixture._fields, FIXTURES, ids=[f.test_id for f in FIXTURES] +) +def test_pluginDocutilsDocTestFinder( + pytester: _pytest.pytester.Pytester, + tmp_path: pathlib.Path, + monkeypatch: pytest.MonkeyPatch, + test_id: str, + files: FixtureFileDict, + tests_found: int, +) -> None: + # Initialize variables + pytester.plugins = ["pytest_doctest_docutils"] + pytester.makefile(".ini", pytest="[pytest]\naddopts=-p no:doctest -vv\n") + tests_path = tmp_path / "tests" + first_test_key = list(files.keys())[0] + first_test_filename = str(tests_path / first_test_key) + + # Setup: Files + tests_path.mkdir() + for file_name, text in files.items(): + rst_file = tests_path / file_name + rst_file.write_text( + text, + encoding="utf-8", + ) + + # Test + result = pytester.runpytest(str(first_test_filename)) + result.assert_outcomes(passed=tests_found) From ef6755866236a49e09ed46182ccfc52cd05ba782 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 5 Sep 2022 17:59:09 -0500 Subject: [PATCH 3/3] fix(pytest-doctest-docutils): Silently disable doctest --- src/pytest_doctest_docutils.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/pytest_doctest_docutils.py b/src/pytest_doctest_docutils.py index c228fc5..38a8184 100644 --- a/src/pytest_doctest_docutils.py +++ b/src/pytest_doctest_docutils.py @@ -24,7 +24,6 @@ import _pytest from _pytest import outcomes from _pytest.outcomes import OutcomeException -from _pytest.warning_types import PytestConfigWarning from doctest_docutils import DocutilsDocTestFinder, setup @@ -45,14 +44,7 @@ def pytest_configure(config: pytest.Config) -> None: Todo: Find a way to make these plugins cooperate without collecting twice. """ if config.pluginmanager.has_plugin("doctest"): - message = ( - "`pytest-doctest-docutils` is incompatible with `doctest`. " - "Please disable `doctest` via `-p no:doctest` in order to use " - "`pytest-doctest-docutils`." - ) - config.pluginmanager.set_blocked("doctest") - config.issue_config_time_warning(PytestConfigWarning(message), stacklevel=3) def pytest_unconfigure() -> None: