Skip to content

Commit f7ae219

Browse files
🧪 Convert normalize_doctree_xml to pytest fixture (#1090)
Converted `normalize_doctree_xml` from a standalone function to a pytest fixture. Tests no longer need to import it - they can now use it directly as a fixture parameter. ### Changes Made - [x] Converted `normalize_doctree_xml` to a pytest fixture in `tests/conftest.py` - Added `@pytest.fixture` decorator - Wrapped implementation in a callable that returns the normalize function - Maintains the same functionality and signature - [x] Removed all imports of `normalize_doctree_xml` across test files (9 files) - [x] Updated all test functions to accept `normalize_doctree_xml` as a fixture parameter - 8 test files updated - Multiple test functions per file updated - [x] Applied ruff formatting to fix pre-commit issues - Properly formatted long function signatures across multiple lines - [x] All tests passing successfully ### Files Modified 1. `tests/conftest.py` - Converted function to fixture, applied formatting 2. `tests/test_sphinx/conftest.py` - Removed import, added fixture parameter to `get_sphinx_app_doctree` 3. `tests/test_html/test_html_to_nodes.py` - Removed import, added fixture parameter 4. `tests/test_renderers/test_fixtures_docutils.py` - Removed import, added fixture parameter to 5 test functions, applied formatting 5. `tests/test_renderers/test_myst_refs.py` - Removed import, added fixture parameter 6. `tests/test_renderers/test_myst_config.py` - Removed import, added fixture parameter 7. `tests/test_renderers/test_include_directive.py` - Removed import, added fixture parameter 8. `tests/test_renderers/test_fixtures_sphinx.py` - Removed import, added fixture parameter to 11 test functions, applied formatting 9. `tests/test_sphinx/test_sphinx_builds.py` - Removed import, added fixture parameter --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: chrisjsewell <2997570+chrisjsewell@users.noreply.github.com>
1 parent 8877b76 commit f7ae219

File tree

9 files changed

+109
-69
lines changed

9 files changed

+109
-69
lines changed

tests/conftest.py

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,61 @@
22

33
import re
44

5+
import pytest
56
from docutils import __version_info__ as docutils_version_info
67

78
DOCUTILS_0_22_PLUS = docutils_version_info >= (0, 22)
89

910

10-
def normalize_doctree_xml(text: str) -> str:
11+
@pytest.fixture
12+
def normalize_doctree_xml():
1113
"""Normalize docutils XML output for cross-version compatibility.
1214
1315
In docutils 0.22+, boolean attributes are serialized as "1"/"0"
1416
instead of "True"/"False". This function normalizes to the old format
1517
for consistent test fixtures.
1618
"""
17-
if DOCUTILS_0_22_PLUS:
18-
# Normalize new format (1/0) to old format (1/0)
19-
# Only replace when it's clearly a boolean attribute value
20-
# Pattern: attribute="1" or attribute="0"
21-
attrs = [
22-
"force",
23-
"glob",
24-
"hidden",
25-
"id_link",
26-
"includehidden",
27-
"inline",
28-
"internal",
29-
"is_div",
30-
"linenos",
31-
"multi_line_parameter_list",
32-
"multi_line_trailing_comma",
33-
"no-contents-entry",
34-
"no-index",
35-
"no-index-entry",
36-
"no-typesetting",
37-
"no-wrap",
38-
"nocontentsentry",
39-
"noindex",
40-
"noindexentry",
41-
"nowrap",
42-
"refexplicit",
43-
"refspecific",
44-
"refwarn",
45-
"sorted",
46-
"titlesonly",
47-
"toctree",
48-
"translatable",
49-
]
50-
text = re.sub(rf' ({"|".join(attrs)})="1"', r' \1="True"', text)
51-
text = re.sub(rf' ({"|".join(attrs)})="0"', r' \1="False"', text)
52-
# numbered is changed in math_block, but not in toctree, so we have to be more precise
53-
text = re.sub(r' numbered="1" xml:space', r' numbered="True" xml:space', text)
54-
return text
19+
20+
def _normalize(text: str) -> str:
21+
if DOCUTILS_0_22_PLUS:
22+
# Normalize new format (1/0) to old format (1/0)
23+
# Only replace when it's clearly a boolean attribute value
24+
# Pattern: attribute="1" or attribute="0"
25+
attrs = [
26+
"force",
27+
"glob",
28+
"hidden",
29+
"id_link",
30+
"includehidden",
31+
"inline",
32+
"internal",
33+
"is_div",
34+
"linenos",
35+
"multi_line_parameter_list",
36+
"multi_line_trailing_comma",
37+
"no-contents-entry",
38+
"no-index",
39+
"no-index-entry",
40+
"no-typesetting",
41+
"no-wrap",
42+
"nocontentsentry",
43+
"noindex",
44+
"noindexentry",
45+
"nowrap",
46+
"refexplicit",
47+
"refspecific",
48+
"refwarn",
49+
"sorted",
50+
"titlesonly",
51+
"toctree",
52+
"translatable",
53+
]
54+
text = re.sub(rf' ({"|".join(attrs)})="1"', r' \1="True"', text)
55+
text = re.sub(rf' ({"|".join(attrs)})="0"', r' \1="False"', text)
56+
# numbered is changed in math_block, but not in toctree, so we have to be more precise
57+
text = re.sub(
58+
r' numbered="1" xml:space', r' numbered="True" xml:space', text
59+
)
60+
return text
61+
62+
return _normalize

tests/test_html/test_html_to_nodes.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from myst_parser.config.main import MdParserConfig
88
from myst_parser.mdit_to_docutils.html_to_nodes import html_to_nodes
9-
from tests.conftest import normalize_doctree_xml
109

1110
FIXTURE_PATH = Path(__file__).parent
1211

@@ -30,7 +29,7 @@ def _run_directive(name: str, first_line: str, content: str, position: int):
3029

3130

3231
@pytest.mark.param_file(FIXTURE_PATH / "html_to_nodes.md")
33-
def test_html_to_nodes(file_params, mock_renderer):
32+
def test_html_to_nodes(file_params, mock_renderer, normalize_doctree_xml):
3433
output = nodes.container()
3534
output += html_to_nodes(file_params.content, line_number=0, renderer=mock_renderer)
3635
file_params.assert_expected(normalize_doctree_xml(output.pformat()), rstrip=True)

tests/test_renderers/test_fixtures_docutils.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from typing import Any
1212

1313
import pytest
14-
from conftest import normalize_doctree_xml
1514
from docutils import __version_info__ as docutils_version
1615
from docutils.core import Publisher, publish_doctree
1716
from pytest_param_files import ParamTestData
@@ -22,7 +21,9 @@
2221

2322

2423
@pytest.mark.param_file(FIXTURE_PATH / "docutil_syntax_elements.md")
25-
def test_syntax_elements(file_params: ParamTestData, monkeypatch):
24+
def test_syntax_elements(
25+
file_params: ParamTestData, monkeypatch, normalize_doctree_xml
26+
):
2627
"""Test conversion of Markdown to docutils AST (before transforms are applied)."""
2728

2829
def _apply_transforms(self):
@@ -47,7 +48,7 @@ def _apply_transforms(self):
4748

4849

4950
@pytest.mark.param_file(FIXTURE_PATH / "docutil_link_resolution.md")
50-
def test_link_resolution(file_params: ParamTestData):
51+
def test_link_resolution(file_params: ParamTestData, normalize_doctree_xml):
5152
"""Test that Markdown links resolve to the correct target, or give the correct warning."""
5253
settings = settings_from_cmdline(file_params.description)
5354
report_stream = StringIO()
@@ -70,7 +71,7 @@ def test_link_resolution(file_params: ParamTestData):
7071

7172

7273
@pytest.mark.param_file(FIXTURE_PATH / "docutil_roles.md")
73-
def test_docutils_roles(file_params: ParamTestData, monkeypatch):
74+
def test_docutils_roles(file_params: ParamTestData, monkeypatch, normalize_doctree_xml):
7475
"""Test conversion of Markdown to docutils AST (before transforms are applied)."""
7576

7677
def _apply_transforms(self):
@@ -90,7 +91,9 @@ def _apply_transforms(self):
9091

9192

9293
@pytest.mark.param_file(FIXTURE_PATH / "docutil_directives.md")
93-
def test_docutils_directives(file_params: ParamTestData, monkeypatch):
94+
def test_docutils_directives(
95+
file_params: ParamTestData, monkeypatch, normalize_doctree_xml
96+
):
9497
"""Test output of docutils directives."""
9598
if "SKIP" in file_params.description: # line-block directive not yet supported
9699
pytest.skip(file_params.description)
@@ -112,7 +115,7 @@ def _apply_transforms(self):
112115

113116

114117
@pytest.mark.param_file(FIXTURE_PATH / "docutil_syntax_extensions.txt")
115-
def test_syntax_extensions(file_params: ParamTestData):
118+
def test_syntax_extensions(file_params: ParamTestData, normalize_doctree_xml):
116119
"""The description is parsed as a docutils commandline"""
117120
settings = settings_from_cmdline(file_params.description)
118121
report_stream = StringIO()

tests/test_renderers/test_fixtures_sphinx.py

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@
1717
from sphinx_pytest.plugin import CreateDoctree
1818

1919
from myst_parser.mdit_to_docutils.sphinx_ import SphinxRenderer
20-
from tests.conftest import normalize_doctree_xml
2120

2221
FIXTURE_PATH = Path(__file__).parent.joinpath("fixtures")
2322

2423

2524
@pytest.mark.param_file(FIXTURE_PATH / "sphinx_syntax_elements.md")
2625
def test_syntax_elements(
27-
file_params: ParamTestData, sphinx_doctree: CreateDoctree, monkeypatch
26+
file_params: ParamTestData,
27+
sphinx_doctree: CreateDoctree,
28+
monkeypatch,
29+
normalize_doctree_xml,
2830
):
2931
sphinx_doctree.set_conf({"extensions": ["myst_parser"], "show_warning_types": True})
3032

@@ -52,7 +54,9 @@ def _apply_transforms(self):
5254

5355

5456
@pytest.mark.param_file(FIXTURE_PATH / "sphinx_link_resolution.md")
55-
def test_link_resolution(file_params: ParamTestData, sphinx_doctree: CreateDoctree):
57+
def test_link_resolution(
58+
file_params: ParamTestData, sphinx_doctree: CreateDoctree, normalize_doctree_xml
59+
):
5660
sphinx_doctree.set_conf(
5761
{"extensions": ["myst_parser"], **settings_from_json(file_params.description)}
5862
)
@@ -78,7 +82,11 @@ def settings_from_json(string: str | None):
7882

7983

8084
@pytest.mark.param_file(FIXTURE_PATH / "tables.md")
81-
def test_tables(file_params: ParamTestData, sphinx_doctree_no_tr: CreateDoctree):
85+
def test_tables(
86+
file_params: ParamTestData,
87+
sphinx_doctree_no_tr: CreateDoctree,
88+
normalize_doctree_xml,
89+
):
8290
sphinx_doctree_no_tr.set_conf({"extensions": ["myst_parser"]})
8391
result = sphinx_doctree_no_tr(file_params.content, "index.md")
8492
file_params.assert_expected(
@@ -88,7 +96,9 @@ def test_tables(file_params: ParamTestData, sphinx_doctree_no_tr: CreateDoctree)
8896

8997
@pytest.mark.param_file(FIXTURE_PATH / "directive_options.md")
9098
def test_directive_options(
91-
file_params: ParamTestData, sphinx_doctree_no_tr: CreateDoctree
99+
file_params: ParamTestData,
100+
sphinx_doctree_no_tr: CreateDoctree,
101+
normalize_doctree_xml,
92102
):
93103
sphinx_doctree_no_tr.set_conf({"extensions": ["myst_parser"]})
94104
result = sphinx_doctree_no_tr(file_params.content, "index.md")
@@ -99,7 +109,9 @@ def test_directive_options(
99109

100110
@pytest.mark.param_file(FIXTURE_PATH / "sphinx_directives.md")
101111
def test_sphinx_directives(
102-
file_params: ParamTestData, sphinx_doctree_no_tr: CreateDoctree
112+
file_params: ParamTestData,
113+
sphinx_doctree_no_tr: CreateDoctree,
114+
normalize_doctree_xml,
103115
):
104116
# TODO fix skipped directives
105117
# TODO test domain directives
@@ -117,7 +129,11 @@ def test_sphinx_directives(
117129

118130

119131
@pytest.mark.param_file(FIXTURE_PATH / "sphinx_roles.md")
120-
def test_sphinx_roles(file_params: ParamTestData, sphinx_doctree_no_tr: CreateDoctree):
132+
def test_sphinx_roles(
133+
file_params: ParamTestData,
134+
sphinx_doctree_no_tr: CreateDoctree,
135+
normalize_doctree_xml,
136+
):
121137
if file_params.title.startswith("SKIP"):
122138
pytest.skip(file_params.title)
123139

@@ -140,7 +156,11 @@ def test_sphinx_roles(file_params: ParamTestData, sphinx_doctree_no_tr: CreateDo
140156

141157

142158
@pytest.mark.param_file(FIXTURE_PATH / "dollarmath.md")
143-
def test_dollarmath(file_params: ParamTestData, sphinx_doctree_no_tr: CreateDoctree):
159+
def test_dollarmath(
160+
file_params: ParamTestData,
161+
sphinx_doctree_no_tr: CreateDoctree,
162+
normalize_doctree_xml,
163+
):
144164
sphinx_doctree_no_tr.set_conf(
145165
{"extensions": ["myst_parser"], "myst_enable_extensions": ["dollarmath"]}
146166
)
@@ -152,7 +172,10 @@ def test_dollarmath(file_params: ParamTestData, sphinx_doctree_no_tr: CreateDoct
152172

153173
@pytest.mark.param_file(FIXTURE_PATH / "amsmath.md")
154174
def test_amsmath(
155-
file_params: ParamTestData, sphinx_doctree_no_tr: CreateDoctree, monkeypatch
175+
file_params: ParamTestData,
176+
sphinx_doctree_no_tr: CreateDoctree,
177+
monkeypatch,
178+
normalize_doctree_xml,
156179
):
157180
monkeypatch.setattr(SphinxRenderer, "_random_label", lambda self: "mock-uuid")
158181
sphinx_doctree_no_tr.set_conf(
@@ -166,7 +189,10 @@ def test_amsmath(
166189

167190
@pytest.mark.param_file(FIXTURE_PATH / "containers.md")
168191
def test_containers(
169-
file_params: ParamTestData, sphinx_doctree_no_tr: CreateDoctree, monkeypatch
192+
file_params: ParamTestData,
193+
sphinx_doctree_no_tr: CreateDoctree,
194+
monkeypatch,
195+
normalize_doctree_xml,
170196
):
171197
monkeypatch.setattr(SphinxRenderer, "_random_label", lambda self: "mock-uuid")
172198
sphinx_doctree_no_tr.set_conf(
@@ -180,7 +206,9 @@ def test_containers(
180206

181207
@pytest.mark.param_file(FIXTURE_PATH / "eval_rst.md")
182208
def test_evalrst_elements(
183-
file_params: ParamTestData, sphinx_doctree_no_tr: CreateDoctree
209+
file_params: ParamTestData,
210+
sphinx_doctree_no_tr: CreateDoctree,
211+
normalize_doctree_xml,
184212
):
185213
sphinx_doctree_no_tr.set_conf({"extensions": ["myst_parser"]})
186214
result = sphinx_doctree_no_tr(file_params.content, "index.md")
@@ -191,7 +219,9 @@ def test_evalrst_elements(
191219

192220
@pytest.mark.param_file(FIXTURE_PATH / "definition_lists.md")
193221
def test_definition_lists(
194-
file_params: ParamTestData, sphinx_doctree_no_tr: CreateDoctree
222+
file_params: ParamTestData,
223+
sphinx_doctree_no_tr: CreateDoctree,
224+
normalize_doctree_xml,
195225
):
196226
sphinx_doctree_no_tr.set_conf(
197227
{"extensions": ["myst_parser"], "myst_enable_extensions": ["deflist"]}
@@ -203,7 +233,11 @@ def test_definition_lists(
203233

204234

205235
@pytest.mark.param_file(FIXTURE_PATH / "attributes.md")
206-
def test_attributes(file_params: ParamTestData, sphinx_doctree_no_tr: CreateDoctree):
236+
def test_attributes(
237+
file_params: ParamTestData,
238+
sphinx_doctree_no_tr: CreateDoctree,
239+
normalize_doctree_xml,
240+
):
207241
sphinx_doctree_no_tr.set_conf(
208242
{
209243
"extensions": ["myst_parser"],

tests/test_renderers/test_include_directive.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from pathlib import Path
44

55
import pytest
6-
from conftest import normalize_doctree_xml
76
from docutils.core import publish_doctree
87

98
from myst_parser.parsers.docutils_ import Parser
@@ -12,7 +11,7 @@
1211

1312

1413
@pytest.mark.param_file(FIXTURE_PATH / "mock_include.md")
15-
def test_render(file_params, tmp_path, monkeypatch):
14+
def test_render(file_params, tmp_path, monkeypatch, normalize_doctree_xml):
1615
monkeypatch.chdir(tmp_path)
1716

1817
tmp_path.joinpath("other.md").write_text("a\nb\nc")

tests/test_renderers/test_myst_config.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from pathlib import Path
66

77
import pytest
8-
from conftest import normalize_doctree_xml
98
from docutils import __version_info__ as docutils_version
109
from docutils.core import Publisher, publish_string
1110
from pytest_param_files import ParamTestData
@@ -17,7 +16,7 @@
1716

1817

1918
@pytest.mark.param_file(FIXTURE_PATH / "myst-config.txt")
20-
def test_cmdline(file_params: ParamTestData):
19+
def test_cmdline(file_params: ParamTestData, normalize_doctree_xml):
2120
"""The description is parsed as a docutils commandline"""
2221
if file_params.title == "attrs_image" and docutils_version < (0, 22):
2322
# loose system messages are also output to ast in 0.22 https://github.com/live-clones/docutils/commit/dc4e16315b4fbe391417a6f7aad215b9389a9c74

tests/test_renderers/test_myst_refs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import sys
22

33
import pytest
4-
from conftest import normalize_doctree_xml
54
from sphinx.util.console import strip_colors
65
from sphinx_pytest.plugin import CreateDoctree
76

@@ -42,6 +41,7 @@ def test_parse(
4241
should_warn: bool,
4342
sphinx_doctree: CreateDoctree,
4443
file_regression,
44+
normalize_doctree_xml,
4545
):
4646
sphinx_doctree.set_conf({"extensions": ["myst_parser"], "show_warning_types": True})
4747
result = sphinx_doctree(text, "index.md")

tests/test_sphinx/conftest.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ def test_basic(app, status, warning, get_sphinx_app_output):
4141
from docutils import nodes
4242

4343
from myst_parser._compat import findall
44-
from tests.conftest import normalize_doctree_xml
4544

4645
SOURCE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "sourcedirs"))
4746

@@ -95,7 +94,7 @@ def read(
9594

9695

9796
@pytest.fixture
98-
def get_sphinx_app_doctree(file_regression):
97+
def get_sphinx_app_doctree(file_regression, normalize_doctree_xml):
9998
def read(
10099
app,
101100
docname="index",

0 commit comments

Comments
 (0)