mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Enable automatic formatting for `sphinx/ext/imgmath.py
`
This commit is contained in:
parent
f592962b8d
commit
da5a67d5a4
@ -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",
|
||||
|
@ -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,
|
||||
def generate_latex_macro(
|
||||
image_format: str,
|
||||
math: str,
|
||||
config: Config,
|
||||
confdir: str | os.PathLike[str] = '') -> str:
|
||||
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',
|
||||
app.add_config_value(
|
||||
'imgmath_dvipng_args',
|
||||
['-gamma', '1.5', '-D', '110', '-bg', 'Transparent'],
|
||||
'html')
|
||||
'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')
|
||||
|
Loading…
Reference in New Issue
Block a user