Skip to content

Commit 3509107

Browse files
authored
pytest doctest docutils: Plugin tests, disable doctest on startup (#3)
2 parents 153e9e1 + ef67558 commit 3509107

File tree

2 files changed

+191
-2
lines changed

2 files changed

+191
-2
lines changed

src/pytest_doctest_docutils.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,30 @@
2323

2424
import _pytest
2525
from _pytest import outcomes
26-
from _pytest.doctest import DoctestItem
2726
from _pytest.outcomes import OutcomeException
2827

2928
from doctest_docutils import DocutilsDocTestFinder, setup
3029

3130
if TYPE_CHECKING:
3231
from doctest import _Out
3332

33+
from _pytest.doctest import DoctestItem
34+
3435
logger = logging.getLogger(__name__)
3536

3637
# Lazy definition of runner class
3738
RUNNER_CLASS = None
3839

3940

41+
def pytest_configure(config: pytest.Config) -> None:
42+
"""Disable pytest.doctest to prevent running tests twice.
43+
44+
Todo: Find a way to make these plugins cooperate without collecting twice.
45+
"""
46+
if config.pluginmanager.has_plugin("doctest"):
47+
config.pluginmanager.set_blocked("doctest")
48+
49+
4050
def pytest_unconfigure() -> None:
4151
global RUNNER_CLASS
4252

@@ -170,7 +180,7 @@ def _DocTestRunner__patched_linecache_getlines(
170180

171181

172182
class DocTestDocutilsFile(pytest.Module):
173-
def collect(self) -> Iterable[DoctestItem]:
183+
def collect(self) -> Iterable["DoctestItem"]:
174184
setup()
175185

176186
encoding = self.config.getini("doctest_encoding")
@@ -189,6 +199,7 @@ def collect(self) -> Iterable[DoctestItem]:
189199
self.config
190200
),
191201
)
202+
from _pytest.doctest import DoctestItem
192203

193204
for test in finder.find(
194205
text,
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import pathlib
2+
import textwrap
3+
import typing as t
4+
5+
import pytest
6+
7+
import _pytest.pytester
8+
9+
FixtureFileDict = t.Dict[str, str]
10+
11+
12+
class PytestDocTestFinderFixture(t.NamedTuple):
13+
# pytest
14+
test_id: str
15+
16+
# Content
17+
files: FixtureFileDict
18+
tests_found: int
19+
20+
21+
FIXTURES = [
22+
#
23+
# Docutils
24+
#
25+
PytestDocTestFinderFixture(
26+
test_id="reST-doctest_block",
27+
files={
28+
"example.rst": textwrap.dedent(
29+
"""
30+
>>> 4 + 4
31+
8
32+
"""
33+
)
34+
},
35+
tests_found=1,
36+
),
37+
PytestDocTestFinderFixture(
38+
test_id="reST-doctest_directive",
39+
files={
40+
"example.rst": textwrap.dedent(
41+
"""
42+
.. doctest::
43+
44+
>>> 4 + 4
45+
8
46+
"""
47+
)
48+
},
49+
tests_found=1,
50+
),
51+
#
52+
# Markdown / myst-parser
53+
#
54+
PytestDocTestFinderFixture(
55+
test_id="MyST-doctest_block",
56+
files={
57+
"example.md": textwrap.dedent(
58+
"""
59+
```
60+
>>> 4 + 4
61+
8
62+
```
63+
"""
64+
)
65+
},
66+
tests_found=1,
67+
),
68+
PytestDocTestFinderFixture(
69+
test_id="MyST-doctest_block-indented",
70+
files={
71+
"example.md": textwrap.dedent(
72+
"""
73+
Here's a test:
74+
75+
>>> 4 + 4
76+
8
77+
"""
78+
)
79+
},
80+
tests_found=1,
81+
),
82+
PytestDocTestFinderFixture(
83+
test_id="MyST-doctest_directive-colons",
84+
files={
85+
"example.md": textwrap.dedent(
86+
"""
87+
:::{doctest}
88+
89+
>>> 4 + 4
90+
8
91+
:::
92+
"""
93+
)
94+
},
95+
tests_found=1,
96+
),
97+
PytestDocTestFinderFixture(
98+
test_id="MyST-doctest_directive-backticks",
99+
files={
100+
"example.md": textwrap.dedent(
101+
"""
102+
```{doctest}
103+
104+
>>> 4 + 4
105+
8
106+
```
107+
"""
108+
)
109+
},
110+
tests_found=1,
111+
),
112+
PytestDocTestFinderFixture(
113+
test_id="MyST-doctest_directive-eval-rst-colons",
114+
files={
115+
"example.md": textwrap.dedent(
116+
"""
117+
:::{eval-rst}
118+
119+
.. doctest::
120+
121+
>>> 4 + 4
122+
8
123+
:::
124+
"""
125+
)
126+
},
127+
tests_found=1,
128+
),
129+
PytestDocTestFinderFixture(
130+
test_id="MyST-doctest_directive-eval-rst-backticks",
131+
files={
132+
"example.md": textwrap.dedent(
133+
"""
134+
```{eval-rst}
135+
136+
.. doctest::
137+
138+
>>> 4 + 4
139+
8
140+
```
141+
"""
142+
)
143+
},
144+
tests_found=1,
145+
),
146+
]
147+
148+
149+
@pytest.mark.parametrize(
150+
PytestDocTestFinderFixture._fields, FIXTURES, ids=[f.test_id for f in FIXTURES]
151+
)
152+
def test_pluginDocutilsDocTestFinder(
153+
pytester: _pytest.pytester.Pytester,
154+
tmp_path: pathlib.Path,
155+
monkeypatch: pytest.MonkeyPatch,
156+
test_id: str,
157+
files: FixtureFileDict,
158+
tests_found: int,
159+
) -> None:
160+
# Initialize variables
161+
pytester.plugins = ["pytest_doctest_docutils"]
162+
pytester.makefile(".ini", pytest="[pytest]\naddopts=-p no:doctest -vv\n")
163+
tests_path = tmp_path / "tests"
164+
first_test_key = list(files.keys())[0]
165+
first_test_filename = str(tests_path / first_test_key)
166+
167+
# Setup: Files
168+
tests_path.mkdir()
169+
for file_name, text in files.items():
170+
rst_file = tests_path / file_name
171+
rst_file.write_text(
172+
text,
173+
encoding="utf-8",
174+
)
175+
176+
# Test
177+
result = pytester.runpytest(str(first_test_filename))
178+
result.assert_outcomes(passed=tests_found)

0 commit comments

Comments
 (0)