From 1f451ce2f91bfa0dd8508d608d018d691af384e4 Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 28 May 2017 13:10:17 +0200 Subject: [PATCH 1/7] Fix #3781: instruct SmartQuotes of nodes to skip Relates #3666, #3787 --- sphinx/transforms/__init__.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index aceffa329..1e3e163e1 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -9,16 +9,19 @@ :license: BSD, see LICENSE for details. """ +import docutils from docutils import nodes from docutils.transforms import Transform, Transformer from docutils.transforms.parts import ContentsFilter from docutils.utils import new_document +from docutils.transforms.universal import SmartQuotes as DocutilsSmartQuotes from sphinx import addnodes from sphinx.locale import _ from sphinx.util import logging from sphinx.util.i18n import format_date from sphinx.util.nodes import apply_source_workaround +from sphinx import addnodes if False: # For type annotation @@ -327,3 +330,33 @@ class SphinxContentsFilter(ContentsFilter): def visit_image(self, node): # type: (nodes.Node) -> None raise nodes.SkipNode + + +class SphinxSmartQuotes(DocutilsSmartQuotes): # NOQA + """ + Customized SmartQuotes to avoid transform for some extra node types. + """ + def get_tokens(self, txtnodes): + # A generator that yields ``(texttype, nodetext)`` tuples for a list + # of "Text" nodes (interface to ``smartquotes.educate_tokens()``). + + texttype = {True: 'literal', # "literal" text is not changed: + False: 'plain'} + for txtnode in txtnodes: + nodetype = texttype[isinstance(txtnode.parent, + (nodes.literal, + nodes.literal_block, + addnodes.literal_emphasis, + addnodes.literal_strong, + addnodes.desc_signature, + addnodes.productionlist, + addnodes.desc_optional, + addnodes.desc_name, + nodes.math, + nodes.image, + nodes.raw, + nodes.problematic))] + yield (nodetype, txtnode.astext()) + + +docutils.transforms.universal.SmartQuotes = SphinxSmartQuotes From 3f6bfe1e8afb03bada144d286a19d32d648df34a Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 28 May 2017 13:32:44 +0200 Subject: [PATCH 2/7] Fix flake8 --- sphinx/transforms/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index 1e3e163e1..c52eafda2 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -21,7 +21,6 @@ from sphinx.locale import _ from sphinx.util import logging from sphinx.util.i18n import format_date from sphinx.util.nodes import apply_source_workaround -from sphinx import addnodes if False: # For type annotation @@ -340,7 +339,7 @@ class SphinxSmartQuotes(DocutilsSmartQuotes): # NOQA # A generator that yields ``(texttype, nodetext)`` tuples for a list # of "Text" nodes (interface to ``smartquotes.educate_tokens()``). - texttype = {True: 'literal', # "literal" text is not changed: + texttype = {True: 'literal', # "literal" text is not changed: False: 'plain'} for txtnode in txtnodes: nodetype = texttype[isinstance(txtnode.parent, From 19e4462fd73e01dd6dd0c695cf9353153e8c54c8 Mon Sep 17 00:00:00 2001 From: jfbu Date: Sun, 28 May 2017 15:24:38 +0200 Subject: [PATCH 3/7] Update CHANGES for PR #3816 --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index 9c310de37..5b601fc9d 100644 --- a/CHANGES +++ b/CHANGES @@ -36,6 +36,7 @@ Bugs fixed * #3791: PDF "continued on next page" for long tables isn't internationalized * #3788: smartquotes emits warnings for unsupported languages * #3807: docs do not say Latexmk is dependency on Windows for ``make latexpdf`` +* #3781: double hyphens in option directive are compiled as endashes Testing -------- From 69cf328b8bdc0b2e9b6243bd0e6de2905d03637e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 28 May 2017 22:08:52 +0900 Subject: [PATCH 4/7] Add Sphinx own parser (refs: #3816) --- sphinx/application.py | 3 ++- sphinx/io.py | 3 +++ sphinx/parsers.py | 29 +++++++++++++++++++++++++++++ sphinx/transforms/__init__.py | 10 ++++------ tests/test_application.py | 2 +- 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/sphinx/application.py b/sphinx/application.py index 075f828fb..c06e86995 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -85,6 +85,7 @@ builtin_extensions = ( 'sphinx.directives.code', 'sphinx.directives.other', 'sphinx.directives.patches', + 'sphinx.parsers', 'sphinx.roles', 'sphinx.transforms.post_transforms', 'sphinx.transforms.post_transforms.images', @@ -265,7 +266,7 @@ class Sphinx(object): for suffix, parser in iteritems(self.config.source_parsers): self.add_source_parser(suffix, parser) for suffix, parser in iteritems(self.registry.get_source_parsers()): - if suffix not in self.config.source_suffix: + if suffix not in self.config.source_suffix and suffix != '*': self.config.source_suffix.append(suffix) def _init_env(self, freshenv): diff --git a/sphinx/io.py b/sphinx/io.py index 7cb54efff..8f048c7fc 100644 --- a/sphinx/io.py +++ b/sphinx/io.py @@ -63,6 +63,9 @@ class SphinxBaseReader(standalone.Reader): if source.source_path.endswith(suffix): self.parser = self.parser_map[suffix] break + else: + # use special parser for unknown file-extension '*' (if exists) + self.parser = self.parser_map.get('*') if not self.parser: self.parser = parser diff --git a/sphinx/parsers.py b/sphinx/parsers.py index 9aba947d3..d4123880c 100644 --- a/sphinx/parsers.py +++ b/sphinx/parsers.py @@ -10,9 +10,15 @@ """ import docutils.parsers +import docutils.parsers.rst +from docutils.transforms.universal import SmartQuotes + +from sphinx.transforms import SphinxSmartQuotes if False: # For type annotation + from typing import Any, Dict, Type # NOQA + from docutils.transforms import Transform # NOQA from sphinx.application import Sphinx # NOQA @@ -47,3 +53,26 @@ class Parser(docutils.parsers.Parser): self.env = app.env self.warn = app.warn self.info = app.info + + +class RSTParser(docutils.parsers.rst.Parser): + """A reST parser customized for Sphinx.""" + + def get_transforms(self): + # type: () -> List[Type[Transform]] + """Sphinx's reST parser replaces a transform class for smart-quotes by own's""" + transforms = docutils.parsers.rst.Parser.get_transforms(self) + transforms.remove(SmartQuotes) + transforms.append(SphinxSmartQuotes) + return transforms + + +def setup(app): + # type: (Sphinx) -> Dict[unicode, Any] + app.add_source_parser('*', RSTParser) # register as a special parser + + return { + 'version': 'builtin', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index c52eafda2..6d9360180 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -9,12 +9,11 @@ :license: BSD, see LICENSE for details. """ -import docutils from docutils import nodes from docutils.transforms import Transform, Transformer from docutils.transforms.parts import ContentsFilter from docutils.utils import new_document -from docutils.transforms.universal import SmartQuotes as DocutilsSmartQuotes +from docutils.transforms.universal import SmartQuotes from sphinx import addnodes from sphinx.locale import _ @@ -331,9 +330,11 @@ class SphinxContentsFilter(ContentsFilter): raise nodes.SkipNode -class SphinxSmartQuotes(DocutilsSmartQuotes): # NOQA +class SphinxSmartQuotes(SmartQuotes): """ Customized SmartQuotes to avoid transform for some extra node types. + + refs: sphinx.parsers.RSTParser """ def get_tokens(self, txtnodes): # A generator that yields ``(texttype, nodetext)`` tuples for a list @@ -356,6 +357,3 @@ class SphinxSmartQuotes(DocutilsSmartQuotes): # NOQA nodes.raw, nodes.problematic))] yield (nodetype, txtnode.astext()) - - -docutils.transforms.universal.SmartQuotes = SphinxSmartQuotes diff --git a/tests/test_application.py b/tests/test_application.py index 576a01916..785a78878 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -83,6 +83,6 @@ def test_domain_override(app, status, warning): @pytest.mark.sphinx(testroot='add_source_parser') def test_add_source_parser(app, status, warning): assert set(app.config.source_suffix) == set(['.rst', '.md', '.test']) - assert set(app.registry.get_source_parsers().keys()) == set(['.md', '.test']) + assert set(app.registry.get_source_parsers().keys()) == set(['*', '.md', '.test']) assert app.registry.get_source_parsers()['.md'].__name__ == 'DummyMarkdownParser' assert app.registry.get_source_parsers()['.test'].__name__ == 'TestSourceParser' From a7ea7580b67a6982d127b6c5f1121abf7eec1876 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 28 May 2017 22:46:01 +0900 Subject: [PATCH 5/7] Fix mypy violation --- sphinx/parsers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/parsers.py b/sphinx/parsers.py index d4123880c..33556e487 100644 --- a/sphinx/parsers.py +++ b/sphinx/parsers.py @@ -17,7 +17,7 @@ from sphinx.transforms import SphinxSmartQuotes if False: # For type annotation - from typing import Any, Dict, Type # NOQA + from typing import Any, Dict, List, Type # NOQA from docutils.transforms import Transform # NOQA from sphinx.application import Sphinx # NOQA From 0b945ce15793d72ec7c10ffd687f8c221985a7bf Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 28 May 2017 22:47:57 +0900 Subject: [PATCH 6/7] Fix #3817: latex builder raises AttributeError --- CHANGES | 2 ++ sphinx/transforms/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 5b601fc9d..c2e78e80b 100644 --- a/CHANGES +++ b/CHANGES @@ -37,6 +37,8 @@ Bugs fixed * #3788: smartquotes emits warnings for unsupported languages * #3807: docs do not say Latexmk is dependency on Windows for ``make latexpdf`` * #3781: double hyphens in option directive are compiled as endashes +* #3817: latex builder raises AttributeError + Testing -------- diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index c52eafda2..243386815 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -87,7 +87,7 @@ class SphinxTransformer(Transformer): def apply_transforms(self): # type: () -> None if isinstance(self.document, nodes.document): - if hasattr(self.document.settings, 'env') and self.env: + if not hasattr(self.document.settings, 'env') and self.env: self.document.settings.env = self.env Transformer.apply_transforms(self) From fae1bff6453562ed34d63408e59441b5139cf6c9 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 28 May 2017 23:06:37 +0900 Subject: [PATCH 7/7] Fix warning message for old docutils package --- sphinx/builders/html.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index c69b6ca79..540125b2a 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -20,6 +20,7 @@ from hashlib import md5 from six import iteritems, text_type, string_types from six.moves import cPickle as pickle +import docutils from docutils import nodes from docutils.io import DocTreeInput, StringOutput from docutils.core import Publisher @@ -34,7 +35,7 @@ from sphinx.util.inventory import InventoryFile from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \ movefile, copyfile from sphinx.util.nodes import inline_all_toctrees -from sphinx.util.docutils import is_html5_writer_available, __version_info__ +from sphinx.util.docutils import is_html5_writer_available from sphinx.util.fileutil import copy_asset from sphinx.util.matching import patmatch, Matcher, DOTFILES from sphinx.config import string_classes @@ -214,10 +215,9 @@ class StandaloneHTMLBuilder(Builder): self.use_index = self.get_builder_config('use_index', 'html') if self.config.html_experimental_html5_writer and not html5_ready: - self.app.warn(' '.join(( - 'html_experimental_html5_writer is set, but current version is old.', - 'Docutils\' version should be or newer than 0.13, but %s.', - )) % '.'.join(map(str, __version_info__))) + self.app.warn(('html_experimental_html5_writer is set, but current version ' + 'is old. Docutils\' version should be 0.13 or newer, but %s.') % + docutils.__version__) def _get_translations_js(self): # type: () -> unicode