Skip to content

Commit 7e3a182

Browse files
committed
👌 IMPROVE: Simplify and fix mathjax config override for Sphinx 8/9
- Remove dead Sphinx 3 / MathJax 2 code path (`mathjax_config['tex2jax']`) since only Sphinx >=8 is supported. - Add mathjax4_config support for Sphinx 9, preferring whichever config the user has explicitly set. - Fix default case: processHtmlClass is now always applied even when no user mathjax config is set. - Simplify log_override_warning to use the actual config attribute name instead of a version number. - Add tests for default config, myst_update_mathjax=False, and mathjax4_config override warning (Sphinx 9 only).
1 parent fde7aa8 commit 7e3a182

6 files changed

Lines changed: 121 additions & 44 deletions

File tree

myst_parser/sphinx_ext/mathjax.py

Lines changed: 30 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,13 @@
2020
logger = logging.getLogger(__name__)
2121

2222

23-
def log_override_warning(app: Sphinx, version: int, current: str, new: str) -> None:
23+
def log_override_warning(app: Sphinx, config_name: str, current: str, new: str) -> None:
2424
"""Log a warning if MathJax configuration being overridden."""
2525
if logging.is_suppressed_warning("myst", "mathjax", app.config.suppress_warnings):
2626
return
27-
config_name = (
28-
"mathjax3_config['options']['processHtmlClass']"
29-
if version == 3
30-
else "mathjax_config['tex2jax']['processClass']"
31-
)
3227
logger.warning(
33-
f"`{config_name}` is being overridden by myst-parser: '{current}' -> '{new}'. "
28+
f"`{config_name}['options']['processHtmlClass']` "
29+
f"is being overridden by myst-parser: '{current}' -> '{new}'. "
3430
"Set `suppress_warnings=['myst.mathjax']` to ignore this warning, or "
3531
"`myst_update_mathjax=False` if this is undesirable."
3632
)
@@ -59,43 +55,33 @@ def override_mathjax(app: Sphinx):
5955

6056
mjax_classes = app.env.myst_config.mathjax_classes # type: ignore[attr-defined]
6157

62-
mathjax_opt = None
63-
for opt in ("mathjax4_config", "mathjax3_config"):
64-
if getattr(app.config, opt, None):
65-
mathjax_opt = opt
66-
break
67-
if mathjax_opt is not None:
68-
# sphinx 4 + mathjax 3
69-
# sphinx 9 + mathjax 4
70-
config = getattr(app.config, opt, {}) or {}
71-
config.setdefault("options", {})
72-
if (
73-
"processHtmlClass" in config["options"]
74-
and config["options"]["processHtmlClass"] != mjax_classes
75-
):
76-
log_override_warning(
77-
app,
78-
3,
79-
config["options"]["processHtmlClass"],
80-
mjax_classes,
81-
)
82-
config["options"]["processHtmlClass"] = mjax_classes
83-
setattr(app.config, opt, config)
84-
elif "mathjax_config" in app.config:
85-
# sphinx 3 + mathjax 2
86-
app.config.mathjax_config = app.config.mathjax_config or {}
87-
app.config.mathjax_config.setdefault("tex2jax", {})
88-
if (
89-
"processClass" in app.config.mathjax_config["tex2jax"]
90-
and app.config.mathjax_config["tex2jax"]["processClass"] != mjax_classes
91-
):
92-
log_override_warning(
93-
app,
94-
2,
95-
app.config.mathjax_config["tex2jax"]["processClass"],
96-
mjax_classes,
97-
)
98-
app.config.mathjax_config["tex2jax"]["processClass"] = mjax_classes
58+
# Determine which mathjax config to modify:
59+
# prefer whichever the user has explicitly set, falling back to
60+
# the Sphinx version's default (mathjax4_config for Sphinx 9+, mathjax3_config for 8)
61+
has_mjax4 = hasattr(app.config, "mathjax4_config")
62+
if has_mjax4 and app.config.mathjax4_config:
63+
config_attr = "mathjax4_config"
64+
elif app.config.mathjax3_config:
65+
config_attr = "mathjax3_config"
66+
elif has_mjax4:
67+
config_attr = "mathjax4_config"
68+
else:
69+
config_attr = "mathjax3_config"
70+
71+
config: dict = getattr(app.config, config_attr) or {} # type: ignore[type-arg]
72+
config.setdefault("options", {})
73+
if (
74+
"processHtmlClass" in config["options"]
75+
and config["options"]["processHtmlClass"] != mjax_classes
76+
):
77+
log_override_warning(
78+
app,
79+
config_attr,
80+
config["options"]["processHtmlClass"],
81+
mjax_classes,
82+
)
83+
config["options"]["processHtmlClass"] = mjax_classes
84+
setattr(app.config, config_attr, config)
9985

