Skip to content

FIX: Keep figures inside prf boxes from floating in LaTeX - #170

Open
mmcky wants to merge 1 commit into
mainfrom
fix/latex-figures-in-proof-boxes
Open

mmcky wants to merge 1 commit into
mainfrom
fix/latex-figures-in-proof-boxes

Conversation

@mmcky

@mmcky mmcky commented Nov 10, 2026

Copy link
Copy Markdown
Member

Fixes #169

A captioned figure inside a prf: directive box, such as prf:theorem or a :nonumber: prf:lemma, breaks the LaTeX/PDF build with LaTeX Error: Not in outer par mode. Sphinx's LaTeX writer increments no_latex_floats whenever it opens one of its own admonitions, and visit_figure then writes \begin{figure}[H] instead of a float. sphinx-proof opens the same sphinxadmonition box in visit_enumerable_node and visit_unenumerable_node but never touched the counter, so figures inside it were written as \begin{figure}[htbp], which LaTeX rejects inside the box. This mirrors the change in executablebooks/sphinx-exercise#95, released in sphinx-exercise 1.2.2.

Changes

  • sphinx_proof/nodes.py: the LaTeX branches of the enumerable and unenumerable visit/depart pairs now open and close the box through a small visit_latex_admonition / depart_latex_admonition helper pair that also increments and decrements self.no_latex_floats. This covers every directive in PROOF_TYPES, numbered or :nonumber:. The helpers still append the exact latex_admonition_start string that the depart_* functions search for to place the box title. prf:proof needed no change, because it wraps a docutils admonition node that Sphinx's own visitor already handles. HTML output is unchanged.
  • New test root tests/books/test-latexfigure/ and tests/test_latex.py::test_latex_figure_in_admonition: figures in a numbered theorem, an unnumbered lemma, a prf:proof, a note, nested boxes, and one figure after all the boxes that must still be [htbp], which shows the counter is restored. The test reads only the generated .tex, so CI needs no TeX installation.
  • CHANGELOG.md: entry under Unreleased.

Testing

  • The new test fails on main and passes with this change on Sphinx 7.2.6, 7.4.7, 8.1.3, 9.0.4 and 9.1.1, and on 5.3.0 and 6.2.1 with a local shim for the suite's conftest.py, which needs Sphinx 7.2 or later. Full suite: 15 passed on main, 16 with this change.
  • End to end with latexmk -pdf on Sphinx 7.4.7: the new test root stops at the first in-box figure on main and compiles with this change.
  • Nesting: boxes inside prf: boxes and prf: boxes inside others all write their figures as [H], the counter returns to zero at the end of the document, and the PDF compiles.
  • pre-commit could not fetch its hook repositories from this machine, so the pinned tools were run directly (black 25.9.0, flake8 7.3.0, the whitespace and end-of-file hooks): all clean.

Not addressed here: when one prf: box contains another, the LaTeX output still places the outer box's title in the inner box, the LaTeX counterpart of #165.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WT8bMZoSvoQTbzkdmZiMnd

A captioned figure inside a prf: directive box, numbered or :nonumber:,
broke the LaTeX/PDF build with "LaTeX Error: Not in outer par mode".
Sphinx's LaTeX writer increments no_latex_floats whenever it opens one
of its own admonitions, and visit_figure then writes
\begin{figure}[H]. The enumerable and unenumerable visitors open the
same sphinxadmonition box but never touched the counter, so figures
inside it were written as floating \begin{figure}[htbp], which LaTeX
rejects there.

Open and close the box through a small visit_latex_admonition /
depart_latex_admonition helper pair that also increments and
decrements the counter. prf:proof was already unaffected: it wraps a
docutils admonition node that Sphinx's own visitor handles. HTML output
is unchanged.

Add the tests/books/test-latexfigure root and
tests/test_latex.py::test_latex_figure_in_admonition, and a CHANGELOG
entry. Mirrors the change in executablebooks/sphinx-exercise#95.

Fixes #169

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WT8bMZoSvoQTbzkdmZiMnd
Copilot AI balanced review requested due to automatic review settings November 10, 2026 05:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Copilot was unable to complete this review at the selected tier due to model policy or plan restrictions.

🟡 Changes recommended

The change still has an unresolved moderate test robustness issue where latex_figures can silently drop earlier figures on duplicate or missing names, along with a minor changelog style inconsistency that should be corrected.

2 open issues
What changed in this PR

Fixes LaTeX/PDF build failures when captioned figures appear inside prf: directive boxes by aligning sphinx-proof’s LaTeX admonition handling with Sphinx’s float-suppression behavior to avoid “Not in outer par mode”.

Changes:

  • Add LaTeX admonition helper functions to open/close sphinxadmonition boxes while updating no_latex_floats for prf: nodes.
  • Add a LaTeX regression test root and a test that inspects generated .tex to verify in-box figures use [H] and floats resume after boxes.
  • Document the fix under CHANGELOG.md (Unreleased).
File Description
tests/​test_latex.py Adds a regression test that parses generated LaTeX to verify figure float behavior inside and outside proof/admonition boxes (including nesting).
tests/​books/​test-latexfigure/​index.rst Introduces a new test root index/toctree to drive the LaTeX figure-in-admonition regression scenario.
tests/​books/​test-latexfigure/​figures.rst Adds test content covering figures inside numbered/unnumbered prf: boxes, Sphinx admonitions, nested boxes, and a figure outside boxes.
tests/​books/​test-latexfigure/​conf.py Provides a minimal Sphinx configuration enabling sphinx_proof for the new LaTeX regression test root.
sphinx_proof/​nodes.py Refactors LaTeX visitor logic to open/close admonition environments via helpers that manage no_latex_floats so figures inside prf: boxes are emitted as non-floating.
CHANGELOG.md Adds an Unreleased changelog entry documenting the LaTeX fix for figures inside prf: directive boxes.

Review effort: Balanced

Comment thread tests/test_latex.py
Comment on lines +37 to +38
name = LATEX_FIGURE_NAME.search(figure["body"])
figures[name["name"] if name else None] = (figure["align"], depth)
Comment thread CHANGELOG.md
Comment on lines +7 to +9
- Captioned figures inside `prf:` directive boxes breaking the LaTeX/PDF build with `LaTeX Error: Not in outer par mode`, fixing [\#169](https://github.com/executablebooks/sphinx-proof/issues/169).
- Figures inside every `prf:` box, numbered or `:nonumber:`, are now written as `\begin{figure}[H]` so they stay in place, as Sphinx already does for figures inside its own admonitions
- HTML output is unchanged

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LaTeX: figures inside theorem-style boxes are written as floats ("Not in outer par mode")

2 participants