From 2c1bf732f9d138fbdc27224b678163abac31871b Mon Sep 17 00:00:00 2001 From: milde Date: Thu, 19 Jan 2012 11:55:26 +0000 Subject: [PATCH] Fix handling of missing stylesheets. Updated and simplied tests. Missing stylesheets are no reason to abort conversion: Report as error and insert a comment in the output doc. git-svn-id: https://docutils.svn.sourceforge.net/svnroot/docutils/trunk/docutils@7317 929543f6-e4f2-0310-98a6-ba3bd3dd1d04 --- HISTORY.txt | 15 ++-- docutils/writers/__init__.py | 2 +- docutils/writers/html4css1/__init__.py | 39 ++++++---- docutils/writers/latex2e/__init__.py | 82 +++++++++++++--------- test/data/hidden.css | 2 - test/data/spam.sty | 3 - .../multistyle_path_embed_rst_html4css1.html | 28 -------- .../expected/multistyle_path_rst_html4css1.html | 18 ----- ...ml4css1.html => stylesheet_path_html4css1.html} | 4 +- .../tests/multistyle_path_embedd_rst_html4css1.py | 14 ---- .../tests/multistyle_path_rst_html4css1.py | 14 ---- test/functional/tests/multistyle_rst_html4css1.py | 14 ---- test/functional/tests/stylesheet_path_html4css1.py | 15 ++++ test/test_writers/test_latex2e.py | 26 +++---- 14 files changed, 108 insertions(+), 168 deletions(-) delete mode 100644 test/data/hidden.css delete mode 100644 test/data/spam.sty delete mode 100644 test/functional/expected/multistyle_path_embed_rst_html4css1.html delete mode 100644 test/functional/expected/multistyle_path_rst_html4css1.html rename test/functional/expected/{multistyle_rst_html4css1.html => stylesheet_path_html4css1.html} (78%) delete mode 100644 test/functional/tests/multistyle_path_embedd_rst_html4css1.py delete mode 100644 test/functional/tests/multistyle_path_rst_html4css1.py delete mode 100644 test/functional/tests/multistyle_rst_html4css1.py create mode 100644 test/functional/tests/stylesheet_path_html4css1.py diff --git a/HISTORY.txt b/HISTORY.txt index 5c47394ae..d10d21f5b 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -13,17 +13,15 @@ .. contents:: - Changes Since 0.8.1 =================== * General: - - reStructuredText "code" role and directive with syntax highlighting - by Pygments_. - - "code" option of the "include" directive. + - New reStructuredText "code" role and directive and "code" option + of the "include" directive with syntax highlighting by Pygments_. - Fix parse_option_marker for option arguments containing ``=``. - + .. _Pygments: http://pygments.org/ * setup.py @@ -61,16 +59,17 @@ Changes Since 0.8.1 - Support the `abbreviation` and `acronym` standard roles. - Record only files required to generate the LaTeX source as dependencies. + - Fix handling of missing stylesheets. * docutils/writers/html4css1/__init__.py - Change default for `math-output` setting to MathJax. + - Fix handling of missing stylesheets. * docutils/writers/docutils_xml.py - - Use the visitor pattern with default methods instead of minidom - to facilitate special handling of selected nodes. - + - Use the visitor pattern with default_visit()/default_depart() methods + instead of minidom to facilitate special handling of selected nodes. - Support raw XML (inserted as-is inside a node). Release 0.8.1 (2011-08-30) diff --git a/docutils/writers/__init__.py b/docutils/writers/__init__.py index ff8c02328..e30dbf6e6 100644 --- a/docutils/writers/__init__.py +++ b/docutils/writers/__init__.py @@ -52,7 +52,7 @@ class Writer(Component): def __init__(self): - # Used by HTML and LaTex writer for output fragments: + # Used by HTML and LaTeX writer for output fragments: self.parts = {} """Mapping of document part names to fragments of `self.output`. Values are Unicode strings; encoding is up to the client. The 'whole' diff --git a/docutils/writers/html4css1/__init__.py b/docutils/writers/html4css1/__init__.py index ec1edfb82..6d94f944f 100644 --- a/docutils/writers/html4css1/__init__.py +++ b/docutils/writers/html4css1/__init__.py @@ -1,5 +1,6 @@ # $Id$ -# Author: David Goodger +# Author: David Goodger +# Maintainer: docutils-develop@lists.sourceforge.net # Copyright: This module has been placed in the public domain. """ @@ -31,6 +32,7 @@ except ImportError: PIL = None import docutils from docutils import frontend, nodes, utils, writers, languages, io +from docutils.error_reporting import SafeString from docutils.transforms import writer_aux from docutils.math import unichar2tex, pick_math_environment from docutils.math.latex2mathml import parse_latex_math @@ -286,19 +288,8 @@ class HTMLTranslator(nodes.NodeVisitor): # encoding not interpolated: self.html_prolog.append(self.xml_declaration) self.head = self.meta[:] - # stylesheets - styles = utils.get_stylesheet_list(settings) - if settings.stylesheet_path and not(settings.embed_stylesheet): - styles = [utils.relative_path(settings._destination, sheet) - for sheet in styles] - if settings.embed_stylesheet: - self.stylesheet = [self.embedded_stylesheet % - io.FileInput(source_path=sheet, encoding='utf-8').read() - for sheet in styles] - settings.record_dependencies.add(*styles) - else: # link to stylesheets - self.stylesheet = [self.stylesheet_link % self.encode(stylesheet) - for stylesheet in styles] + self.stylesheet = [self.stylesheet_call(path) + for path in utils.get_stylesheet_list(settings)] self.body_prefix = ['\n\n'] # document title, subtitle display self.body_pre_docinfo = [] @@ -377,6 +368,26 @@ class HTMLTranslator(nodes.NodeVisitor): encoded = encoded.replace('.', '.') return encoded + def stylesheet_call(self, path): + """Return code to reference or embed stylesheet file `path`""" + if self.settings.embed_stylesheet: + try: + content = io.FileInput(source_path=path, + encoding='utf-8', + handle_io_errors=False).read() + self.settings.record_dependencies.add(path) + except IOError, err: + msg = u"Cannot embed stylesheet '%s': %s." % ( + path, SafeString(err.strerror)) + self.document.reporter.error(msg) + return '<--- %s --->\n' % msg + return self.embedded_stylesheet % content + # else link to style file: + if self.settings.stylesheet_path: + # adapt path relative to output (cf. config.html#stylesheet-path) + path = utils.relative_path(self.settings._destination, path) + return self.stylesheet_link % self.encode(path) + def starttag(self, node, tagname, suffix='\n', empty=0, **attributes): """ Construct and return a start tag given a node (id & class attributes diff --git a/docutils/writers/latex2e/__init__.py b/docutils/writers/latex2e/__init__.py index c21f5016f..d64edc7fb 100644 --- a/docutils/writers/latex2e/__init__.py +++ b/docutils/writers/latex2e/__init__.py @@ -1,6 +1,7 @@ # .. coding: utf8 # $Id$ -# Author: Engelbert Gruber +# Author: Engelbert Gruber, Günter Milde +# Maintainer: docutils-develop@lists.sourceforge.net # Copyright: This module has been placed in the public domain. """LaTeX2e document tree Writer.""" @@ -19,6 +20,7 @@ import re import string import urllib from docutils import frontend, nodes, languages, writers, utils, io +from docutils.error_reporting import SafeString from docutils.transforms import writer_aux from docutils.math import pick_math_environment, unichar2tex @@ -492,11 +494,6 @@ PreambleCmds.docinfo = r""" \DUprovidelength{\DUdocinfowidth}{0.9\textwidth}""" # PreambleCmds.docinfo._depends = 'providelength' -PreambleCmds.embedded_package_wrapper = r"""\makeatletter -%% embedded stylesheet: %s -%s -\makeatother""" - PreambleCmds.dedication = r""" % dedication topic \providecommand{\DUtopicdedication}[1]{\begin{center}#1\end{center}}""" @@ -970,7 +967,6 @@ class LaTeXTranslator(nodes.NodeVisitor): self.use_latex_toc = settings.use_latex_toc self.use_latex_docinfo = settings.use_latex_docinfo self._use_latex_citations = settings.use_latex_citations - self.embed_stylesheet = settings.embed_stylesheet self._reference_label = settings.reference_label self.hyperlink_color = settings.hyperlink_color self.compound_enumerators = settings.compound_enumerators @@ -1037,7 +1033,6 @@ class LaTeXTranslator(nodes.NodeVisitor): self.requirements = SortableDict() # made a list in depart_document() self.requirements['__static'] = r'\usepackage{ifthen}' self.latex_preamble = [settings.latex_preamble] - self.stylesheet = [] self.fallbacks = SortableDict() # made a list in depart_document() self.pdfsetup = [] # PDF properties (hyperref package) self.title = [] @@ -1109,30 +1104,10 @@ class LaTeXTranslator(nodes.NodeVisitor): self.requirements['typearea'] = r'\usepackage{typearea}' # Stylesheets - # get list of style sheets from settings - styles = utils.get_stylesheet_list(settings) - # adapt path if --stylesheet_path is used - if settings.stylesheet_path and not(self.embed_stylesheet): - styles = [utils.relative_path(settings._destination, sheet) - for sheet in styles] - for sheet in styles: - (base, ext) = os.path.splitext(sheet) - is_package = ext in ['.sty', ''] - if self.embed_stylesheet: - if is_package: - sheet = base + '.sty' # adapt package name - # wrap in \makeatletter, \makeatother - wrapper = PreambleCmds.embedded_package_wrapper - else: - wrapper = '%% embedded stylesheet: %s\n%s' - settings.record_dependencies.add(sheet) - self.stylesheet.append(wrapper % - (sheet, io.FileInput(source_path=sheet, encoding='utf-8').read())) - else: # link to style sheet - if is_package: - self.stylesheet.append(r'\usepackage{%s}' % base) - else: - self.stylesheet.append(r'\input{%s}' % sheet) + # (the name `self.stylesheet` is singular because only one + # stylesheet was supported before Docutils 0.6). + self.stylesheet = [self.stylesheet_call(path) + for path in utils.get_stylesheet_list(settings)] # PDF setup if self.hyperlink_color in ('0', 'false', 'False', ''): @@ -1150,7 +1125,11 @@ class LaTeXTranslator(nodes.NodeVisitor): ## self.requirements['tocdepth'] = (r'\setcounter{tocdepth}{%d}' % ## len(self.d_class.sections)) - # LaTeX section numbering + # Section numbering + # TODO: use \secnumdepth instead of starred commands + ## if self.settings.sectnum_xform: # section numbering by Docutils + ## sectnum_depth = 0 + ## else: if not self.settings.sectnum_xform: # section numbering by LaTeX: # sectnum_depth: # None "sectnum" directive without depth arg -> LaTeX default @@ -1180,7 +1159,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.requirements['sectnum_start'] = ( r'\setcounter{%s}{%d}' % (self.d_class.sections[0], settings.sectnum_start-1)) - # currently ignored (configure in a stylesheet): + # TODO: currently ignored (configure in a stylesheet): ## settings.sectnum_prefix ## settings.sectnum_suffix @@ -1188,6 +1167,41 @@ class LaTeXTranslator(nodes.NodeVisitor): # Auxiliary Methods # ----------------- + def stylesheet_call(self, path): + """Return code to reference or embed stylesheet file `path`""" + # is it a package (no extension or *.sty) or "normal" tex code: + (base, ext) = os.path.splitext(path) + is_package = ext in ['.sty', ''] + # Embed content of style file: + if self.settings.embed_stylesheet: + if is_package: + path = base + '.sty' # ensure extension + try: + content = io.FileInput(source_path=path, + encoding='utf-8', + handle_io_errors=False).read() + self.settings.record_dependencies.add(path) + except IOError, err: + msg = u"Cannot embed stylesheet '%s':\n %s." % ( + path, SafeString(err.strerror)) + self.document.reporter.error(msg) + return '% ' + msg.replace('\n', '\n% ') + if is_package: + content = '\n'.join([r'\makeatletter', + content, + r'\makeatother']) + return '%% embedded stylesheet: %s\n%s' % (path, content) + # Link to style file: + if is_package: + path = base # drop extension + cmd = r'\usepackage{%s}' + else: + cmd = r'\input{%s}' + if self.settings.stylesheet_path: + # adapt path relative to output (cf. config.html#stylesheet-path) + path = utils.relative_path(self.settings._destination, path) + return cmd % path + def to_latex_encoding(self,docutils_encoding): """Translate docutils encoding name into LaTeX's. diff --git a/test/data/hidden.css b/test/data/hidden.css deleted file mode 100644 index cf57ccd7b..000000000 --- a/test/data/hidden.css +++ /dev/null @@ -1,2 +0,0 @@ -.hidden { - display: none } diff --git a/test/data/spam.sty b/test/data/spam.sty deleted file mode 100644 index 2288ae31c..000000000 --- a/test/data/spam.sty +++ /dev/null @@ -1,3 +0,0 @@ -\ProvidesPackage{spam} -[2008/12/09 v0.2 simple silly test package] -\newcommand{\spam}{\@percentchar\ wonderfull spam} diff --git a/test/functional/expected/multistyle_path_embed_rst_html4css1.html b/test/functional/expected/multistyle_path_embed_rst_html4css1.html deleted file mode 100644 index 9beb5e7ca..000000000 --- a/test/functional/expected/multistyle_path_embed_rst_html4css1.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - -
- - -