10086

10187
def html_visit_displaymath(self: HTMLTranslator, node: nodes.math_block) -> None:
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
extensions = ["myst_parser"]
2+
exclude_patterns = ["_build"]
3+
4+
mathjax4_config = {"options": {"processHtmlClass": "other"}}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Test
2+
3+
```{math}
4+
a = 1
5+
```
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
extensions = ["myst_parser"]
2+
exclude_patterns = ["_build"]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Test
2+
3+
```{math}
4+
a = 1
5+
```

tests/test_sphinx/test_sphinx_builds.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,81 @@ def test_mathjax_warning(
595595
)
596596

597597

598+
@pytest.mark.sphinx(
599+
buildername="html",
600+
srcdir=os.path.join(SOURCE_DIR, "mathjax_default"),
601+
freshenv=True,
602+
confoverrides={"myst_enable_extensions": ["dollarmath"]},
603+
)
604+
def test_mathjax_default(
605+
app,
606+
status,
607+
warning,
608+
):
609+
"""Test mathjax processHtmlClass is set even without user config."""
610+
app.build()
611+
assert "build succeeded" in status.getvalue()
612+
warnings = warning.getvalue().strip()
613+
assert "overridden by myst-parser" not in warnings
614+
# Verify processHtmlClass was applied to the appropriate config
615+
if hasattr(app.config, "mathjax4_config"):
616+
config = app.config.mathjax4_config
617+
else:
618+
config = app.config.mathjax3_config
619+
assert config["options"]["processHtmlClass"] == (
620+
"tex2jax_process|mathjax_process|math|output_area"
621+
)
622+
623+
624+
@pytest.mark.sphinx(
625+
buildername="html",
626+
srcdir=os.path.join(SOURCE_DIR, "mathjax_default"),
627+
freshenv=True,
628+
confoverrides={
629+
"myst_enable_extensions": ["dollarmath"],
630+
"myst_update_mathjax": False,
631+
},
632+
)
633+
def test_mathjax_no_override(
634+
app,
635+
status,
636+
warning,
637+
):
638+
"""Test that myst_update_mathjax=False prevents config override."""
639+
app.build()
640+
assert "build succeeded" in status.getvalue()
641+
# processHtmlClass should NOT have been set
642+
if hasattr(app.config, "mathjax4_config"):
643+
assert app.config.mathjax4_config is None
644+
else:
645+
assert app.config.mathjax3_config is None
646+
647+
648+
@pytest.mark.skipif(
649+
int(__import__("sphinx").__version__.split(".")[0]) < 9,
650+
reason="mathjax4_config not available before Sphinx 9",
651+
)
652+
@pytest.mark.sphinx(
653+
buildername="html",
654+
srcdir=os.path.join(SOURCE_DIR, "mathjax4"),
655+
freshenv=True,
656+
confoverrides={"myst_enable_extensions": ["dollarmath"]},
657+
)
658+
def test_mathjax4_warning(
659+
app,
660+
status,
661+
warning,
662+
):
663+
"""Test mathjax4_config override warning (Sphinx 9+)."""
664+
app.build()
665+
assert "build succeeded" in status.getvalue()
666+
warnings = warning.getvalue().strip()
667+
assert (
668+
"overridden by myst-parser: 'other' -> 'tex2jax_process|mathjax_process|math|output_area'"
669+
in warnings
670+
)
671+
672+
598673
@pytest.mark.skipif(
599674
sys.platform == "win32",
600675
reason="Unicode encoding issues on Windows",

0 commit comments

Comments
 (0)