diff --git a/.ruff.toml b/.ruff.toml
index 351b05a37..c2b62f25b 100644
--- a/.ruff.toml
+++ b/.ruff.toml
@@ -415,7 +415,6 @@ exclude = [
"sphinx/domains/python/_object.py",
"sphinx/domains/rst.py",
"sphinx/domains/std/__init__.py",
- "sphinx/ext/imgmath.py",
"sphinx/ext/inheritance_diagram.py",
"sphinx/ext/linkcode.py",
"sphinx/ext/mathjax.py",
diff --git a/sphinx/ext/imgmath.py b/sphinx/ext/imgmath.py
index 2a06dd208..df7cc9e1e 100644
--- a/sphinx/ext/imgmath.py
+++ b/sphinx/ext/imgmath.py
@@ -29,7 +29,6 @@ from sphinx.util.png import read_png_depth, write_png_depth
from sphinx.util.template import LaTeXRenderer
if TYPE_CHECKING:
-
from docutils.nodes import Element
from sphinx.application import Sphinx
@@ -47,7 +46,7 @@ class MathExtError(SphinxError):
category = 'Math extension error'
def __init__(
- self, msg: str, stderr: str | None = None, stdout: str | None = None,
+ self, msg: str, stderr: str | None = None, stdout: str | None = None
) -> None:
if stderr:
msg += '\n[stderr]\n' + stderr
@@ -68,9 +67,8 @@ depthsvgcomment_re = re.compile(r'')
def read_svg_depth(filename: str) -> int | None:
- """Read the depth from comment at last line of SVG file
- """
- with open(filename, encoding="utf-8") as f:
+ """Read the depth from comment at last line of SVG file"""
+ with open(filename, encoding='utf-8') as f:
for line in f: # NoQA: B007
pass
# Only last line is checked
@@ -81,16 +79,17 @@ def read_svg_depth(filename: str) -> int | None:
def write_svg_depth(filename: str, depth: int) -> None:
- """Write the depth to SVG file as a comment at end of file
- """
- with open(filename, 'a', encoding="utf-8") as f:
+ """Write the depth to SVG file as a comment at end of file"""
+ with open(filename, 'a', encoding='utf-8') as f:
f.write('\n' % depth)
-def generate_latex_macro(image_format: str,
- math: str,
- config: Config,
- confdir: str | os.PathLike[str] = '') -> str:
+def generate_latex_macro(
+ image_format: str,
+ math: str,
+ config: Config,
+ confdir: str | os.PathLike[str] = '',
+) -> str:
"""Generate LaTeX macro."""
variables = {
'fontsize': config.imgmath_font_size,
@@ -109,7 +108,9 @@ def generate_latex_macro(image_format: str,
for template_dir in config.templates_path:
for template_suffix in ('.jinja', '_t'):
- template = os.path.join(confdir, template_dir, template_name + template_suffix)
+ template = os.path.join(
+ confdir, template_dir, template_name + template_suffix
+ )
if os.path.exists(template):
return LaTeXRenderer().render(template, variables)
@@ -149,16 +150,21 @@ def compile_math(latex: str, builder: Builder) -> str:
command.append('math.tex')
try:
- subprocess.run(command, capture_output=True, cwd=tempdir, check=True,
- encoding='ascii')
+ subprocess.run(
+ command, capture_output=True, cwd=tempdir, check=True, encoding='ascii'
+ )
if imgmath_latex_name in {'xelatex', 'tectonic'}:
return os.path.join(tempdir, 'math.xdv')
else:
return os.path.join(tempdir, 'math.dvi')
except OSError as exc:
- logger.warning(__('LaTeX command %r cannot be run (needed for math '
- 'display), check the imgmath_latex setting'),
- builder.config.imgmath_latex)
+ logger.warning(
+ __(
+ 'LaTeX command %r cannot be run (needed for math '
+ 'display), check the imgmath_latex setting'
+ ),
+ builder.config.imgmath_latex,
+ )
raise InvokeError from exc
except CalledProcessError as exc:
msg = 'latex exited with error'
@@ -171,12 +177,19 @@ def convert_dvi_to_image(command: list[str], name: str) -> tuple[str, str]:
ret = subprocess.run(command, capture_output=True, check=True, encoding='ascii')
return ret.stdout, ret.stderr
except OSError as exc:
- logger.warning(__('%s command %r cannot be run (needed for math '
- 'display), check the imgmath_%s setting'),
- name, command[0], name)
+ logger.warning(
+ __(
+ '%s command %r cannot be run (needed for math '
+ 'display), check the imgmath_%s setting'
+ ),
+ name,
+ command[0],
+ name,
+ )
raise InvokeError from exc
except CalledProcessError as exc:
- raise MathExtError('%s exited with error' % name, exc.stderr, exc.stdout) from exc
+ msg = f'{name} exited with error'
+ raise MathExtError(msg, exc.stderr, exc.stdout) from exc
def convert_dvi_to_png(dvipath: str, builder: Builder, out_path: str) -> int | None:
@@ -245,13 +258,16 @@ def render_math(
unsupported_format_msg = 'imgmath_image_format must be either "png" or "svg"'
raise MathExtError(unsupported_format_msg)
- latex = generate_latex_macro(image_format,
- math,
- self.builder.config,
- self.builder.confdir)
+ latex = generate_latex_macro(
+ image_format, math, self.builder.config, self.builder.confdir
+ )
- filename = f"{sha1(latex.encode(), usedforsecurity=False).hexdigest()}.{image_format}"
- generated_path = os.path.join(self.builder.outdir, self.builder.imagedir, 'math', filename)
+ filename = (
+ f'{sha1(latex.encode(), usedforsecurity=False).hexdigest()}.{image_format}'
+ )
+ generated_path = os.path.join(
+ self.builder.outdir, self.builder.imagedir, 'math', filename
+ )
ensuredir(os.path.dirname(generated_path))
if os.path.isfile(generated_path):
if image_format == 'png':
@@ -261,8 +277,9 @@ def render_math(
return generated_path, depth
# if latex or dvipng (dvisvgm) has failed once, don't bother to try again
- if hasattr(self.builder, '_imgmath_warned_latex') or \
- hasattr(self.builder, '_imgmath_warned_image_translator'):
+ latex_failed = hasattr(self.builder, '_imgmath_warned_latex')
+ trans_failed = hasattr(self.builder, '_imgmath_warned_image_translator')
+ if latex_failed or trans_failed:
return None, None
# .tex -> .dvi
@@ -286,7 +303,7 @@ def render_math(
def render_maths_to_base64(image_format: str, generated_path: str) -> str:
- with open(generated_path, "rb") as f:
+ with open(generated_path, 'rb') as f:
encoded = base64.b64encode(f.read()).decode(encoding='utf-8')
if image_format == 'png':
return f'data:image/png;base64,{encoded}'
@@ -308,12 +325,14 @@ def clean_up_files(app: Sphinx, exc: Exception) -> None:
# in embed mode, the images are still generated in the math output dir
# to be shared across workers, but are not useful to the final document
with contextlib.suppress(Exception):
- shutil.rmtree(os.path.join(app.builder.outdir, app.builder.imagedir, 'math'))
+ shutil.rmtree(
+ os.path.join(app.builder.outdir, app.builder.imagedir, 'math')
+ )
def get_tooltip(self: HTML5Translator, node: Element) -> str:
if self.builder.config.imgmath_add_tooltips:
- return ' alt="%s"' % self.encode(node.astext()).strip()
+ return f' alt="{self.encode(node.astext()).strip()}"'
return ''
@@ -322,16 +341,18 @@ def html_visit_math(self: HTML5Translator, node: nodes.math) -> None:
rendered_path, depth = render_math(self, '$' + node.astext() + '$')
except MathExtError as exc:
msg = str(exc)
- sm = nodes.system_message(msg, type='WARNING', level=2,
- backrefs=[], source=node.astext())
+ sm = nodes.system_message(
+ msg, type='WARNING', level=2, backrefs=[], source=node.astext()
+ )
sm.walkabout(self)
logger.warning(__('display latex %r: %s'), node.astext(), msg)
raise nodes.SkipNode from exc
if rendered_path is None:
# something failed -- use text-only as a bad substitute
- self.body.append('%s' %
- self.encode(node.astext()).strip())
+ self.body.append(
+ f'{self.encode(node.astext()).strip()}'
+ )
else:
if self.builder.config.imgmath_embed:
image_format = self.builder.config.imgmath_image_format.lower()
@@ -340,10 +361,10 @@ def html_visit_math(self: HTML5Translator, node: nodes.math) -> None:
bname = os.path.basename(rendered_path)
relative_path = os.path.join(self.builder.imgpath, 'math', bname)
img_src = relative_path.replace(os.path.sep, '/')
- c = f'')
+ align = f' style="vertical-align: {-depth:d}px"' if depth is not None else ''
+ self.body.append(
+ f'
'
+ )
raise nodes.SkipNode
@@ -356,8 +377,9 @@ def html_visit_displaymath(self: HTML5Translator, node: nodes.math_block) -> Non
rendered_path, depth = render_math(self, latex)
except MathExtError as exc:
msg = str(exc)
- sm = nodes.system_message(msg, type='WARNING', level=2,
- backrefs=[], source=node.astext())
+ sm = nodes.system_message(
+ msg, type='WARNING', level=2, backrefs=[], source=node.astext()
+ )
sm.walkabout(self)
logger.warning(__('inline latex %r: %s'), node.astext(), msg)
raise nodes.SkipNode from exc
@@ -371,8 +393,9 @@ def html_visit_displaymath(self: HTML5Translator, node: nodes.math_block) -> Non
if rendered_path is None:
# something failed -- use text-only as a bad substitute
- self.body.append('%s