simple input

-
- - diff --git a/test/functional/expected/multistyle_path_rst_html4css1.html b/test/functional/expected/multistyle_path_rst_html4css1.html deleted file mode 100644 index b7c923601..000000000 --- a/test/functional/expected/multistyle_path_rst_html4css1.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - -
- - -

simple input

-
- - diff --git a/test/functional/expected/multistyle_rst_html4css1.html b/test/functional/expected/stylesheet_path_html4css1.html similarity index 78% rename from test/functional/expected/multistyle_rst_html4css1.html rename to test/functional/expected/stylesheet_path_html4css1.html index c61978fa1..a3f88d7bd 100644 --- a/test/functional/expected/multistyle_rst_html4css1.html +++ b/test/functional/expected/stylesheet_path_html4css1.html @@ -5,8 +5,8 @@ - - + +
diff --git a/test/functional/tests/multistyle_path_embedd_rst_html4css1.py b/test/functional/tests/multistyle_path_embedd_rst_html4css1.py deleted file mode 100644 index 7c4eea91a..000000000 --- a/test/functional/tests/multistyle_path_embedd_rst_html4css1.py +++ /dev/null @@ -1,14 +0,0 @@ -# Source and destination file names. -test_source = "simple.txt" -test_destination = "multistyle_path_embed_rst_html4css1.html" - -# Keyword parameters passed to publish_file. -reader_name = "standalone" -parser_name = "rst" -writer_name = "html4css1" - -# Settings -# test for encoded attribute value: -settings_overrides['stylesheet'] = '' -settings_overrides['stylesheet_path'] = 'data/hidden.css,data/ham.css' -settings_overrides['embed_stylesheet'] = 1 diff --git a/test/functional/tests/multistyle_path_rst_html4css1.py b/test/functional/tests/multistyle_path_rst_html4css1.py deleted file mode 100644 index 85417642b..000000000 --- a/test/functional/tests/multistyle_path_rst_html4css1.py +++ /dev/null @@ -1,14 +0,0 @@ -# Source and destination file names. -test_source = "simple.txt" -test_destination = "multistyle_path_rst_html4css1.html" - -# Keyword parameters passed to publish_file. -reader_name = "standalone" -parser_name = "rst" -writer_name = "html4css1" - -# Settings -# test for encoded attribute value: -settings_overrides['stylesheet'] = '' -settings_overrides['stylesheet_path'] = 'ham.css,path/to/spam.css' -settings_overrides['embed_stylesheet'] = 0 diff --git a/test/functional/tests/multistyle_rst_html4css1.py b/test/functional/tests/multistyle_rst_html4css1.py deleted file mode 100644 index c7ccf850d..000000000 --- a/test/functional/tests/multistyle_rst_html4css1.py +++ /dev/null @@ -1,14 +0,0 @@ -# Source and destination file names. -test_source = "simple.txt" -test_destination = "multistyle_rst_html4css1.html" - -# Keyword parameters passed to publish_file. -reader_name = "standalone" -parser_name = "rst" -writer_name = "html4css1" - -# Settings -# test for encoded attribute value: -settings_overrides['stylesheet'] = 'ham.css,/spam.css' -settings_overrides['stylesheet_path'] = '' -settings_overrides['embed_stylesheet'] = 0 diff --git a/test/functional/tests/stylesheet_path_html4css1.py b/test/functional/tests/stylesheet_path_html4css1.py new file mode 100644 index 000000000..a8dd43733 --- /dev/null +++ b/test/functional/tests/stylesheet_path_html4css1.py @@ -0,0 +1,15 @@ +# Test re-writing of stylesheet paths relative to output directory + +# Source and destination file names. +test_source = "simple.txt" +test_destination = "stylesheet_path_html4css1.html" + +# Keyword parameters passed to publish_file. +reader_name = "standalone" +parser_name = "rst" +writer_name = "html4css1" + +# Settings +settings_overrides['stylesheet'] = '' +settings_overrides['stylesheet_path'] = 'data/ham.css,/missing.css' +settings_overrides['embed_stylesheet'] = False diff --git a/test/test_writers/test_latex2e.py b/test/test_writers/test_latex2e.py index 7a6c90849..9f04f1f33 100755 --- a/test/test_writers/test_latex2e.py +++ b/test/test_writers/test_latex2e.py @@ -17,23 +17,22 @@ if not hasattr(string, 'Template'): from __init__ import DocutilsTestSupport -from docutils._compat import b - def suite(): - settings = {'use_latex_toc': 0} + settings = {'use_latex_toc': False} s = DocutilsTestSupport.PublishTestSuite('latex', suite_settings=settings) s.generateTests(totest) - settings['use_latex_toc'] = 1 + settings['use_latex_toc'] = True s.generateTests(totest_latex_toc) - settings['use_latex_toc'] = 0 - settings['sectnum_xform'] = 0 + settings['use_latex_toc'] = False + settings['sectnum_xform'] = False s.generateTests(totest_latex_sectnum) - settings['sectnum_xform'] = 1 - settings['use_latex_citations'] = 1 + settings['sectnum_xform'] = True + settings['use_latex_citations'] = True s.generateTests(totest_latex_citations) settings['stylesheet_path'] = 'data/spam,data/ham.tex' s.generateTests(totest_stylesheet) - settings['embed_stylesheet'] = 1 + settings['embed_stylesheet'] = True + settings['warning_stream'] = '' s.generateTests(totest_stylesheet_embed) return s @@ -659,13 +658,8 @@ totest_stylesheet_embed['two-styles'] = [ # input ["""two stylesheets embedded in the header""", head_template.substitute(dict(parts, stylesheet = -r"""\makeatletter -% embedded stylesheet: data/spam.sty -\ProvidesPackage{spam} -[2008/12/09 v0.2 simple silly test package] -\newcommand{\spam}{\@percentchar\ wonderfull spam} - -\makeatother +r"""% Cannot embed stylesheet 'data/spam.sty': +% No such file or directory. % embedded stylesheet: data/ham.tex \newcommand{\ham}{wonderful ham} -- 2.11.4.GIT