"""Test math extensions.""" from __future__ import annotations import re import shutil import subprocess import warnings import pytest from docutils import nodes from sphinx.ext.mathjax import MATHJAX_URL from sphinx.testing.util import assert_node def has_binary(binary: str) -> bool: try: subprocess.check_output([binary]) except FileNotFoundError: return False except OSError: pass return True @pytest.mark.skipif( not has_binary('dvipng'), reason='Requires dvipng" binary', ) @pytest.mark.sphinx( 'html', testroot='ext-math-simple', confoverrides={'extensions': ['sphinx.ext.imgmath']}, ) def test_imgmath_png(app): app.build(force_all=True) if "LaTeX command 'latex' cannot be run" in app.warning.getvalue(): msg = 'LaTeX command "latex" is not available' raise pytest.skip.Exception(msg) if "dvipng command 'dvipng' cannot be run" in app.warning.getvalue(): msg = 'dvipng command "dvipng" is not available' raise pytest.skip.Exception(msg) content = (app.outdir / 'index.html').read_text(encoding='utf8') shutil.rmtree(app.outdir) html = ( r'
\s*

\s*\s*

\s*
' ) assert re.search(html, content, re.DOTALL) @pytest.mark.skipif( not has_binary('dvisvgm'), reason='Requires dvisvgm" binary', ) @pytest.mark.sphinx( 'html', testroot='ext-math-simple', confoverrides={'extensions': ['sphinx.ext.imgmath'], 'imgmath_image_format': 'svg'}, ) def test_imgmath_svg(app): app.build(force_all=True) if "LaTeX command 'latex' cannot be run" in app.warning.getvalue(): msg = 'LaTeX command "latex" is not available' raise pytest.skip.Exception(msg) if "dvisvgm command 'dvisvgm' cannot be run" in app.warning.getvalue(): msg = 'dvisvgm command "dvisvgm" is not available' raise pytest.skip.Exception(msg) content = (app.outdir / 'index.html').read_text(encoding='utf8') shutil.rmtree(app.outdir) html = ( r'
\s*

\s*\s*

\s*
' ) assert re.search(html, content, re.DOTALL) @pytest.mark.skipif( not has_binary('dvisvgm'), reason='Requires dvisvgm" binary', ) @pytest.mark.sphinx( 'html', testroot='ext-math-simple', confoverrides={ 'extensions': ['sphinx.ext.imgmath'], 'imgmath_image_format': 'svg', 'imgmath_embed': True, }, ) def test_imgmath_svg_embed(app): app.build(force_all=True) if "LaTeX command 'latex' cannot be run" in app.warning.getvalue(): msg = 'LaTeX command "latex" is not available' raise pytest.skip.Exception(msg) if "dvisvgm command 'dvisvgm' cannot be run" in app.warning.getvalue(): msg = 'dvisvgm command "dvisvgm" is not available' raise pytest.skip.Exception(msg) content = (app.outdir / 'index.html').read_text(encoding='utf8') shutil.rmtree(app.outdir) html = r'' '' ) in content @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides={'extensions': ['sphinx.ext.mathjax']}, ) def test_mathjax_align(app): app.build(force_all=True) content = (app.outdir / 'index.html').read_text(encoding='utf8') shutil.rmtree(app.outdir) html = ( r'
\s*' r'\\\[ \\begin\{align\}\\begin\{aligned\}S \&= \\pi r\^2\\\\' r'V \&= \\frac\{4\}\{3\} \\pi r\^3\\end\{aligned\}\\end\{align\} \\\]
' ) assert re.search(html, content, re.DOTALL) @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides={'math_number_all': True, 'extensions': ['sphinx.ext.mathjax']}, ) def test_math_number_all_mathjax(app): app.build() content = (app.outdir / 'index.html').read_text(encoding='utf8') html = ( r'
\s*' r'\(1\)\xb6\\\[a\^2\+b\^2=c\^2\\\]
' ) assert re.search(html, content, re.DOTALL) @pytest.mark.sphinx( 'latex', testroot='ext-math', confoverrides={'extensions': ['sphinx.ext.mathjax']}, ) def test_math_number_all_latex(app): app.build() content = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8') macro = ( r'\\begin{equation\*}\s*' r'\\begin{split}a\^2\+b\^2=c\^2\\end{split}\s*' r'\\end{equation\*}' ) assert re.search(macro, content, re.DOTALL) macro = r'Inline \\\(E=mc\^2\\\)' assert re.search(macro, content, re.DOTALL) macro = ( r'\\begin{equation\*}\s*' r'\\begin{split}e\^{i\\pi}\+1=0\\end{split}\s+' r'\\end{equation\*}' ) assert re.search(macro, content, re.DOTALL) macro = ( r'\\begin{align\*}\\!\\begin{aligned}\s*' r'S &= \\pi r\^2\\\\\s*' r'V &= \\frac\{4}\{3} \\pi r\^3\\\\\s*' r'\\end{aligned}\\end{align\*}' ) assert re.search(macro, content, re.DOTALL) macro = r'Referencing equation \\eqref{equation:math:foo}.' assert re.search(macro, content, re.DOTALL) @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides={ 'extensions': ['sphinx.ext.mathjax'], 'math_eqref_format': 'Eq.{number}', }, ) def test_math_eqref_format_html(app): app.build(force_all=True) content = (app.outdir / 'math.html').read_text(encoding='utf8') html = ( '

Referencing equation Eq.1 and Eq.1.

' ) assert html in content @pytest.mark.sphinx( 'latex', testroot='ext-math', confoverrides={ 'extensions': ['sphinx.ext.mathjax'], 'math_eqref_format': 'Eq.{number}', }, ) def test_math_eqref_format_latex(app): app.build(force_all=True) content = (app.outdir / 'projectnamenotset.tex').read_text(encoding='utf8') macro = ( r'Referencing equation Eq.\\ref{equation:math:foo} and ' r'Eq.\\ref{equation:math:foo}.' ) assert re.search(macro, content, re.DOTALL) @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides={ 'extensions': ['sphinx.ext.mathjax'], 'numfig': True, 'math_numfig': True, }, ) def test_mathjax_numfig_html(app): app.build(force_all=True) content = (app.outdir / 'math.html').read_text(encoding='utf8') html = ( '
\n' '(1.2)' ) assert html in content html = ( '

Referencing equation (1.1) and ' '(1.1).

' ) assert html in content @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides={ 'extensions': ['sphinx.ext.mathjax'], 'numfig': True, 'math_numfig': True, 'math_numsep': '-', }, ) def test_mathjax_numsep_html(app): app.build(force_all=True) content = (app.outdir / 'math.html').read_text(encoding='utf8') html = ( '
\n' '(1-2)' ) assert html in content html = ( '

Referencing equation (1-1) and ' '(1-1).

' ) assert html in content @pytest.mark.usefixtures('_http_teapot') @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides={ 'extensions': ['sphinx.ext.imgmath'], 'numfig': True, 'numfig_secnum_depth': 0, 'math_numfig': True, }, ) def test_imgmath_numfig_html(app): app.build(force_all=True) content = (app.outdir / 'page.html').read_text(encoding='utf8') html = '(3)Referencing equations (1) and ' '(3).

' ) assert html in content @pytest.mark.sphinx('dummy', testroot='ext-math-compat') def test_math_compat(app): with warnings.catch_warnings(record=True): app.build(force_all=True) doctree = app.env.get_and_resolve_doctree('index', app.builder) assert_node( doctree, [ nodes.document, nodes.section, ( nodes.title, [nodes.section, (nodes.title, nodes.paragraph)], nodes.section, ), ], ) assert_node( doctree[0][1][1], ( 'Inline: ', [nodes.math, 'E=mc^2'], '\nInline my math: ', [nodes.math, 'E = mc^2'], ), ) assert_node( doctree[0][2], ( [nodes.title, 'block'], [nodes.math_block, 'a^2+b^2=c^2\n\n'], [nodes.paragraph, 'Second math'], [nodes.math_block, 'e^{i\\pi}+1=0\n\n'], [nodes.paragraph, 'Multi math equations'], [nodes.math_block, 'E = mc^2'], ), ) @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides={ 'extensions': ['sphinx.ext.mathjax'], 'mathjax3_config': {'extensions': ['tex2jax.js']}, }, ) def test_mathjax3_config(app): app.build(force_all=True) content = (app.outdir / 'index.html').read_text(encoding='utf8') assert MATHJAX_URL in content assert '' in content @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides={ 'extensions': ['sphinx.ext.mathjax'], 'mathjax2_config': {'extensions': ['tex2jax.js']}, }, ) def test_mathjax2_config(app): app.build(force_all=True) content = (app.outdir / 'index.html').read_text(encoding='utf8') assert '' ) in content @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides={ 'extensions': ['sphinx.ext.mathjax'], 'mathjax_options': {'async': 'async'}, 'mathjax3_config': {'extensions': ['tex2jax.js']}, }, ) def test_mathjax_options_async_for_mathjax3(app): app.build(force_all=True) content = (app.outdir / 'index.html').read_text(encoding='utf8') assert MATHJAX_URL in content assert '' in content @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides={ 'extensions': ['sphinx.ext.mathjax'], 'mathjax_path': 'MathJax.js?config=scipy-mathjax', }, ) def test_mathjax_path_config(app): app.build(force_all=True) content = (app.outdir / 'index.html').read_text(encoding='utf8') assert ( '' ) in content @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides={'extensions': ['sphinx.ext.mathjax']}, ) def test_mathjax_is_installed_only_if_document_having_math(app): app.build(force_all=True) content = (app.outdir / 'index.html').read_text(encoding='utf8') assert MATHJAX_URL in content content = (app.outdir / 'nomath.html').read_text(encoding='utf8') assert MATHJAX_URL not in content @pytest.mark.sphinx( 'html', testroot='basic', confoverrides={'extensions': ['sphinx.ext.mathjax']}, ) def test_mathjax_is_not_installed_if_no_equations(app): app.build(force_all=True) content = (app.outdir / 'index.html').read_text(encoding='utf8') assert 'MathJax.js' not in content @pytest.mark.sphinx( 'html', testroot='ext-math', confoverrides={'extensions': ['sphinx.ext.mathjax']}, ) def test_mathjax_is_installed_if_no_equations_when_forced(app): app.set_html_assets_policy('always') app.build(force_all=True) content = (app.outdir / 'index.html').read_text(encoding='utf8') assert MATHJAX_URL in content content = (app.outdir / 'nomath.html').read_text(encoding='utf8') assert MATHJAX_URL in content @pytest.mark.sphinx( 'html', testroot='ext-math-include', confoverrides={'extensions': ['sphinx.ext.mathjax']}, ) def test_mathjax_is_installed_if_included_file_has_equations(app): app.build(force_all=True) # no real equations at the rst level, but includes "included" content = (app.outdir / 'index.html').read_text(encoding='utf8') assert MATHJAX_URL in content # no real equations at the rst level, but includes "math.rst" content = (app.outdir / 'included.html').read_text(encoding='utf8') assert MATHJAX_URL in content content = (app.outdir / 'math.html').read_text(encoding='utf8') assert MATHJAX_URL in content @pytest.mark.sphinx( 'singlehtml', testroot='ext-math', confoverrides={'extensions': ['sphinx.ext.mathjax']}, ) def test_mathjax_is_installed_only_if_document_having_math_singlehtml(app): app.build(force_all=True) content = (app.outdir / 'index.html').read_text(encoding='utf8') assert MATHJAX_URL in content @pytest.mark.sphinx( 'singlehtml', testroot='basic', confoverrides={'extensions': ['sphinx.ext.mathjax']}, ) def test_mathjax_is_not_installed_if_no_equations_singlehtml(app): app.build(force_all=True) content = (app.outdir / 'index.html').read_text(encoding='utf8') assert 'MathJax.js' not in content @pytest.mark.sphinx( 'singlehtml', testroot='ext-math-include', confoverrides={'extensions': ['sphinx.ext.mathjax']}, ) def test_mathjax_is_installed_if_included_file_has_equations_singlehtml(app): app.build(force_all=True) content = (app.outdir / 'index.html').read_text(encoding='utf8') assert MATHJAX_URL in content