SF.net SVN: docutils:[10003 ] trunk/docutils/test/test _writers
milde--- via Docutils-checkins <[email protected]>
| Newsgroups | gmane.text.docutils.cvs |
|---|---|
| Message-ID | <[email protected]> |
Revision: 10003
http://sourceforge.net/p/docutils/code/10003
Author: milde
Date: 2024-12-18 22:03:08 +0000 (Wed, 18 Dec 2024)
Log Message:
-----------
Simplify latex2e writer test modules.
Remove basic publish_parts()-test in "test_latex2e.py".
Parts are now tested in a dedicated test module.
"test_latex2e.py" now only checks the "body" part of the output.
Test of syntax constructs that change the document premable (head), are
moved to "test_latex2e_parts.py".
Modified Paths:
--------------
trunk/docutils/test/test_writers/test_latex2e.py
trunk/docutils/test/test_writers/test_latex2e_misc.py
trunk/docutils/test/test_writers/test_latex2e_parts.py
Modified: trunk/docutils/test/test_writers/test_latex2e.py
===================================================================
--- trunk/docutils/test/test_writers/test_latex2e.py 2024-12-16 22:33:32 UTC (rev 10002)
+++ trunk/docutils/test/test_writers/test_latex2e.py 2024-12-18 22:03:08 UTC (rev 10003)
@@ -1,15 +1,17 @@
#! /usr/bin/env python3
# $Id$
# Author: engelbert gruber <[email protected]>
+# Maintainer: [email protected]
# Copyright: This module has been placed in the public domain.
"""
Tests for latex2e writer.
+
+This module test only the "body" part of the output.
+For tests of constructs that change the "head", see test-latex2e_parts.py.
"""
-import os
from pathlib import Path
-import string
import sys
import unittest
@@ -18,21 +20,10 @@
# so we import the local `docutils` package.
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
-from docutils.core import publish_string
+from docutils.core import publish_parts
from docutils.writers import latex2e
-# DATA_ROOT is ./test/data from the docutils root
-DATA_ROOT = Path(__file__).resolve().parents[1] / 'data'
-ham = os.path.relpath(DATA_ROOT/'ham.tex').replace('\\', '/')
-spam = os.path.relpath(DATA_ROOT/'spam').replace('\\', '/')
-# workaround for PyPy (cf. https://sourceforge.net/p/docutils/bugs/471/)
-if sys.implementation.name == "pypy" and sys.version_info < (3, 10):
- spampath = f"PosixPath('{spam}.sty')"
-else:
- spampath = f"'{spam}.sty'"
-
-
class WriterPublishTestCase(unittest.TestCase):
maxDiff = None
@@ -39,460 +30,108 @@
settings = {
'_disable_config': True,
'strict_visitor': True,
- 'output_encoding': 'unicode',
# avoid latex writer future warnings:
'use_latex_citations': False,
'legacy_column_widths': True,
}
- def test_publish(self):
+ def test_body(self):
for name, (settings_overrides, cases) in samples.items():
for casenum, (rst_input, expected) in enumerate(cases):
with self.subTest(id=f'samples[{name!r}][{casenum}]'):
- output = publish_string(
+ output = publish_parts(
source=rst_input,
writer=latex2e.Writer(),
- settings_overrides=self.settings|settings_overrides)
+ settings_overrides=self.settings|settings_overrides
+ )['body']
self.assertEqual(expected, output)
-head_template = string.Template(
-r"""$head_prefix% generated by Docutils <https://docutils.sourceforge.io/>
-\usepackage{cmap} % fix search and cut-and-paste in Acrobat
-$requirements
-%%% Custom LaTeX preamble
-$latex_preamble
-%%% User specified packages and stylesheets
-$stylesheet
-%%% Fallback definitions for Docutils-specific commands
-$fallbacks$pdfsetup
-%%% Body
-\begin{document}
-$titledata""")
-
-parts = {
-'head_prefix': r"""\documentclass[a4paper]{article}
-""",
-'requirements': r"""\usepackage[T1]{fontenc}
-""",
-'latex_preamble': r"""% PDF Standard Fonts
-\usepackage{mathptmx} % Times
-\usepackage[scaled=.90]{helvet}
-\usepackage{courier}
-""",
-'longtable': r"""\usepackage{longtable,ltcaption,array}
-\setlength{\extrarowheight}{2pt}
-\newlength{\DUtablewidth} % internal use in tables
-""",
-'stylesheet': '',
-'fallbacks': '',
-'fallbacks_highlight': r"""
-% basic code highlight:
-\providecommand*\DUrolecomment[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
-\providecommand*\DUroledeleted[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
-\providecommand*\DUrolekeyword[1]{\textbf{#1}}
-\providecommand*\DUrolestring[1]{\textit{#1}}
-
-% custom inline roles: \DUrole{#1}{#2} tries \DUrole#1{#2}
-\providecommand*{\DUrole}[2]{%
- \ifcsname DUrole#1\endcsname%
- \csname DUrole#1\endcsname{#2}%
- \else%
- #2%
- \fi%
-}
-""",
-'pdfsetup': r"""
-% hyperlinks:
-\ifdefined\hypersetup
-\else
- \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref}
- \usepackage{bookmark}
- \urlstyle{same} % normal text font (alternatives: tt, rm, sf)
-\fi
-""",
-'titledata': ''}
-
-head = head_template.substitute(parts)
-
-head_table = head_template.substitute(
- dict(parts, requirements=parts['requirements'] + parts['longtable']))
-
-head_booktabs = head_template.substitute(
- dict(parts, requirements=parts['requirements']
- + '\\usepackage{booktabs}\n' + parts['longtable']))
-
-head_image = head_template.substitute(
- dict(parts, requirements=parts['requirements']
- + '\\usepackage{graphicx}\n'))
-
-head_minitoc = head_template.substitute(
- dict(parts, requirements=parts['requirements']
- + '%% local table of contents\n'
- '\\usepackage{minitoc}\n'
- '\\dosecttoc\n'
- '\\mtcsetdepth{secttoc}{5}\n'
- '\\setcounter{secnumdepth}{0}\n'))
-
-head_textcomp = head_template.substitute(
- dict(parts, requirements=parts['requirements']
- + '\\usepackage{textcomp} % text symbol macros\n'))
-
-head_alltt = head_template.substitute(
- dict(parts, requirements=parts['requirements']
- + '\\usepackage{alltt}\n'))
-
-
samples = {}
-samples['url_chars'] = ({}, [
-["http://nowhere/url_with%28parens%29",
-head + r"""
-\url{http://nowhere/url_with\%28parens\%29}
-\end{document}
-"""],
-])
-
-samples['textcomp'] = ({}, [
-["2 µm is just 2/1000000 m",
-head_textcomp + r"""
-2 \textmu{}m is just 2/1000000 m
-
-\end{document}
-"""],
-])
-
-samples['images'] = ({}, [
-["""
-.. image:: blue%20square.png
-.. image:: vectors.svg
-""",
-head_image + r"""
-\includegraphics{blue square.png}
-
-\includegraphics{vectors.svg}
-
-\end{document}
-"""],
-])
-
-samples['svg-image'] = ({'stylesheet': 'svg'}, [
-["""
-.. image:: pixels.png
-.. image:: vectors.svg
-""",
-head_template.substitute(dict(parts,
-requirements=r"""\usepackage[T1]{fontenc}
-\usepackage{graphicx}
-""",
-stylesheet=r"""\usepackage{svg}
-""")) + r"""
-\includegraphics{pixels.png}
-
-\includesvg{vectors.svg}
-
-\end{document}
-"""],
-])
-
-samples['spanish_quote'] = ({}, [
-[".. role:: language-es\n\nUnd damit :language-es:`basta`!",
-head_template.substitute(dict(parts,
-requirements=r"""\usepackage[T1]{fontenc}
-\usepackage[spanish,main=english]{babel}
-\AtBeginDocument{\shorthandoff{.<>}}
-""")) + r"""
-Und damit \foreignlanguage{spanish}{basta}!
-
-\end{document}
-"""],
-])
-
-samples['code_role'] = ({}, [
-[':code:`x=1`',
-head_template.substitute(dict(parts, requirements=parts['requirements']
- + '\\usepackage{color}\n',
- fallbacks=parts['fallbacks_highlight']))
-+ r"""
-\texttt{\DUrole{code}{x=1}}
-
-\end{document}
-"""],
-])
-
-samples['minitoc'] = ({}, [
-# local toc reqires the minitoc package
-# and either \tableofcontents or \faketableofcontents
+samples['default'] = ({}, [
+# url chars
+['http://nowhere/url_with%28parens%29',
+ '\n\\url{http://nowhere/url_with\\%28parens\\%29}\n'
+],
+# enumerated lists
["""\
-section with local ToC
-======================
+1. Item 1.
+2. Second to the previous item this one will explain
-.. contents::
- :local:
+ a) nothing.
+ b) or some other.
-section not in local toc
-========================
-""",
-head_minitoc + r"""
+3. Third is
-\section{section with local ToC%
- \label{section-with-local-toc}%
-}
-
-\phantomsection\label{contents}
-\mtcsettitle{secttoc}{}
-\secttoc
-
-
-\section{section not in local toc%
- \label{section-not-in-local-toc}%
-}
-
-\faketableofcontents % for local ToCs
-
-\end{document}
-"""],
-])
-
-samples['table_of_contents'] = ({'use_latex_toc': False}, [
-["""\
-.. contents:: Table of Contents
-
-Title 1
-=======
-Paragraph 1.
-
-Title 2
--------
-Paragraph 2.
+ (I) having pre and postfixes
+ (II) in roman numerals.
""",
-# expected output
-head_template.substitute(dict(parts,
- requirements=parts['requirements'] + '\\setcounter{secnumdepth}{0}\n',
- fallbacks=r"""
-% class handling for environments (block-level elements)
-% \begin{DUclass}{spam} tries \DUCLASSspam and
-% \end{DUclass}{spam} tries \endDUCLASSspam
-\ifdefined\DUclass
-\else % poor man's "provideenvironment"
- \newenvironment{DUclass}[1]%
- {% "#1" does not work in end-part of environment.
- \def\DocutilsClassFunctionName{DUCLASS#1}
- \csname \DocutilsClassFunctionName \endcsname}%
- {\csname end\DocutilsClassFunctionName \endcsname}%
-\fi
+r"""
+\begin{enumerate}
+\item Item 1.
-% title for topics, admonitions, unsupported section levels, and sidebar
-\providecommand*{\DUtitle}[1]{%
- \smallskip\noindent\textbf{#1}\smallskip}
+\item Second to the previous item this one will explain
+\end{enumerate}
-\providecommand*{\DUCLASScontents}{%
- \renewenvironment{itemize}%
- {\begin{list}{}{\setlength{\partopsep}{0pt}
- \setlength{\parsep}{0pt}}
- }%
- {\end{list}}%
-}
-""")) + r"""
-\phantomsection\label{table-of-contents}
-\pdfbookmark[1]{Table of Contents}{table-of-contents}
+\begin{quote}
+\begin{enumerate}
+\renewcommand{\labelenumi}{\alph{enumi})}
+\item nothing.
-\begin{DUclass}{contents}
+\item or some other.
+\end{enumerate}
+\end{quote}
-\DUtitle{Table of Contents}
-
-\begin{itemize}
-\item \hyperref[title-1]{Title 1}
-
-\begin{itemize}
-\item \hyperref[title-2]{Title 2}
-\end{itemize}
-\end{itemize}
-\end{DUclass}
-
-
-\section{Title 1%
- \label{title-1}%
-}
-
-Paragraph 1.
-
-
-\subsection{Title 2%
- \label{title-2}%
-}
-
-Paragraph 2.
-
-\end{document}
-"""],
-])
-
-
-samples['footnote_text'] = ({}, [
-["""\
-.. [1] paragraph
-
-.. [2] 1. enumeration
-""",
-# expected output
-head_template.substitute(dict(parts,
- fallbacks=r"""
-% 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%
-}
-""")) + r"""%
-\DUfootnotetext{footnote-1}{footnote-1}{1}{%
-paragraph
-}
-%
-\DUfootnotetext{footnote-2}{footnote-2}{2}{
\begin{enumerate}
-\item enumeration
+\setcounter{enumi}{2}
+\item Third is
\end{enumerate}
-}
-\end{document}
-"""],
-])
+\begin{quote}
+\begin{enumerate}
+\renewcommand{\labelenumi}{(\Roman{enumi})}
+\item having pre and postfixes
-samples['no_sectnum'] = ({}, [
-["""\
-.. contents::
-
-unnumbered section
-------------------
-""",
-# expected output
-head_template.substitute(dict(parts,
- requirements=parts['requirements'] + '\\setcounter{secnumdepth}{0}\n'
-)) + r"""
-\phantomsection\label{contents}
-\pdfbookmark[1]{Contents}{contents}
-\tableofcontents
-
-
-\section{unnumbered section%
- \label{unnumbered-section}%
-}
-
-\end{document}
+\item in roman numerals.
+\end{enumerate}
+\end{quote}
"""],
-])
-
-samples['sectnum'] = ({}, [
-["""\
-.. contents::
-.. sectnum::
-
-first section
--------------
+# bracket protection
+["""
+* [no option] to this item
""",
-# expected output
-head_template.substitute(dict(parts,
- requirements=parts['requirements'] + '\\setcounter{secnumdepth}{0}\n'
-)) + r"""
-\phantomsection\label{contents}
-\pdfbookmark[1]{Contents}{contents}
-\tableofcontents
-
-
-\section{1~~~first section%
- \label{first-section}%
-}
-
-\end{document}
+r"""
+\begin{itemize}
+\item {[}no option{]} to this item
+\end{itemize}
"""],
-])
+# raw directive and role
+[r""".. raw:: latex
-samples['depth'] = ({}, [
-["""\
-.. contents::
- :depth: 1
+ $E=mc^2$
-first section
--------------
-""",
-# expected output
-head_template.substitute(dict(parts,
- requirements=parts['requirements'] + '\\setcounter{secnumdepth}{0}\n'
-)) + r"""
-\phantomsection\label{contents}
-\pdfbookmark[1]{Contents}{contents}
-\setcounter{tocdepth}{1}
-\tableofcontents
+A paragraph.
+.. |sub| raw:: latex
-\section{first section%
- \label{first-section}%
-}
+ (some raw text)
-\end{document}
-"""],
-])
-
-samples['book'] = ({'documentclass': 'book'}, [
-["""\
-.. contents::
- :depth: 1
-
-first chapter
--------------
+Foo |sub|
+same paragraph.
""",
-# expected output
-head_template.substitute(dict(parts,
- head_prefix=r"""\documentclass[a4paper]{book}
-""",
- requirements=parts['requirements'] + '\\setcounter{secnumdepth}{-1}\n'
-)) + r"""
-\phantomsection\label{contents}
-\pdfbookmark[1]{Contents}{contents}
-\setcounter{tocdepth}{0}
-\tableofcontents
+r"""
+$E=mc^2$
+A paragraph.
-\chapter{first chapter%
- \label{first-chapter}%
-}
-
-\end{document}
+Foo (some raw text)
+same paragraph.
"""],
])
-samples['no_sectnum'] = ({'use_latex_toc': False,
- 'sectnum_xform': False}, [
-["""\
-some text
-
-first section
--------------
-""",
-# expected output
-head_template.substitute(dict(parts, requirements=parts['requirements']
- + '\\setcounter{secnumdepth}{0}\n')) + r"""
-some text
-
-
-\section{first section%
- \label{first-section}%
-}
-
-\end{document}
-"""],
-])
-
samples['latex_sectnum'] = ({'sectnum_xform': False}, [
["""\
.. sectnum::
@@ -502,8 +141,7 @@
first section
-------------
""",
-# expected output
-head + r"""
+r"""
some text
@@ -510,8 +148,6 @@
\section{first section%
\label{first-section}%
}
-
-\end{document}
"""],
])
@@ -523,8 +159,7 @@
.. [my_cite2006]
The underscore is mishandled.
""",
-# expected output
-head + r"""
+r"""
Just a test citation \cite{my_cite2006}.
\begin{thebibliography}{my\_cite2006}
@@ -532,8 +167,6 @@
The underscore is mishandled.
}
\end{thebibliography}
-
-\end{document}
"""],
["""\
Two non-citations: [MeYou2007]_[YouMe2007]_.
@@ -548,8 +181,7 @@
.. [MeYou2007] not.
.. [YouMe2007] important.
""",
-# expected output
-head + r"""
+r"""
Two non-citations: {[}MeYou2007{]}\_{[}YouMe2007{]}\_.
Need to be separated for grouping: \cite{MeYou2007,YouMe2007}.
@@ -566,656 +198,25 @@
important.
}
\end{thebibliography}
-
-\end{document}
"""],
])
-samples['enumerated_lists'] = ({}, [
-["""\
-1. Item 1.
-2. Second to the previous item this one will explain
-
- a) nothing.
- b) or some other.
-
-3. Third is
-
- (I) having pre and postfixes
- (II) in roman numerals.
-""",
-# expected output
-head + r"""
-\begin{enumerate}
-\item Item 1.
-
-\item Second to the previous item this one will explain
-\end{enumerate}
-
-\begin{quote}
-\begin{enumerate}
-\renewcommand{\labelenumi}{\alph{enumi})}
-\item nothing.
-
-\item or some other.
-\end{enumerate}
-\end{quote}
-
-\begin{enumerate}
-\setcounter{enumi}{2}
-\item Third is
-\end{enumerate}
-
-\begin{quote}
-\begin{enumerate}
-\renewcommand{\labelenumi}{(\Roman{enumi})}
-\item having pre and postfixes
-
-\item in roman numerals.
-\end{enumerate}
-\end{quote}
-
-\end{document}
-"""],
-])
-
-# TODO: need to test for quote replacing if the language uses "ASCII-quotes"
-# as active character (e.g. de (ngerman)).
-
-
-samples['tables'] = ({}, [
-["""\
-.. table:: Foo
-
- +-----+-----+
- | | |
- +-----+-----+
- | | |
- +-----+-----+
-""",
-head_table + r"""
-\setlength{\DUtablewidth}{\linewidth}%
-\begin{longtable}{|p{0.075\DUtablewidth}|p{0.075\DUtablewidth}|}
-\caption{Foo}\\
-\hline
- & \\
-\hline
- & \\
-\hline
-\end{longtable}
-
-\end{document}
-"""],
-["""\
-.. table::
- :class: borderless
-
- +-----+-----+
- | 1 | 2 |
- +-----+-----+
- | 3 | 4 |
- +-----+-----+
-""",
-head_table + """
-\\setlength{\\DUtablewidth}{\\linewidth}%
-\\begin{longtable*}{p{0.075\\DUtablewidth}p{0.075\\DUtablewidth}}
-
-1
- & \n\
-2
- \\\\
-
-3
- & \n\
-4
- \\\\
-\\end{longtable*}
-
-\\end{document}
-"""],
-["""\
-.. table::
- :class: booktabs
-
- +-----+-+
- | 1 |2|
- +-----+-+
-""",
-head_booktabs + """
-\\setlength{\\DUtablewidth}{\\linewidth}%
-\\begin{longtable*}{p{0.075\\DUtablewidth}p{0.028\\DUtablewidth}}
-\\toprule
-
-1
- & \n\
-2
- \\\\
-\\bottomrule
-\\end{longtable*}
-
-\\end{document}
-"""],
-["""\
-.. table::
- :class: colwidths-auto
-
- +-----+-+
- | 1 |2|
- +-----+-+
-""",
-head_table + r"""
-\begin{longtable*}{|l|l|}
-\hline
-1 & 2 \\
-\hline
-\end{longtable*}
-
-\end{document}
-"""],
-["""\
-.. table::
- :widths: auto
-
- +-----+-+
- | 1 |2|
- +-----+-+
-""",
-head_table + r"""
-\begin{longtable*}{|l|l|}
-\hline
-1 & 2 \\
-\hline
-\end{longtable*}
-
-\end{document}
-"""],
-["""\
-.. table::
- :widths: 15, 30
-
- +-----+-----+
- | 1 | 2 |
- +-----+-----+
-""",
-head_table + """
-\\setlength{\\DUtablewidth}{\\linewidth}%
-\\begin{longtable*}{|p{0.191\\DUtablewidth}|p{0.365\\DUtablewidth}|}
-\\hline
-
-1
- & \n\
-2
- \\\\
-\\hline
-\\end{longtable*}
-
-\\end{document}
-"""],
-])
-
-
-samples['booktabs'] = ({'table_style': ['booktabs']}, [
-# borderless overrides "booktabs" table_style
-["""\
-.. table::
- :class: borderless
-
- +-----+-----+
- | 1 | 2 |
- +-----+-----+
- | 3 | 4 |
- +-----+-----+
-""",
-head_table + """
-\\setlength{\\DUtablewidth}{\\linewidth}%
-\\begin{longtable*}{p{0.075\\DUtablewidth}p{0.075\\DUtablewidth}}
-
-1
- & \n\
-2
- \\\\
-
-3
- & \n\
-4
- \\\\
-\\end{longtable*}
-
-\\end{document}
-"""],
-["""\
-.. table::
- :widths: auto
-
- +-----+-+
- | 1 |2|
- +-----+-+
-""",
-head_booktabs + r"""
-\begin{longtable*}{ll}
-\toprule
-1 & 2 \\
-\bottomrule
-\end{longtable*}
-
-\end{document}
-"""],
-["""\
-.. table::
- :widths: 15, 30
-
- +-----+-----+
- | 1 | 2 |
- +-----+-----+
-""",
-head_booktabs + """
-\\setlength{\\DUtablewidth}{\\linewidth}%
-\\begin{longtable*}{p{0.191\\DUtablewidth}p{0.365\\DUtablewidth}}
-\\toprule
-
-1
- & \n\
-2
- \\\\
-\\bottomrule
-\\end{longtable*}
-
-\\end{document}
-"""],
-])
-
-
-samples['colwidths_auto'] = ({'table_style': ['colwidths-auto']}, [
-["""\
-.. table::
- :class: borderless
-
- +-----+-----+
- | 1 | 2 |
- +-----+-----+
- | 3 | 4 |
- +-----+-----+
-""",
-head_table + r"""
-\begin{longtable*}{ll}
-1 & 2 \\
-3 & 4 \\
-\end{longtable*}
-
-\end{document}
-"""],
-["""\
-.. table::
- :class: booktabs
-
- +-----+-+
- | 1 |2|
- +-----+-+
-""",
-head_booktabs + r"""
-\begin{longtable*}{ll}
-\toprule
-1 & 2 \\
-\bottomrule
-\end{longtable*}
-
-\end{document}
-"""],
-# given width overrides "colwidth-auto"
-["""\
-.. table::
- :widths: 15, 30
-
- +-----+-----+
- | 1 | 2 |
- +-----+-----+
-""",
-head_table + """
-\\setlength{\\DUtablewidth}{\\linewidth}%
-\\begin{longtable*}{|p{0.191\\DUtablewidth}|p{0.365\\DUtablewidth}|}
-\\hline
-
-1
- & \n\
-2
- \\\\
-\\hline
-\\end{longtable*}
-
-\\end{document}
-"""],
-])
-
-samples['table_align'] = ({}, [
-["""\
-.. table::
- :align: right
-
- +-----+-----+
- | 1 | 2 |
- +-----+-----+
-""",
-head_table + """
-\\setlength{\\DUtablewidth}{\\linewidth}%
-\\begin{longtable*}[r]{|p{0.075\\DUtablewidth}|p{0.075\\DUtablewidth}|}
-\\hline
-
-1
- & \n\
-2
- \\\\
-\\hline
-\\end{longtable*}
-
-\\end{document}
-"""],
-])
-
-samples['table_empty_cells'] = ({}, [
-["""\
-===== ======
-Title
-===== ======
-entry value1
-===== ======
-""",
-head_table + """
-\\setlength{\\DUtablewidth}{\\linewidth}%
-\\begin{longtable*}{|p{0.075\\DUtablewidth}|p{0.086\\DUtablewidth}|}
-\\hline
-\\textbf{%
-Title
-} & \\\\
-\\hline
-\\endfirsthead
-\\hline
-\\textbf{%
-Title
-} & \\\\
-\\hline
-\\endhead
-\\multicolumn{2}{p{0.16\\DUtablewidth}}{\\raggedleft\\ldots continued on next page}\\\\
-\\endfoot
-\\endlastfoot
-
-entry
- & \n\
-value1
- \\\\
-\\hline
-\\end{longtable*}
-
-\\end{document}
-"""],
-["""\
-+----+----+
-| c3 | c4 |
-+----+----+
-| |
-+---------+
-""",
-head_table + """
-\\setlength{\\DUtablewidth}{\\linewidth}%
-\\begin{longtable*}{|p{0.063\\DUtablewidth}|p{0.063\\DUtablewidth}|}
-\\hline
-
-c3
- & \n\
-c4
- \\\\
-\\hline
-\\multicolumn{2}{|p{0.13\\DUtablewidth}|}{} \\\\
-\\hline
-\\end{longtable*}
-
-\\end{document}
-"""],
-])
-
-samples['table_nonstandard_class'] = ({}, [
-["""\
-.. table::
- :class: my-class
-
- +-----+-----+
- | 1 | 2 |
- +-----+-----+
- | 3 | 4 |
- +-----+-----+
-""",
-head_template.substitute(
- dict(
- parts,
- requirements=parts['requirements'] + parts['longtable'],
- fallbacks=r"""
-% class handling for environments (block-level elements)
-% \begin{DUclass}{spam} tries \DUCLASSspam and
-% \end{DUclass}{spam} tries \endDUCLASSspam
-\ifdefined\DUclass
-\else % poor man's "provideenvironment"
- \newenvironment{DUclass}[1]%
- {% "#1" does not work in end-part of environment.
- \def\DocutilsClassFunctionName{DUCLASS#1}
- \csname \DocutilsClassFunctionName \endcsname}%
- {\csname end\DocutilsClassFunctionName \endcsname}%
-\fi
-"""
- )
-) + """
-\\begin{DUclass}{my-class}
-\\setlength{\\DUtablewidth}{\\linewidth}%
-\\begin{longtable*}{|p{0.075\\DUtablewidth}|p{0.075\\DUtablewidth}|}
-\\hline
-
-1
- & \n\
-2
- \\\\
-\\hline
-
-3
- & \n\
-4
- \\\\
-\\hline
-\\end{longtable*}
-\\end{DUclass}
-
-\\end{document}
-"""],
-])
-
-# The "[" needs to be protected (otherwise it will be seen as an
-# option to "\\", "\item", etc. ).
-samples['bracket_protection'] = ({}, [
-["""
-* [no option] to this item
-""",
-head + r"""
-\begin{itemize}
-\item {[}no option{]} to this item
-\end{itemize}
-
-\end{document}
-"""],
-])
-
-samples['literal_block'] = ({}, [
-["""\
-Test special characters { [ \\\\ ] } in literal block::
-
- { [ ( \\macro
-
- } ] )
-""",
-head_alltt + r"""
-Test special characters \{ {[} \textbackslash{} {]} \} in literal block:
-
-\begin{quote}
-\begin{alltt}
-\{ [ ( \textbackslash{}macro
-
-\} ] )
-\end{alltt}
-\end{quote}
-
-\end{document}
-"""],
-])
-
-samples['raw'] = ({}, [
-[r""".. raw:: latex
-
- $E=mc^2$
-
-A paragraph.
-
-.. |sub| raw:: latex
-
- (some raw text)
-
-Foo |sub|
-same paragraph.
-""",
-head + r"""
-$E=mc^2$
-
-A paragraph.
-
-Foo (some raw text)
-same paragraph.
-
-\end{document}
-"""],
-[r""".. compound::
-
- Compound paragraph
-
- .. raw:: LaTeX
-
- raw LaTeX block
-
- compound paragraph continuation.
-""",
-head_template.substitute(
- dict(parts,
- fallbacks=r"""
-% class handling for environments (block-level elements)
-% \begin{DUclass}{spam} tries \DUCLASSspam and
-% \end{DUclass}{spam} tries \endDUCLASSspam
-\ifdefined\DUclass
-\else % poor man's "provideenvironment"
- \newenvironment{DUclass}[1]%
- {% "#1" does not work in end-part of environment.
- \def\DocutilsClassFunctionName{DUCLASS#1}
- \csname \DocutilsClassFunctionName \endcsname}%
- {\csname end\DocutilsClassFunctionName \endcsname}%
-\fi
-""")
-) + r"""
-\begin{DUclass}{compound}
-Compound paragraph
-raw LaTeX block
-compound paragraph continuation.
-\end{DUclass}
-
-\end{document}
-"""],
-])
-
-samples['title_with_inline_markup'] = ({}, [
-["""\
-This is the *Title*
-===================
-
-This is the *Subtitle*
-----------------------
-
-This is a *section title*
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This is the *document*.
-""",
-head_template.substitute(dict(parts,
- requirements=parts['requirements'] + '\\setcounter{secnumdepth}{0}\n',
- fallbacks=r"""
-% subtitle (in document title)
-\providecommand*{\DUdocumentsubtitle}[1]{{\large #1}}
-""",
- pdfsetup=parts['pdfsetup'] + r"""\hypersetup{
- pdftitle={This is the Title},
-}
-""", titledata=r"""\title{This is the \emph{Title}%
- \label{this-is-the-title}%
- \\%
- \DUdocumentsubtitle{This is the \emph{Subtitle}}%
- \label{this-is-the-subtitle}}
-\author{}
-\date{}
-""")) + r"""\maketitle
-
-
-\section{This is a \emph{section title}%
- \label{this-is-a-section-title}%
-}
-
-This is the \emph{document}.
-
-\end{document}
-"""],
-])
-
-
-samples['stylesheet_path'] = ({'stylesheet_path': f'{spam},{ham}'}, [
-["""two stylesheet links in the header""",
-head_template.substitute(dict(parts,
-stylesheet=r"""\usepackage{%s}
-\input{%s}
-""" % (spam, ham))) + r"""
-two stylesheet links in the header
-
-\end{document}
-"""],
-])
-
-samples['embed_stylesheet'] = ({'stylesheet_path': f'{spam},{ham}',
- 'embed_stylesheet': True,
- 'warning_stream': ''}, [
-["""two stylesheets embedded in the header""",
-head_template.substitute(dict(parts,
-stylesheet=f"""\
-% Cannot embed stylesheet:
-% [Errno 2] No such file or directory: {spampath}
-% embedded stylesheet: {ham}
-\\newcommand{{\\ham}}{{wonderful ham}}
-
-""")) + r"""
-two stylesheets embedded in the header
-
-\end{document}
-"""],
-])
-
samples['bibtex'] = ({'use_bibtex': ['alpha', 'xampl']}, [
["""\
Just a test citation [book-full]_.
""",
-head + r"""
+r"""
Just a test citation \cite{book-full}.
\bibliographystyle{alpha}
\bibliography{xampl}
-
-\end{document}
"""],
["""\
No bibliography if there is no citation.
""",
-head + r"""
+r"""
No bibliography if there is no citation.
-
-\end{document}
"""],
])
Modified: trunk/docutils/test/test_writers/test_latex2e_misc.py
===================================================================
--- trunk/docutils/test/test_writers/test_latex2e_misc.py 2024-12-16 22:33:32 UTC (rev 10002)
+++ trunk/docutils/test/test_writers/test_latex2e_misc.py 2024-12-18 22:03:08 UTC (rev 10003)
@@ -94,36 +94,7 @@
self.assertNotIn(r'\item \hyperref[foo]{foo}', result)
self.assertIn(r'\tableofcontents', result)
- def test_publish_parts(self):
- """Check for the presence of documented parts.
- """
- parts = core.publish_parts(sample_multiterm,
- writer=latex2e.Writer(),
- settings_overrides=self.settings)
- documented_parts = [
- 'abstract',
- 'body',
- 'body_pre_docinfo',
- 'dedication',
- 'docinfo',
- 'encoding',
- 'errors',
- 'fallbacks',
- 'head_prefix',
- 'latex_preamble',
- 'pdfsetup',
- 'requirements',
- 'stylesheet',
- 'subtitle',
- 'title',
- 'titledata',
- 'version',
- 'whole'
- ]
- self.assertEqual(documented_parts, sorted(parts.keys()))
- self.assertEqual(expected_multiterm, parts['body'])
-
class WarningsTestCase(unittest.TestCase):
def test_future_warnings(self):
Modified: trunk/docutils/test/test_writers/test_latex2e_parts.py
===================================================================
--- trunk/docutils/test/test_writers/test_latex2e_parts.py 2024-12-16 22:33:32 UTC (rev 10002)
+++ trunk/docutils/test/test_writers/test_latex2e_parts.py 2024-12-18 22:03:08 UTC (rev 10003)
@@ -19,6 +19,7 @@
"""
from pathlib import Path
+import os
import sys
import unittest
@@ -32,35 +33,18 @@
from docutils.core import publish_parts
from docutils.writers import latex2e
+# DATA_ROOT is ./test/data from the docutils root
+DATA_ROOT = Path(__file__).resolve().parents[1] / 'data'
-class LaTeXWriterPublishPartsTestCase(unittest.TestCase):
- """Test LaTeX writer `publish_parts()` interface."""
+ham = os.path.relpath(DATA_ROOT/'ham.tex').replace('\\', '/')
+spam = os.path.relpath(DATA_ROOT/'spam').replace('\\', '/')
+# workaround for PyPy (cf. https://sourceforge.net/p/docutils/bugs/471/)
+if sys.implementation.name == "pypy" and sys.version_info < (3, 10):
+ spampath = f"PosixPath('{spam}.sty')"
+else:
+ spampath = f"'{spam}.sty'"
- maxDiff = None
- settings = {'_disable_config': True,
- 'strict_visitor': True,
- # avoid latex writer future warnings:
- 'use_latex_citations': False,
- 'legacy_column_widths': True,
- }
-
- def test_publish_parts(self):
- for name, (settings_overrides, cases) in samples.items():
- for casenum, (case_input, expected_parts) in enumerate(cases):
- parts = publish_parts(
- source=case_input,
- writer=latex2e.Writer(),
- settings_overrides=self.settings|settings_overrides,
- )
- expected = default_parts | expected_parts
- expected['whole'] = expected['whole'].format(**expected)
-
- for key in parts.keys():
- with self.subTest(id=f'samples[{name!r}][{casenum}][{key}]'):
- self.assertEqual(f'{expected[key]}', f'{parts[key]}')
-
-
-default_parts = {
+DEFAULT_PARTS = {
'abstract': '',
'body': '',
'body_pre_docinfo': '',
@@ -74,13 +58,14 @@
'\\usepackage{mathptmx} % Times\n'
'\\usepackage[scaled=.90]{helvet}\n'
'\\usepackage{courier}\n',
- 'pdfsetup': '% hyperlinks:\n'
- '\\ifdefined\\hypersetup\n'
- '\\else\n'
- ' \\usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref}\n'
- ' \\usepackage{bookmark}\n'
- ' \\urlstyle{same} % normal text font (alternatives: tt, rm, sf)\n'
- '\\fi\n',
+ 'pdfsetup': r"""% hyperlinks:
+\ifdefined\hypersetup
+\else
+ \usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref}
+ \usepackage{bookmark}
+ \urlstyle{same} % normal text font (alternatives: tt, rm, sf)
+\fi
+""",
'requirements': '\\usepackage[T1]{fontenc}\n',
'stylesheet': '',
'subtitle': '',
@@ -87,23 +72,43 @@
'title': '',
'titledata': '',
'version': f'{docutils.__version__}',
- 'whole': '{head_prefix}'
- '% generated by Docutils <https://docutils.sourceforge.io/>\n'
- '\\usepackage{{cmap}} % fix search and cut-and-paste in Acrobat\n'
- '{requirements}\n'
- '%%% Custom LaTeX preamble\n'
- '{latex_preamble}\n'
- '%%% User specified packages and stylesheets\n'
- '{stylesheet}\n'
- '%%% Fallback definitions for Docutils-specific commands\n'
- '{fallbacks}\n'
- '{pdfsetup}\n'
- '%%% Body\n'
- '\\begin{{document}}\n'
- '{body}\n'
- '\\end{{document}}\n'
- }
+ }
+
+REQUIREMENTS_TABLE = r"""\usepackage{longtable,ltcaption,array}
+\setlength{\extrarowheight}{2pt}
+\newlength{\DUtablewidth} % internal use in tables
+"""
+
+
+class LaTeXWriterPublishPartsTestCase(unittest.TestCase):
+ """Test LaTeX writer `publish_parts()` interface."""
+
+ maxDiff = None
+ settings = {'_disable_config': True,
+ 'strict_visitor': True,
+ # avoid latex writer future warnings:
+ 'use_latex_citations': False,
+ 'legacy_column_widths': True,
+ }
+
+ def test_publish_parts(self):
+ for name, (settings_overrides, cases) in samples.items():
+ for casenum, (case_input, expected) in enumerate(cases):
+ parts = publish_parts(
+ source=case_input,
+ writer=latex2e.Writer(),
+ settings_overrides=self.settings|settings_overrides,
+ )
+ expected = DEFAULT_PARTS | expected
+ with self.subTest(id=f'samples[{name!r}][{casenum}]'):
+ for key in parts.keys():
+ if key == 'whole':
+ continue # assembly tested in functional tests
+ self.assertEqual(f'{expected[key]}', f'{parts[key]}',
+ msg=f'Differences in part "{key}"!')
+
+
samples = {}
samples['default'] = ({}, [
@@ -110,8 +115,883 @@
['', # empty input string
{} # results in default parts
],
+['2 µm is just 2/1000000 m',
+ {'body': '\n2 µm is just 2/1000000 m\n',
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\usepackage{textcomp} % text symbol macros\n',
+ }
+ ],
+# load "babel" if there is a text part in a foreign language
+["""\
+.. role:: language-es
+
+Und damit :language-es:`basta`!
+""",
+ {'body': r"""
+Und damit \foreignlanguage{spanish}{basta}!
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\usepackage[spanish,main=english]{babel}\n'
+ '\\AtBeginDocument{\\shorthandoff{.<>}}\n'
+ }],
+# load requirements for code syntax higlight
+[':code:`x=1`',
+ {'body': '\n\\texttt{\\DUrole{code}{x=1}}\n',
+ 'fallbacks': r"""
+% basic code highlight:
+\providecommand*\DUrolecomment[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
+\providecommand*\DUroledeleted[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}}
+\providecommand*\DUrolekeyword[1]{\textbf{#1}}
+\providecommand*\DUrolestring[1]{\textit{#1}}
+
+% custom inline roles: \DUrole{#1}{#2} tries \DUrole#1{#2}
+\providecommand*{\DUrole}[2]{%
+ \ifcsname DUrole#1\endcsname%
+ \csname DUrole#1\endcsname{#2}%
+ \else%
+ #2%
+ \fi%
+}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\usepackage{color}\n'
+ }],
+# footnote text
+["""\
+.. [1] paragraph
+
+.. [2] 1. enumeration
+""",
+ {'body': r"""%
+\DUfootnotetext{footnote-1}{footnote-1}{1}{%
+paragraph
+}
+%
+\DUfootnotetext{footnote-2}{footnote-2}{2}{
+\begin{enumerate}
+\item enumeration
+\end{enumerate}
+}
+""",
+ 'fallbacks': r"""
+% 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%
+}
+""",
+ }],
+# no section numbering: switch off section numbering in requirements
+["""\
+.. contents::
+
+unnumbered section
+------------------
+""",
+ {'body': r"""
+\phantomsection\label{contents}
+\pdfbookmark[1]{Contents}{contents}
+\tableofcontents
+
+
+\section{unnumbered section%
+ \label{unnumbered-section}%
+}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\setcounter{secnumdepth}{0}\n',
+ }],
+# Docutils section numbering: switch off section numbering in requirements
+["""\
+.. contents::
+.. sectnum::
+
+first section
+-------------
+""",
+ {'body': r"""
+\phantomsection\label{contents}
+\pdfbookmark[1]{Contents}{contents}
+\tableofcontents
+
+
+\section{1 first section%
+ \label{first-section}%
+}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\setcounter{secnumdepth}{0}\n',
+ }],
+# LaTeX ToC with limited depth, no section numbers
+["""\
+.. contents::
+ :depth: 1
+
+first section
+-------------
+""",
+ {'body': r"""
+\phantomsection\label{contents}
+\pdfbookmark[1]{Contents}{contents}
+\setcounter{tocdepth}{1}
+\tableofcontents
+
+
+\section{first section%
+ \label{first-section}%
+}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\setcounter{secnumdepth}{0}\n',
+ }],
+# local ToC reqires "minitoc" and \tableofcontents or \faketableofcontents
+["""\
+section with local ToC
+======================
+
+.. contents::
+ :local:
+
+section not in local toc
+========================
+""",
+ {'body': r"""
+
+\section{section with local ToC%
+ \label{section-with-local-toc}%
+}
+
+\phantomsection\label{contents}
+\mtcsettitle{secttoc}{}
+\secttoc
+
+
+\section{section not in local toc%
+ \label{section-not-in-local-toc}%
+}
+
+\faketableofcontents % for local ToCs
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '%% local table of contents\n'
+ '\\usepackage{minitoc}\n'
+ '\\dosecttoc\n'
+ '\\mtcsetdepth{secttoc}{5}\n'
+ '\\setcounter{secnumdepth}{0}\n'
+ }],
+# include images with "\includegraphics", load "graphicx" package
+["""\
+.. image:: blue%20square.png
+.. image:: vectors.svg
+""",
+ {'body': r"""
+\includegraphics{blue square.png}
+
+\includegraphics{vectors.svg}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\usepackage{graphicx}\n',
+ }],
+# table with caption
+["""\
+.. table:: Foo
+
+ +-----+-----+
+ | | |
+ +-----+-----+
+ | | |
+ +-----+-----+
+""",
+ {'body': r"""
+\setlength{\DUtablewidth}{\linewidth}%
+\begin{longtable}{|p{0.075\DUtablewidth}|p{0.075\DUtablewidth}|}
+\caption{Foo}\\
+\hline
+ & \\
+\hline
+ & \\
+\hline
+\end{longtable}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ + REQUIREMENTS_TABLE,
+ }],
+# borderless table
+["""\
+.. table::
+ :class: borderless
+
+ +-----+-----+
+ | 1 | 2 |
+ +-----+-----+
+ | 3 | 4 |
+ +-----+-----+
+""",
+ {'body': """
+\\setlength{\\DUtablewidth}{\\linewidth}%
+\\begin{longtable*}{p{0.075\\DUtablewidth}p{0.075\\DUtablewidth}}
+
+1
+ & \n\
+2
+ \\\\
+
+3
+ & \n\
+4
+ \\\\
+\\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# table style "booktabs"
+["""\
+.. table::
+ :class: booktabs
+
+ +-----+-+
+ | 1 |2|
+ +-----+-+
+""",
+ {'body': """
+\\setlength{\\DUtablewidth}{\\linewidth}%
+\\begin{longtable*}{p{0.075\\DUtablewidth}p{0.028\\DUtablewidth}}
+\\toprule
+
+1
+ & \n\
+2
+ \\\\
+\\bottomrule
+\\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\usepackage{booktabs}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# collumn widths determined by LaTeX (via class argument)
+["""\
+.. table::
+ :class: colwidths-auto
+
+ +-----+-+
+ | 1 |2|
+ +-----+-+
+""",
+ {'body': r"""
+\begin{longtable*}{|l|l|}
+\hline
+1 & 2 \\
+\hline
+\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# collumn widths determined by LaTeX (via "width" option)
+["""\
+.. table::
+ :widths: auto
+
+ +-----+-+
+ | 1 |2|
+ +-----+-+
+""",
+ {'body': r"""
+\begin{longtable*}{|l|l|}
+\hline
+1 & 2 \\
+\hline
+\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# collumn widths specified via "width" option
+["""\
+.. table::
+ :widths: 15, 30
+
+ +-----+-----+
+ | 1 | 2 |
+ +-----+-----+
+""",
+ {'body': """
+\\setlength{\\DUtablewidth}{\\linewidth}%
+\\begin{longtable*}{|p{0.191\\DUtablewidth}|p{0.365\\DUtablewidth}|}
+\\hline
+
+1
+ & \n\
+2
+ \\\\
+\\hline
+\\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# table alignment
+["""\
+.. table::
+ :align: right
+
+ +-----+-----+
+ | 1 | 2 |
+ +-----+-----+
+""",
+ {'body': """
+\\setlength{\\DUtablewidth}{\\linewidth}%
+\\begin{longtable*}[r]{|p{0.075\\DUtablewidth}|p{0.075\\DUtablewidth}|}
+\\hline
+
+1
+ & \n\
+2
+ \\\\
+\\hline
+\\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# table with title row and empty cell
+["""\
+===== ======
+Title
+===== ======
+entry value1
+===== ======
+""",
+ {'body': """
+\\setlength{\\DUtablewidth}{\\linewidth}%
+\\begin{longtable*}{|p{0.075\\DUtablewidth}|p{0.086\\DUtablewidth}|}
+\\hline
+\\textbf{%
+Title
+} & \\\\
+\\hline
+\\endfirsthead
+\\hline
+\\textbf{%
+Title
+} & \\\\
+\\hline
+\\endhead
+\\multicolumn{2}{p{0.16\\DUtablewidth}}{\\raggedleft\\ldots continued on next page}\\\\
+\\endfoot
+\\endlastfoot
+
+entry
+ & \n\
+value1
+ \\\\
+\\hline
+\\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# table with emtpy rowspanning cell
+["""\
++----+----+
+| c3 | c4 |
++----+----+
+| |
++---------+
+""",
+ {'body': """
+\\setlength{\\DUtablewidth}{\\linewidth}%
+\\begin{longtable*}{|p{0.063\\DUtablewidth}|p{0.063\\DUtablewidth}|}
+\\hline
+
+c3
+ & \n\
+c4
+ \\\\
+\\hline
+\\multicolumn{2}{|p{0.13\\DUtablewidth}|}{} \\\\
+\\hline
+\\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# table with custom class value
+["""\
+.. table::
+ :class: my-class
+
+ +-----+-----+
+ | 1 | 2 |
+ +-----+-----+
+ | 3 | 4 |
+ +-----+-----+
+""",
+ {'body': """
+\\begin{DUclass}{my-class}
+\\setlength{\\DUtablewidth}{\\linewidth}%
+\\begin{longtable*}{|p{0.075\\DUtablewidth}|p{0.075\\DUtablewidth}|}
+\\hline
+
+1
+ & \n\
+2
+ \\\\
+\\hline
+
+3
+ & \n\
+4
+ \\\\
+\\hline
+\\end{longtable*}
+\\end{DUclass}
+""",
+ 'fallbacks': r"""
+% class handling for environments (block-level elements)
+% \begin{DUclass}{spam} tries \DUCLASSspam and
+% \end{DUclass}{spam} tries \endDUCLASSspam
+\ifdefined\DUclass
+\else % poor man's "provideenvironment"
+ \newenvironment{DUclass}[1]%
+ {% "#1" does not work in end-part of environment.
+ \def\DocutilsClassFunctionName{DUCLASS#1}
+ \csname \DocutilsClassFunctionName \endcsname}%
+ {\csname end\DocutilsClassFunctionName \endcsname}%
+\fi
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# literal block
+["""\
+Test special characters { [ \\\\ ] } in literal block::
+
+ { [ ( \\macro
+
+ } ] )
+""",
+ {'body': r"""
+Test special characters \{ {[} \textbackslash{} {]} \} in literal block:
+
+\begin{quote}
+\begin{alltt}
+\{ [ ( \textbackslash{}macro
+
+\} ] )
+\end{alltt}
+\end{quote}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\usepackage{alltt}\n'
+ }],
+# raw block in compound directive
+["""\
+.. compound::
+
+ Compound paragraph
+
+ .. raw:: LaTeX
+
+ raw LaTeX block
+
+ compound paragraph continuation.
+""",
+ {'body': r"""
+\begin{DUclass}{compound}
+Compound paragraph
+raw LaTeX block
+compound paragraph continuation.
+\end{DUclass}
+""",
+ 'fallbacks': r"""
+% class handling for environments (block-level elements)
+% \begin{DUclass}{spam} tries \DUCLASSspam and
+% \end{DUclass}{spam} tries \endDUCLASSspam
+\ifdefined\DUclass
+\else % poor man's "provideenvironment"
+ \newenvironment{DUclass}[1]%
+ {% "#1" does not work in end-part of environment.
+ \def\DocutilsClassFunctionName{DUCLASS#1}
+ \csname \DocutilsClassFunctionName \endcsname}%
+ {\csname end\DocutilsClassFunctionName \endcsname}%
+\fi
+""",
+ }],
+# titles with inline markup
+["""\
+This is the *Title*
+===================
+
+This is the *Subtitle*
+----------------------
+
+This is a *section title*
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the *document*.
+""",
+ {'body': r"""
+
+\section{This is a \emph{section title}%
+ \label{this-is-a-section-title}%
+}
+
+This is the \emph{document}.
+""",
+ 'body_pre_docinfo': '\\maketitle\n',
+ 'fallbacks': r"""
+% subtitle (in document title)
+\providecommand*{\DUdocumentsubtitle}[1]{{\large #1}}
+""",
+ 'pdfsetup': DEFAULT_PARTS['pdfsetup'] + r"""\hypersetup{
+ pdftitle={This is the Title},
+}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\setcounter{secnumdepth}{0}\n',
+ 'subtitle': 'This is the \\emph{Subtitle}',
+ 'title': 'This is the \\emph{Title}',
+ 'titledata': r"""\title{This is the \emph{Title}%
+ \label{this-is-the-title}%
+ \\%
+ \DUdocumentsubtitle{This is the \emph{Subtitle}}%
+ \label{this-is-the-subtitle}}
+\author{}
+\date{}
+"""
+ }],
+
+# template
+["""\
+""",
+ {'body': '',
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ }],
+
])
+samples['book'] = ({'documentclass': 'book'}, [
+# Top section level in LaTeX "book" class is 0 (chapter)
+["""\
+.. contents::
+ :depth: 1
+first chapter
+-------------
+""",
+ {'body': r"""
+\phantomsection\label{contents}
+\pdfbookmark[1]{Contents}{contents}
+\setcounter{tocdepth}{0}
+\tableofcontents
+
+
+\chapter{first chapter%
+ \label{first-chapter}%
+}
+""",
+ 'head_prefix': '\\documentclass[a4paper]{book}\n',
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\setcounter{secnumdepth}{-1}\n',
+ }],
+])
+
+samples['booktabs'] = ({'table_style': ['booktabs']}, [
+# column width determined by LaTeX
+["""\
+.. table::
+ :widths: auto
+
+ +-----+-+
+ | 1 |2|
+ +-----+-+
+""",
+ {'body': r"""
+\begin{longtable*}{ll}
+\toprule
+1 & 2 \\
+\bottomrule
+\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\usepackage{booktabs}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# column widhts specified via option
+["""\
+.. table::
+ :widths: 15, 30
+
+ +-----+-----+
+ | 1 | 2 |
+ +-----+-----+
+""",
+ {'body': """
+\\setlength{\\DUtablewidth}{\\linewidth}%
+\\begin{longtable*}{p{0.191\\DUtablewidth}p{0.365\\DUtablewidth}}
+\\toprule
+
+1
+ & \n\
+2
+ \\\\
+\\bottomrule
+\\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\usepackage{booktabs}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# borderless overrides "booktabs" table_style
+["""\
+.. table::
+ :class: borderless
+
+ +-----+-----+
+ | 1 | 2 |
+ +-----+-----+
+ | 3 | 4 |
+ +-----+-----+
+""",
+ {'body': """
+\\setlength{\\DUtablewidth}{\\linewidth}%
+\\begin{longtable*}{p{0.075\\DUtablewidth}p{0.075\\DUtablewidth}}
+
+1
+ & \n\
+2
+ \\\\
+
+3
+ & \n\
+4
+ \\\\
+\\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ + REQUIREMENTS_TABLE
+ }],
+
+])
+
+
+samples['colwidths_auto'] = ({'table_style': ['colwidths-auto']}, [
+# borderless table with auto-width columns
+["""\
+.. table::
+ :class: borderless
+
+ +-----+-----+
+ | 1 | 2 |
+ +-----+-----+
+ | 3 | 4 |
+ +-----+-----+
+""",
+ {'body': r"""
+\begin{longtable*}{ll}
+1 & 2 \\
+3 & 4 \\
+\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# booktabs style table with auto-width columns
+["""\
+.. table::
+ :class: booktabs
+
+ +-----+-+
+ | 1 |2|
+ +-----+-+
+""",
+ {'body': r"""
+\begin{longtable*}{ll}
+\toprule
+1 & 2 \\
+\bottomrule
+\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\usepackage{booktabs}\n'
+ + REQUIREMENTS_TABLE
+ }],
+# given width overrides "colwidth-auto"
+["""\
+.. table::
+ :widths: 15, 30
+
+ +-----+-----+
+ | 1 | 2 |
+ +-----+-----+
+""",
+ {'body': """
+\\setlength{\\DUtablewidth}{\\linewidth}%
+\\begin{longtable*}{|p{0.191\\DUtablewidth}|p{0.365\\DUtablewidth}|}
+\\hline
+
+1
+ & \n\
+2
+ \\\\
+\\hline
+\\end{longtable*}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ + REQUIREMENTS_TABLE
+ }],
+])
+
+samples['Docutils ToC and sectnum'] = ({'use_latex_toc': False}, [
+["""\
+.. contents:: Table of Contents
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+""",
+ {'body': r"""
+\phantomsection\label{table-of-contents}
+\pdfbookmark[1]{Table of Contents}{table-of-contents}
+
+\begin{DUclass}{contents}
+
+\DUtitle{Table of Contents}
+
+\begin{itemize}
+\item \hyperref[title-1]{Title 1}
+
+\begin{itemize}
+\item \hyperref[title-2]{Title 2}
+\end{itemize}
+\end{itemize}
+\end{DUclass}
+
+
+\section{Title 1%
+ \label{title-1}%
+}
+
+Paragraph 1.
+
+
+\subsection{Title 2%
+ \label{title-2}%
+}
+
+Paragraph 2.
+""",
+ 'fallbacks': r"""
+% class handling for environments (block-level elements)
+% \begin{DUclass}{spam} tries \DUCLASSspam and
+% \end{DUclass}{spam} tries \endDUCLASSspam
+\ifdefined\DUclass
+\else % poor man's "provideenvironment"
+ \newenvironment{DUclass}[1]%
+ {% "#1" does not work in end-part of environment.
+ \def\DocutilsClassFunctionName{DUCLASS#1}
+ \csname \DocutilsClassFunctionName \endcsname}%
+ {\csname end\DocutilsClassFunctionName \endcsname}%
+\fi
+
+% title for topics, admonitions, unsupported section levels, and sidebar
+\providecommand*{\DUtitle}[1]{%
+ \smallskip\noindent\textbf{#1}\smallskip}
+
+\providecommand*{\DUCLASScontents}{%
+ \renewenvironment{itemize}%
+ {\begin{list}{}{\setlength{\partopsep}{0pt}
+ \setlength{\parsep}{0pt}}
+ }%
+ {\end{list}}%
+}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\setcounter{secnumdepth}{0}\n',
+ }],
+])
+
+
+samples['embed_stylesheet'] = ({'stylesheet_path': f'{spam},{ham}',
+ 'embed_stylesheet': True,
+ 'warning_stream': ''}, [
+['two stylesheets embedded in the header',
+ {'body': '\ntwo stylesheets embedded in the header\n',
+ 'stylesheet': f"""\
+% Cannot embed stylesheet:
+% [Errno 2] No such file or directory: {spampath}
+% embedded stylesheet: {ham}
+\\newcommand{{\\ham}}{{wonderful ham}}
+
+""",
+ }],
+])
+
+
+samples['sectnum_xform False'] = ({'sectnum_xform': False}, [
+# no section numbers
+["""\
+some text
+
+first section
+-------------
+""",
+ {'body': r"""
+some text
+
+
+\section{first section%
+ \label{first-section}%
+}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\setcounter{secnumdepth}{0}\n',
+ }],
+])
+
+samples['stylesheet_path'] = ({'stylesheet_path': f'{spam},{ham}'}, [
+['two stylesheet links in the header',
+ {'body': '\ntwo stylesheet links in the header\n',
+ 'stylesheet': f'\\usepackage{{{spam}}}\n'
+ f'\\input{{{ham}}}\n'
+ }],
+])
+
+# if "svg" package is listed, include SVG images with "\includesvg"
+samples['svg-image'] = ({'stylesheet': 'svg'}, [
+["""\
+.. image:: blue%20square.png
+.. image:: vectors.svg
+""",
+ {'body': r"""
+\includegraphics{blue square.png}
+
+\includesvg{vectors.svg}
+""",
+ 'requirements': '\\usepackage[T1]{fontenc}\n'
+ '\\usepackage{graphicx}\n',
+ 'stylesheet': '\\usepackage{svg}\n'
+ }],
+])
+
+# TODO: test for quote replacing if the language uses "ASCII-quotes"
+# as active character (e.g. de (ngerman)).
+
+
if __name__ == '__main__':
unittest.main()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
_______________________________________________
Docutils-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/docutils-checkins