Enable automatic formatting for `sphinx/ext/imgmath.py`

This commit is contained in:
Adam Turner 2024-12-24 19:57:14 +00:00
parent f592962b8d
commit da5a67d5a4
2 changed files with 79 additions and 54 deletions

View File

@ -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",

View File

@ -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'<!-- DEPTH=(-?\d+) -->')
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=%s -->' % 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('<span class="math">%s</span>' %
self.encode(node.astext()).strip())
self.body.append(
f'<span class="math">{self.encode(node.astext()).strip()}</span>'
)
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'<img class="math" src="{img_src}"' + get_tooltip(self, node)
if depth is not None:
c += f' style="vertical-align: {-depth:d}px"'
self.body.append(c + '/>')
align = f' style="vertical-align: {-depth:d}px"' if depth is not None else ''
self.body.append(
f'<img class="math" src="{img_src}"{get_tooltip(self, node)}{align}/>'
)
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('<span class="math">%s</span></p>\n</div>' %
self.encode(node.astext()).strip())
self.body.append(
f'<span class="math">{self.encode(node.astext()).strip()}</span></p>\n</div>'
)
else:
if self.builder.config.imgmath_embed:
image_format = self.builder.config.imgmath_image_format.lower()
@ -381,24 +404,27 @@ def html_visit_displaymath(self: HTML5Translator, node: nodes.math_block) -> Non
bname = os.path.basename(rendered_path)
relative_path = os.path.join(self.builder.imgpath, 'math', bname)
img_src = relative_path.replace(os.path.sep, '/')
self.body.append(f'<img src="{img_src}"' + get_tooltip(self, node) +
'/></p>\n</div>')
self.body.append(f'<img src="{img_src}"{get_tooltip(self, node)}/></p>\n</div>')
raise nodes.SkipNode
def setup(app: Sphinx) -> ExtensionMetadata:
app.add_html_math_renderer('imgmath',
(html_visit_math, None),
(html_visit_displaymath, None))
app.add_html_math_renderer(
'imgmath',
inline_renderers=(html_visit_math, None),
block_renderers=(html_visit_displaymath, None),
)
app.add_config_value('imgmath_image_format', 'png', 'html')
app.add_config_value('imgmath_dvipng', 'dvipng', 'html')
app.add_config_value('imgmath_dvisvgm', 'dvisvgm', 'html')
app.add_config_value('imgmath_latex', 'latex', 'html')
app.add_config_value('imgmath_use_preview', False, 'html')
app.add_config_value('imgmath_dvipng_args',
['-gamma', '1.5', '-D', '110', '-bg', 'Transparent'],
'html')
app.add_config_value(
'imgmath_dvipng_args',
['-gamma', '1.5', '-D', '110', '-bg', 'Transparent'],
'html',
)
app.add_config_value('imgmath_dvisvgm_args', ['--no-fonts'], 'html')
app.add_config_value('imgmath_latex_args', [], 'html')
app.add_config_value('imgmath_latex_preamble', '', 'html')