SF.net SVN: docutils:[9932] trunk/docutils
milde--- via Docutils-checkins <[email protected]>
| Newsgroups | gmane.text.docutils.cvs |
|---|---|
| Message-ID | <[email protected]> |
Revision: 9932
http://sourceforge.net/p/docutils/code/9932
Author: milde
Date: 2024-09-19 10:20:44 +0000 (Thu, 19 Sep 2024)
Log Message:
-----------
Revise/fix handling of length specifications.
Don't use the generic number-formatter "g" to drop trailing zeroes
in `nodes.validate_measure()` to avoid writing large values in
scientific format (which is not supported in reStructuredText).
Instead, `nodes.parse_measure()` returns an `int` if possible so that
converting to `str` does not add a trailing zero in the first place.
Refactor `writers._html_base.HTMLTranslator.image_size()`.
(Using the "g"-formatter in the HTML writer is no problem, as the
scientific format is valid in CSS and "style" attribute values.)
Simplify `writers.latex2e.LaTeXTranslator.to_latex_length()`:
Use `nodes.parse_measure()`.
Move XeTeX-specific code to the "XeTeX" writer.
Drop trailing zeroes.
(Using "g" with percentage values is considered safe, as a "width"
value larger than 10 000 000 % leads to output problems anyway.)
Modified Paths:
--------------
trunk/docutils/HISTORY.rst
trunk/docutils/RELEASE-NOTES.rst
trunk/docutils/docutils/nodes.py
trunk/docutils/docutils/writers/_html_base.py
trunk/docutils/docutils/writers/latex2e/__init__.py
trunk/docutils/docutils/writers/xetex/__init__.py
trunk/docutils/test/functional/expected/latex_cornercases.tex
trunk/docutils/test/functional/expected/latex_memoir.tex
trunk/docutils/test/functional/expected/standalone_rst_latex.tex
trunk/docutils/test/functional/expected/standalone_rst_xetex.tex
Added Paths:
-----------
trunk/docutils/test/test_writers/test_xetex_misc.py
Modified: trunk/docutils/HISTORY.rst
===================================================================
--- trunk/docutils/HISTORY.rst 2024-09-15 11:13:43 UTC (rev 9931)
+++ trunk/docutils/HISTORY.rst 2024-09-19 10:20:44 UTC (rev 9932)
@@ -156,8 +156,10 @@
* docutils/writers/latex2e/__init__.py
- - Remove optional argument `pxunit` of `LaTeXTranslator.to_latex_length()`
- (ignored since at least 2012).
+ - `LaTeXTranslator.to_latex_length()`:
+ remove optional argument `pxunit` (ignored since at least 2012),
+ drop trailing zeroes from length values,
+ move XeTeX-specific code to the "xetex" writer.
- Don't wrap references with custom reference-label_ in
a ``\hyperref`` command.
- Provide an "unknown_references_resolver" (cf. `docutils/TransformSpec`)
@@ -179,7 +181,7 @@
- `null.Writer.translate()` sets `self.output` to the empty string.
-* tools/rst2odt_prepstyles.py
+* tools/rst2odt.py
- Use `core.publish_file()` instead of `core.publish_file_to_binary()`.
Modified: trunk/docutils/RELEASE-NOTES.rst
===================================================================
--- trunk/docutils/RELEASE-NOTES.rst 2024-09-15 11:13:43 UTC (rev 9931)
+++ trunk/docutils/RELEASE-NOTES.rst 2024-09-19 10:20:44 UTC (rev 9932)
@@ -102,6 +102,11 @@
- Remove ``use_verbatim_when_possible`` setting
(use literal_block_env_: verbatim) in Docutils 2.0.
+ - The `default length unit`__ will change from "bp" (DTP point)
+ to "px" (pixel unit) in Docutils 1.0.
+
+ __ docs/user/latex.html#length-units
+
Misc
----
Modified: trunk/docutils/docutils/nodes.py
===================================================================
--- trunk/docutils/docutils/nodes.py 2024-09-15 11:13:43 UTC (rev 9931)
+++ trunk/docutils/docutils/nodes.py 2024-09-19 10:20:44 UTC (rev 9932)
@@ -37,6 +37,7 @@
# import docutils.transforms # -> conditional import in document.__init__()
if TYPE_CHECKING:
+ import numbers
from collections.abc import (Callable, Iterable, Iterator,
Mapping, Sequence)
from types import ModuleType
@@ -3074,7 +3075,7 @@
return '"%s"' % value
-def parse_measure(measure: str) -> tuple[float, str]:
+def parse_measure(measure: str) -> tuple[numbers.Rational, str]:
"""Parse a measure__, return value + optional unit.
__ https://docutils.sourceforge.io/docs/ref/doctree.html#measure
@@ -3083,7 +3084,10 @@
"""
match = re.fullmatch('(-?[0-9.]+) *([a-zA-Zµ]*|%?)', measure)
try:
- value = float(match.group(1))
+ try:
+ value = int(match.group(1))
+ except ValueError:
+ value = float(match.group(1))
unit = match.group(2)
except (AttributeError, ValueError):
raise ValueError(f'"{measure}" is no valid measure.')
@@ -3168,7 +3172,7 @@
__ https://docutils.sourceforge.io/docs/ref/doctree.html#measure
"""
value, unit = parse_measure(measure)
- return f'{value:g}{unit}'
+ return f'{value}{unit}'
def validate_NMTOKEN(value: str) -> str:
Modified: trunk/docutils/docutils/writers/_html_base.py
===================================================================
--- trunk/docutils/docutils/writers/_html_base.py 2024-09-15 11:13:43 UTC (rev 9931)
+++ trunk/docutils/docutils/writers/_html_base.py 2024-09-19 10:20:44 UTC (rev 9932)
@@ -40,9 +40,8 @@
from docutils.utils.math import (latex2mathml, math2html, tex2mathml_extern,
unichar2tex, wrap_math_code, MathError)
-
if TYPE_CHECKING:
- from numbers import Real
+ from docutils.transforms import Transform
class Writer(writers.Writer):
@@ -157,7 +156,7 @@
'html_prolog', 'html_head', 'html_title', 'html_subtitle',
'html_body')
- def get_transforms(self):
+ def get_transforms(self) -> list[type[Transform]]:
return super().get_transforms() + [writer_aux.Admonitions]
def translate(self) -> None:
@@ -167,11 +166,10 @@
setattr(self, attr, getattr(visitor, attr))
self.output = self.apply_template()
- def apply_template(self):
+ def apply_template(self) -> str:
template_path = Path(self.document.settings.template)
template = template_path.read_text(encoding='utf-8')
- subs = self.interpolation_dict()
- return template % subs
+ return template % self.interpolation_dict()
def interpolation_dict(self):
subs = {}
@@ -416,36 +414,31 @@
def image_size(self, node: nodes.image) -> dict[str, str]:
"""Determine the image size from node arguments or the image file.
+ Return as dictionary of <img> attributes,
+ e.g., ``{height': '32', 'style': 'width: 4 em;'}``.
+
Auxiliary method called from `self.visit_image()`.
-
Provisional.
"""
- # List with optional width and height measures ((value, unit)-tuples)
- measures: list[tuple[Real, str] | None] = [None, None]
dimensions = ('width', 'height')
- for i, dimension in enumerate(dimensions):
+ measures = {} # (value, unit)-tuples) for width and height
+ for dimension in dimensions:
if dimension in node:
- measures[i] = nodes.parse_measure(node[dimension])
- if None in measures and 'scale' in node:
+ measures[dimension] = nodes.parse_measure(node[dimension])
+ if 'scale' in node and len(measures) < 2:
# supplement with (unitless) values read from image file
imgsize = self.read_size_with_PIL(node)
if imgsize:
- measures = [measure or (imgvalue, '')
- for measure, imgvalue in zip(measures, imgsize)]
- # scale values
- factor = node.get('scale', 100) / 100 # scaling factor
- if factor != 1:
- measures = [(measure[0] * factor, measure[1])
- for measure in measures if measure]
- # format as <img> attributes,
- # use "width" and "hight" for unitless values and "style" else,
- # e.g., height': '32' 'style': 'width: 4 em;'}``:
- size_atts = {} # attributes "width", "height", or "style"
+ for dimension, value in zip(dimensions, imgsize):
+ if dimension not in measures:
+ measures[dimension] = (value, '')
+ # Scale and format as <img> attributes,
+ # use "width" and "hight" for unitless values and "style" else:
+ scaling_factor = node.get('scale', 100) / 100
+ size_atts = {}
declarations = [] # declarations for the "style" attribute
- for dimension, measure in zip(dimensions, measures):
- if measure is None:
- continue
- value, unit = measure
+ for dimension, (value, unit) in measures.items():
+ value *= scaling_factor
if unit:
declarations.append(f'{dimension}: {value:g}{unit};')
else:
Modified: trunk/docutils/docutils/writers/latex2e/__init__.py
===================================================================
--- trunk/docutils/docutils/writers/latex2e/__init__.py 2024-09-15 11:13:43 UTC (rev 9931)
+++ trunk/docutils/docutils/writers/latex2e/__init__.py 2024-09-19 10:20:44 UTC (rev 9932)
@@ -2390,27 +2390,17 @@
self.requirements['~header'] = ''.join(self.out)
self.pop_output_collector()
- def to_latex_length(self, length_str):
- """Convert `length_str` with rst length to LaTeX length
+ def to_latex_length(self, length_str: str) -> str:
+ """Convert "measure" `length_str` to LaTeX length specification.
+
+ Note: the default length unit will change from "bp"
+ (Postscript point) to "px" in Docutils 1.0.
"""
- match = re.match(r'(\d*\.?\d*)\s*(\S*)', length_str)
- if not match:
- return length_str
- value, unit = match.groups()[:2]
- # no unit or "DTP" points (called 'bp' in TeX):
- if unit in ('', 'pt'):
- length_str = '%sbp' % value
- # percentage: relate to current line width
- elif unit == '%':
- length_str = '%.3f\\linewidth' % (float(value)/100.0)
- elif self.is_xetex and unit == 'px':
- # XeTeX does not know the length unit px.
- # Use \pdfpxdimen, the macro to set the value of 1 px in pdftex.
- # This way, configuring works the same for pdftex and xetex.
- if not self.fallback_stylesheet:
- self.fallbacks['_providelength'] = PreambleCmds.providelength
- self.fallbacks['px'] = '\n\\DUprovidelength{\\pdfpxdimen}{1bp}\n'
- length_str = r'%s\pdfpxdimen' % value
+ value, unit = nodes.parse_measure(length_str)
+ if unit in ('', 'pt'): # no unit or "Postscript points"
+ return f'{value}bp' # LaTeX uses symbol "bp"
+ if unit == '%': # percentage: relate to current line width
+ return f'{value/100:g}\\linewidth'
return length_str
def visit_image(self, node) -> None:
Modified: trunk/docutils/docutils/writers/xetex/__init__.py
===================================================================
--- trunk/docutils/docutils/writers/xetex/__init__.py 2024-09-15 11:13:43 UTC (rev 9931)
+++ trunk/docutils/docutils/writers/xetex/__init__.py 2024-09-19 10:20:44 UTC (rev 9932)
@@ -24,6 +24,7 @@
from docutils import frontend
from docutils.writers import latex2e
+from docutils.writers.latex2e import PreambleCmds
class Writer(latex2e.Writer):
@@ -145,3 +146,18 @@
else:
self.requirements['_inputenc'] = (r'\XeTeXinputencoding %s '
% self.latex_encoding)
+
+ def to_latex_length(self, length_str: str) -> str:
+ """Convert "measure" `length_str` to LaTeX length specification.
+
+ XeTeX does not know the length unit px.
+ Use ``\\pdfpxdimen``, the macro holding the value of 1 px in pdfTeX.
+ This way, configuring works the same for pdftex and xetex.
+ """
+ length_str = super().to_latex_length(length_str)
+ if length_str.endswith('px'):
+ if not self.fallback_stylesheet:
+ self.fallbacks['_providelength'] = PreambleCmds.providelength
+ self.fallbacks['px'] = '\n\\DUprovidelength{\\pdfpxdimen}{1bp}\n'
+ return length_str.replace('px', '\\pdfpxdimen')
+ return length_str
Modified: trunk/docutils/test/functional/expected/latex_cornercases.tex
===================================================================
--- trunk/docutils/test/functional/expected/latex_cornercases.tex 2024-09-15 11:13:43 UTC (rev 9931)
+++ trunk/docutils/test/functional/expected/latex_cornercases.tex 2024-09-19 10:20:44 UTC (rev 9932)
@@ -305,11 +305,11 @@
Image with 20\% width:
-\includegraphics[width=0.200\linewidth]{../../../docs/user/rst/images/title.png}
+\includegraphics[width=0.2\linewidth]{../../../docs/user/rst/images/title.png}
Image with 100\% width:
-\includegraphics[width=1.000\linewidth]{../../../docs/user/rst/images/title.png}
+\includegraphics[width=1\linewidth]{../../../docs/user/rst/images/title.png}
\section{Tables%
@@ -548,7 +548,7 @@
The \DUroletitlereference{width} option overrides \textquotedbl{}auto\textquotedbl{} \DUroletitlereference{widths} as standard LaTeX tables
don't have a global width setting:
-\setlength{\DUtablewidth}{\dimexpr0.600\linewidth-5\arrayrulewidth\relax}%
+\setlength{\DUtablewidth}{\dimexpr0.6\linewidth-5\arrayrulewidth\relax}%
\begin{longtable}{|p{\DUcolumnwidth{0.400}}|p{\DUcolumnwidth{0.200}}|p{\DUcolumnwidth{0.200}}|p{\DUcolumnwidth{0.200}}|}
\caption{This table has \DUroletitlereference{widths} \textquotedbl{}auto\textquotedbl{} (ignored) and \DUroletitlereference{width} 60\%.}\\
\hline
Modified: trunk/docutils/test/functional/expected/latex_memoir.tex
===================================================================
--- trunk/docutils/test/functional/expected/latex_memoir.tex 2024-09-15 11:13:43 UTC (rev 9931)
+++ trunk/docutils/test/functional/expected/latex_memoir.tex 2024-09-19 10:20:44 UTC (rev 9932)
@@ -816,7 +816,7 @@
An image directive (also clickable -{}- a hyperlink reference):
-\hyperref[directives]{\includegraphics[width=0.700\linewidth]{../../../docs/user/rst/images/title.png}}
+\hyperref[directives]{\includegraphics[width=0.7\linewidth]{../../../docs/user/rst/images/title.png}}
Image with multiple IDs:
@@ -858,7 +858,7 @@
Relative units allow adaption of the image to the screen or paper size.
An image occupying 50\% of the line width:
-\includegraphics[width=0.500\linewidth]{../../../docs/user/rst/images/title.png}
+\includegraphics[width=0.5\linewidth]{../../../docs/user/rst/images/title.png}
A \emph{figure} is an image with a caption and/or a legend. With page-based output
media, figures might float to a different position if this helps the page
@@ -1670,7 +1670,7 @@
Here's a list table exercising all features:
\begin{DUclass}{test}
-\setlength{\DUtablewidth}{0.950\linewidth}%
+\setlength{\DUtablewidth}{0.95\linewidth}%
\begin{longtable}{|p{0.133\DUtablewidth}|p{0.110\DUtablewidth}|p{0.249\DUtablewidth}|}
\caption{list table with integral header}\\
\hline
@@ -1832,7 +1832,7 @@
\begin{description}
\item[{Math-Accents:}] \leavevmode
-\setlength{\DUtablewidth}{1.000\linewidth}%
+\setlength{\DUtablewidth}{1\linewidth}%
\begin{longtable*}{p{0.315\DUtablewidth}p{0.315\DUtablewidth}p{0.315\DUtablewidth}}
$\acute{a}$ \texttt{\textbackslash{}acute\{a\}}
Modified: trunk/docutils/test/functional/expected/standalone_rst_latex.tex
===================================================================
--- trunk/docutils/test/functional/expected/standalone_rst_latex.tex 2024-09-15 11:13:43 UTC (rev 9931)
+++ trunk/docutils/test/functional/expected/standalone_rst_latex.tex 2024-09-19 10:20:44 UTC (rev 9932)
@@ -817,7 +817,7 @@
An image directive (also clickable – a hyperlink reference):
-\hyperref[directives]{\includegraphics[width=0.700\linewidth]{../../../docs/user/rst/images/title.png}}
+\hyperref[directives]{\includegraphics[width=0.7\linewidth]{../../../docs/user/rst/images/title.png}}
Image with multiple IDs:
@@ -859,7 +859,7 @@
Relative units allow adaption of the image to the screen or paper size.
An image occupying 50\% of the line width:
-\includegraphics[width=0.500\linewidth]{../../../docs/user/rst/images/title.png}
+\includegraphics[width=0.5\linewidth]{../../../docs/user/rst/images/title.png}
A \emph{figure} is an image with a caption and/or a legend. With page-based output
media, figures might float to a different position if this helps the page
@@ -1692,7 +1692,7 @@
Here’s a list table exercising all features:
\begin{DUclass}{test}
-\setlength{\DUtablewidth}{0.950\linewidth}%
+\setlength{\DUtablewidth}{0.95\linewidth}%
\begin{longtable}{|p{0.133\DUtablewidth}|p{0.110\DUtablewidth}|p{0.249\DUtablewidth}|}
\caption{list table with integral header}\\
\hline
@@ -1854,7 +1854,7 @@
\begin{description}
\item[{Math-Accents:}] \leavevmode
-\setlength{\DUtablewidth}{1.000\linewidth}%
+\setlength{\DUtablewidth}{1\linewidth}%
\begin{longtable*}{p{0.315\DUtablewidth}p{0.315\DUtablewidth}p{0.315\DUtablewidth}}
$\acute{a}$ \texttt{\textbackslash{}acute\{a\}}
Modified: trunk/docutils/test/functional/expected/standalone_rst_xetex.tex
===================================================================
--- trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2024-09-15 11:13:43 UTC (rev 9931)
+++ trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2024-09-19 10:20:44 UTC (rev 9932)
@@ -852,7 +852,7 @@
An image directive (also clickable – a hyperlink reference):
-\hyperref[directives]{\includegraphics[width=0.700\linewidth]{../../../docs/user/rst/images/title.png}}
+\hyperref[directives]{\includegraphics[width=0.7\linewidth]{../../../docs/user/rst/images/title.png}}
Image with multiple IDs:
@@ -894,7 +894,7 @@
Relative units allow adaption of the image to the screen or paper size.
An image occupying 50\% of the line width:
-\includegraphics[width=0.500\linewidth]{../../../docs/user/rst/images/title.png}
+\includegraphics[width=0.5\linewidth]{../../../docs/user/rst/images/title.png}
A \emph{figure} is an image with a caption and/or a legend. With page-based output
media, figures might float to a different position if this helps the page
@@ -1731,7 +1731,7 @@
Here’s a list table exercising all features:
\begin{DUclass}{test}
-\setlength{\DUtablewidth}{0.950\linewidth}%
+\setlength{\DUtablewidth}{0.95\linewidth}%
\begin{longtable}{|p{0.133\DUtablewidth}|p{0.110\DUtablewidth}|p{0.249\DUtablewidth}|}
\caption{list table with integral header}\\
\hline
@@ -1893,7 +1893,7 @@
\begin{description}
\item[{Math-Accents:}] \leavevmode
-\setlength{\DUtablewidth}{1.000\linewidth}%
+\setlength{\DUtablewidth}{1\linewidth}%
\begin{longtable*}{p{0.315\DUtablewidth}p{0.315\DUtablewidth}p{0.315\DUtablewidth}}
$\acute{a}$ \texttt{\textbackslash{}acute\{a\}}
Added: trunk/docutils/test/test_writers/test_xetex_misc.py
===================================================================
--- trunk/docutils/test/test_writers/test_xetex_misc.py (rev 0)
+++ trunk/docutils/test/test_writers/test_xetex_misc.py 2024-09-19 10:20:44 UTC (rev 9932)
@@ -0,0 +1,78 @@
+#! /usr/bin/env python3
+# $Id$
+# Author: Günter Milde
+# Maintainer: [email protected]
+# :Copyright: 2024 Günter Milde,
+# :License: Released under the terms of the `2-Clause BSD license`_, in short:
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved.
+# This file is offered as-is, without any warranty.
+#
+# .. _2-Clause BSD license: https://opensource.org/licenses/BSD-2-Clause
+
+"""
+Miscellaneous XeTeX/LuaTeX writer tests.
+"""
+
+from pathlib import Path
+import sys
+import unittest
+
+
+if __name__ == '__main__':
+ # prepend the "docutils root" to the Python library path
+ # so we import the local `docutils` package.
+ sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
+
+from docutils import core
+from docutils.writers import xetex
+
+# TEST_ROOT is ./test/ from the docutils root
+TEST_ROOT = Path(__file__).parents[1]
+DATA_ROOT = TEST_ROOT / 'data'
+
+px_sample = """\
+.. image:: foo.pdf
+ :width: 250 px
+ :height: 50pt
+"""
+
+px_body = r"""
+\includegraphics[height=50bp,width=250\pdfpxdimen]{foo.pdf}
+"""
+
+px_fallback = r"""
+% Provide a length variable and set default, if it is new
+\providecommand*{\DUprovidelength}[2]{
+ \ifthenelse{\isundefined{#1}}{\newlength{#1}\setlength{#1}{#2}}{}
+}
+
+\DUprovidelength{\pdfpxdimen}{1bp}
+
+
+"""
+
+
+class PublishTestCase(unittest.TestCase):
+ maxDiff = None
+
+ settings = {'_disable_config': True,
+ # avoid latex writer future warnings:
+ 'use_latex_citations': False,
+ 'legacy_column_widths': False,
+ }
+
+ def test_px_workaround(self):
+ """Check the workaround for length unit 'px' missing in XeTeX.
+ """
+ parts = core.publish_parts(px_sample,
+ writer=xetex.Writer(),
+ settings_overrides=self.settings)
+ self.assertEqual(px_body, parts['body'])
+ self.assertEqual(px_fallback, parts['fallbacks'])
+
+
+if __name__ == '__main__':
+ unittest.main()
Property changes on: trunk/docutils/test/test_writers/test_xetex_misc.py
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Revision
\ No newline at end of property
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