[PATCH 2/2] Fix tests to work with --latex-footnotes option.

MatÄ›j Cepl <[email protected]> Tue, 22 Jul 2025 01:52:09 +0200
Newsgroups gmane.text.docutils.devel
Message-ID <[email protected]>
---
 docutils/docutils/writers/latex2e/__init__.py |   4 +-
 docutils/test/data/help/rst2latex.rst         |   3 +-
 docutils/test/test_writers/test_latex2e.py    | 350 ++++++++++++++----
 3 files changed, 280 insertions(+), 77 deletions(-)

diff --git a/docutils/docutils/writers/latex2e/__init__.py b/docutils/docutils/writers/latex2e/__init__.py
index 1dcf13466..4b6b0b431 100644
--- a/docutils/docutils/writers/latex2e/__init__.py
+++ b/docutils/docutils/writers/latex2e/__init__.py
@@ -232,13 +232,13 @@ class Writer(writers.Writer):
           {'default': True,
            'action': 'store_true',
            'validator': frontend.validate_boolean}),
-         ),
          ('Footnotes with numbers by LaTeX.',
            ['--latex-footnotes'],
            {'dest': 'docutils_footnotes',
             'action': 'store_false',
-            'validator': frontend.validate_boolean}),
+            'validator': frontend.validate_boolean})
         )
+    )
 
     relative_path_settings = ('template',)
     settings_defaults = {}
diff --git a/docutils/test/data/help/rst2latex.rst b/docutils/test/data/help/rst2latex.rst
index d0ede4c63..8e7e702f4 100644
--- a/docutils/test/data/help/rst2latex.rst
+++ b/docutils/test/data/help/rst2latex.rst
@@ -256,5 +256,4 @@ LaTeX-Specific Options
 --new-column-widths     Use new algorithm to determine table column widths.
                         (future default)
 --docutils-footnotes    Footnotes with numbers/symbols by Docutils. (default)
-                        (The alternative, --latex-footnotes, is not
-                        implemented yet.)
+--latex-footnotes       Footnotes with numbers by LaTeX.
diff --git a/docutils/test/test_writers/test_latex2e.py b/docutils/test/test_writers/test_latex2e.py
index 434786690..acb9dd6ed 100755
--- a/docutils/test/test_writers/test_latex2e.py
+++ b/docutils/test/test_writers/test_latex2e.py
@@ -47,7 +47,7 @@ def test_body(self):
                     self.assertEqual(expected, output)
 
 
-samples = {}
+samples = {}  # type: ignore
 
 
 samples['default'] = ({}, [
@@ -500,98 +500,256 @@ def test_body(self):
 ])
 
 
-totest_latex_footnotes['simple'] = [
-# input
-["""\
-Paragraphs contain text and may contain footnote references (manually
-numbered [1]_, anonymous auto-numbered [#]_, labeled auto-numbered
-[#label]_, or symbolic [*]_).
+class FootnoteTestCase(unittest.TestCase):
 
-.. [1] A footnote contains body elements, consistently indented by at
-   least 3 spaces.
+    maxDiff = None
+    settings = {
+        '_disable_config': True,
+        'strict_visitor': True,
+        'output_encoding': 'unicode',
+        'stylesheet': '',
+        'language_code': 'en',
+        'use_latex_toc': False,
+        'use_latex_citations': False,
+        'legacy_column_widths': True,
+    }
 
-   This is the footnote's second paragraph.
+    def test_footnotes(self):
+        for name, (settings_overrides, cases) in footnote_samples.items():
+            for casenum, (rst_input, expected) in enumerate(cases):
+                with self.subTest(id=f'footnote_samples[{name!r}][{casenum}]'):
+                    output = publish_parts(
+                        source=rst_input,
+                        writer=latex2e.Writer(),
+                        settings_overrides=self.settings | settings_overrides
+                    )['whole']
+                    self.assertEqual(expected, output)
 
-.. [#label] Footnotes may be numbered, either manually or
-   automatically using a "#"-prefixed label.  This footnote has a
-   label so it can be referred to from multiple places, both as a
-   footnote reference and as a hyperlink reference.
 
-.. [#] This footnote is numbered automatically and anonymously using a
-   label of "#" only.
+footnote_samples = {
+    'simple': ({}, [
+        [r"""
+        Paragraphs contain text and may contain footnote references (manually
+        numbered [1]_, anonymous auto-numbered [#]_, labeled auto-numbered
+        [#label]_, or symbolic [*]_).
+        
+        .. [1] A footnote contains body elements, consistently indented by at
+           least 3 spaces.
+        
+           This is the footnote's second paragraph.
+        
+        .. [#label] Footnotes may be numbered, either manually or
+           automatically using a "#"-prefixed label.  This footnote has a
+           label so it can be referred to from multiple places, both as a
+           footnote reference and as a hyperlink reference.
+        
+        .. [#] This footnote is numbered automatically and anonymously using a
+           label of "#" only.
+        
+        .. [*] Footnotes may also use symbols, specified with a "*" label.
+        """,
+ r"""\documentclass[a4paper]{article}
+% generated by Docutils <https://docutils.sourceforge.io/>
+\usepackage{cmap} % fix search and cut-and-paste in Acrobat
+\usepackage[T1]{fontenc}
+
+%%% Custom LaTeX preamble
+% PDF Standard Fonts
+\usepackage{mathptmx} % Times
+\usepackage[scaled=.90]{helvet}
+\usepackage{courier}
+
+%%% User specified packages and stylesheets
+
+%%% Fallback definitions for Docutils-specific commands
+
+% numerical or symbol footnotes with hyperlinks and backlinks
+\providecommand*{\DUfootnotemark}[3]{%
+  \raisebox{1em}{\hypertarget{#1}{}}%
+  \hyperlink{#2}{\textsuperscript{#3}}%
+}
+\providecommand{\DUfootnotetext}[4]{%
+  \begingroup%
+  \renewcommand{\thefootnote}{%
+    \protect\raisebox{1em}{\protect\hypertarget{#1}{}}%
+    \protect\hyperlink{#2}{#3}}%
+  \footnotetext{#4}%
+  \endgroup%
+}
 
-.. [*] Footnotes may also use symbols, specified with a "*" label.
-""",
-## # expected output
-head_template.substitute(dict(parts)) + r"""
+% hyperlinks:
+\ifdefined\hypersetup
+\else
+  \usepackage[hyperfootnotes=false,
+              colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref}
+  \usepackage{bookmark}
+  \urlstyle{same} % normal text font (alternatives: tt, rm, sf)
+\fi
+
+%%% Body
+\begin{document}
+
+\begin{quote}
 Paragraphs contain text and may contain footnote references (manually
-numbered\footnote{%
+numbered\DUfootnotemark{footnote-reference-1}{footnote-1}{1}, anonymous auto-numbered\DUfootnotemark{footnote-reference-2}{footnote-2}{3}, labeled auto-numbered\DUfootnotemark{footnote-reference-3}{label}{2}, or symbolic\DUfootnotemark{footnote-reference-4}{footnote-3}{*}).
+%
+\DUfootnotetext{footnote-1}{footnote-reference-1}{1}{%
 A footnote contains body elements, consistently indented by at
 least 3 spaces.
 
 This is the footnote's second paragraph.
-}, anonymous auto-numbered\footnote{%
-This footnote is numbered automatically and anonymously using a
-label of \textquotedbl{}\#\textquotedbl{} only.
-}, labeled auto-numbered\footnote{%
+}
+%
+\DUfootnotetext{label}{footnote-reference-3}{2}{\phantomsection\label{label}%
 Footnotes may be numbered, either manually or
 automatically using a \textquotedbl{}\#\textquotedbl{}-prefixed label.  This footnote has a
 label so it can be referred to from multiple places, both as a
 footnote reference and as a hyperlink reference.
-}, or symbolic\footnote{%
+}
+%
+\DUfootnotetext{footnote-2}{footnote-reference-2}{3}{%
+This footnote is numbered automatically and anonymously using a
+label of \textquotedbl{}\#\textquotedbl{} only.
+}
+%
+\DUfootnotetext{footnote-3}{footnote-reference-4}{*}{%
 Footnotes may also use symbols, specified with a \textquotedbl{}*\textquotedbl{} label.
-}).
+}
+\end{quote}
 
 \end{document}
-"""],
-]
+"""]]),
+    'nested': ({}, [
+        [r"""
+        It's possible to produce nested footnotes in LaTeX. [#]_
+        
+        .. [#] It takes some work, though. [#]_
+        .. [#] And don't even get me started on how tricky recursive footnotes would be.
+        """,
+ r"""\documentclass[a4paper]{article}
+% generated by Docutils <https://docutils.sourceforge.io/>
+\usepackage{cmap} % fix search and cut-and-paste in Acrobat
+\usepackage[T1]{fontenc}
+
+%%% Custom LaTeX preamble
+% PDF Standard Fonts
+\usepackage{mathptmx} % Times
+\usepackage[scaled=.90]{helvet}
+\usepackage{courier}
+
+%%% User specified packages and stylesheets
+
+%%% Fallback definitions for Docutils-specific commands
+
+% numerical or symbol footnotes with hyperlinks and backlinks
+\providecommand*{\DUfootnotemark}[3]{%
+  \raisebox{1em}{\hypertarget{#1}{}}%
+  \hyperlink{#2}{\textsuperscript{#3}}%
+}
+\providecommand{\DUfootnotetext}[4]{%
+  \begingroup%
+  \renewcommand{\thefootnote}{%
+    \protect\raisebox{1em}{\protect\hypertarget{#1}{}}%
+    \protect\hyperlink{#2}{#3}}%
+  \footnotetext{#4}%
+  \endgroup%
+}
 
-totest_latex_footnotes['nested'] = [
-# input
-["""\
-It's possible to produce nested footnotes in LaTeX. [#]_
+% hyperlinks:
+\ifdefined\hypersetup
+\else
+  \usepackage[hyperfootnotes=false,
+              colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref}
+  \usepackage{bookmark}
+  \urlstyle{same} % normal text font (alternatives: tt, rm, sf)
+\fi
 
-.. [#] It takes some work, though. [#]_
-.. [#] And don't even get me started on how tricky recursive footnotes would be.
-""",
-## # expected output
-head_template.substitute(dict(parts)) + r"""
-It's possible to produce nested footnotes in LaTeX.\footnote{%
-It takes some work, though.\footnotemark{}
-}\footnotetext{%
+%%% Body
+\begin{document}
+
+\begin{quote}
+It's possible to produce nested footnotes in LaTeX.\DUfootnotemark{footnote-reference-1}{footnote-1}{1}
+%
+\DUfootnotetext{footnote-1}{footnote-reference-1}{1}{%
+It takes some work, though.\DUfootnotemark{footnote-reference-2}{footnote-2}{2}
+}
+%
+\DUfootnotetext{footnote-2}{footnote-reference-2}{2}{%
 And don't even get me started on how tricky recursive footnotes would be.
 }
+\end{quote}
 
 \end{document}
-"""],
-]
+"""]]),
+    'chained': ({}, [
+        [r"""
+        It's possible to produce chained footnotes in LaTeX. [#]_
+        
+        .. [#] They're just a special case of nested footnotes. [#]_
+        .. [#] A nested footnote is a footnote on a footnote. [#]_
+        .. [#] This is a footnote on a footnote on a footnote.
+        """,
+ r"""\documentclass[a4paper]{article}
+% generated by Docutils <https://docutils.sourceforge.io/>
+\usepackage{cmap} % fix search and cut-and-paste in Acrobat
+\usepackage[T1]{fontenc}
+
+%%% Custom LaTeX preamble
+% PDF Standard Fonts
+\usepackage{mathptmx} % Times
+\usepackage[scaled=.90]{helvet}
+\usepackage{courier}
+
+%%% User specified packages and stylesheets
+
+%%% Fallback definitions for Docutils-specific commands
+
+% numerical or symbol footnotes with hyperlinks and backlinks
+\providecommand*{\DUfootnotemark}[3]{%
+  \raisebox{1em}{\hypertarget{#1}{}}%
+  \hyperlink{#2}{\textsuperscript{#3}}%
+}
+\providecommand{\DUfootnotetext}[4]{%
+  \begingroup%
+  \renewcommand{\thefootnote}{%
+    \protect\raisebox{1em}{\protect\hypertarget{#1}{}}%
+    \protect\hyperlink{#2}{#3}}%
+  \footnotetext{#4}%
+  \endgroup%
+}
 
-totest_latex_footnotes['chained'] = [
-# input
-["""\
-It's possible to produce chained footnotes in LaTeX. [#]_
+% hyperlinks:
+\ifdefined\hypersetup
+\else
+  \usepackage[hyperfootnotes=false,
+              colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref}
+  \usepackage{bookmark}
+  \urlstyle{same} % normal text font (alternatives: tt, rm, sf)
+\fi
 
-.. [#] They're just a special case of nested footnotes. [#]_
-.. [#] A nested footnote is a footnote on a footnote. [#]_
-.. [#] This is a footnote on a footnote on a footnote.
-""",
-## # expected output
-head_template.substitute(dict(parts)) + r"""
-It's possible to produce chained footnotes in LaTeX.\footnote{%
-They're just a special case of nested footnotes.\footnotemark{}
-}\footnotetext{%
-A nested footnote is a footnote on a footnote.\footnotemark{}
-}\footnotetext{%
+%%% Body
+\begin{document}
+
+\begin{quote}
+It's possible to produce chained footnotes in LaTeX.\DUfootnotemark{footnote-reference-1}{footnote-1}{1}
+%
+\DUfootnotetext{footnote-1}{footnote-reference-1}{1}{%
+They're just a special case of nested footnotes.\DUfootnotemark{footnote-reference-2}{footnote-2}{2}
+}
+%
+\DUfootnotetext{footnote-2}{footnote-reference-2}{2}{%
+A nested footnote is a footnote on a footnote.\DUfootnotemark{footnote-reference-3}{footnote-3}{3}
+}
+%
+\DUfootnotetext{footnote-3}{footnote-reference-3}{3}{%
 This is a footnote on a footnote on a footnote.
 }
+\end{quote}
 
 \end{document}
-"""],
-]
-
-totest_latex_footnotes['multinested'] = [
-# input
-["""\
+"""]]),
+    'multinested': ({}, [
+        [r"""
 LaTeX isn't the best at nested footnote support. [#]_
 
 .. [#] Specifically, it gets the numbers wrong [#]_ for "multinested"
@@ -600,21 +758,67 @@ def test_body(self):
    show up as footnote 3.
 .. [#] That's a footnote that contains more than one footnote of its own.
 """,
-## # expected output
-head_template.substitute(dict(parts)) + r"""
-LaTeX isn't the best at nested footnote support.\footnote{%
-Specifically, it gets the numbers wrong\footnotemark{} for \textquotedbl{}multinested\textquotedbl{}
-footnotes.\footnotemark{}
-}\footnotetext{%
+r"""\documentclass[a4paper]{article}
+% generated by Docutils <https://docutils.sourceforge.io/>
+\usepackage{cmap} % fix search and cut-and-paste in Acrobat
+\usepackage[T1]{fontenc}
+
+%%% Custom LaTeX preamble
+% PDF Standard Fonts
+\usepackage{mathptmx} % Times
+\usepackage[scaled=.90]{helvet}
+\usepackage{courier}
+
+%%% User specified packages and stylesheets
+
+%%% Fallback definitions for Docutils-specific commands
+
+% numerical or symbol footnotes with hyperlinks and backlinks
+\providecommand*{\DUfootnotemark}[3]{%
+  \raisebox{1em}{\hypertarget{#1}{}}%
+  \hyperlink{#2}{\textsuperscript{#3}}%
+}
+\providecommand{\DUfootnotetext}[4]{%
+  \begingroup%
+  \renewcommand{\thefootnote}{%
+    \protect\raisebox{1em}{\protect\hypertarget{#1}{}}%
+    \protect\hyperlink{#2}{#3}}%
+  \footnotetext{#4}%
+  \endgroup%
+}
+
+% hyperlinks:
+\ifdefined\hypersetup
+\else
+  \usepackage[hyperfootnotes=false,
+              colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref}
+  \usepackage{bookmark}
+  \urlstyle{same} % normal text font (alternatives: tt, rm, sf)
+\fi
+
+%%% Body
+\begin{document}
+
+LaTeX isn't the best at nested footnote support.\DUfootnotemark{footnote-reference-1}{footnote-1}{1}
+%
+\DUfootnotetext{footnote-1}{footnote-reference-1}{1}{%
+Specifically, it gets the numbers wrong\DUfootnotemark{footnote-reference-2}{footnote-2}{2} for \textquotedbl{}multinested\textquotedbl{}
+footnotes.\DUfootnotemark{footnote-reference-3}{footnote-3}{3}
+}
+%
+\DUfootnotetext{footnote-2}{footnote-reference-2}{2}{%
 For example, this should be footnote 2, but both it and the next one
 show up as footnote 3.
-}\footnotetext{%
+}
+%
+\DUfootnotetext{footnote-3}{footnote-reference-3}{3}{%
 That's a footnote that contains more than one footnote of its own.
 }
 
 \end{document}
-"""],
-]
+"""]]),
+}
+
 
 if __name__ == '__main__':
     unittest.main()
-- 
2.50.1