mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #2947 from tk0miya/move_env_processors_to_transforms
Move some processors in BuildEnvironment to transforms
This commit is contained in:
commit
8bc89eeedb
@ -728,12 +728,10 @@ class BuildEnvironment(object):
|
||||
doctree = pub.document
|
||||
|
||||
# post-processing
|
||||
self.filter_messages(doctree)
|
||||
self.process_dependencies(docname, doctree)
|
||||
self.process_images(docname, doctree)
|
||||
self.process_downloads(docname, doctree)
|
||||
self.process_metadata(docname, doctree)
|
||||
self.process_refonly_bullet_lists(docname, doctree)
|
||||
self.create_title_from(docname, doctree)
|
||||
self.note_indexentries_from(docname, doctree)
|
||||
self.build_toc_from(docname, doctree)
|
||||
@ -851,14 +849,6 @@ class BuildEnvironment(object):
|
||||
|
||||
# post-processing of read doctrees
|
||||
|
||||
def filter_messages(self, doctree):
|
||||
"""Filter system messages from a doctree."""
|
||||
filterlevel = self.config.keep_warnings and 2 or 5
|
||||
for node in doctree.traverse(nodes.system_message):
|
||||
if node['level'] < filterlevel:
|
||||
self.app.debug('%s [filtered system message]', node.astext())
|
||||
node.parent.remove(node)
|
||||
|
||||
def process_dependencies(self, docname, doctree):
|
||||
"""Process docutils-generated dependency info."""
|
||||
cwd = getcwd()
|
||||
@ -986,67 +976,6 @@ class BuildEnvironment(object):
|
||||
|
||||
del doctree[0]
|
||||
|
||||
def process_refonly_bullet_lists(self, docname, doctree):
|
||||
"""Change refonly bullet lists to use compact_paragraphs.
|
||||
|
||||
Specifically implemented for 'Indices and Tables' section, which looks
|
||||
odd when html_compact_lists is false.
|
||||
"""
|
||||
if self.config.html_compact_lists:
|
||||
return
|
||||
|
||||
class RefOnlyListChecker(nodes.GenericNodeVisitor):
|
||||
"""Raise `nodes.NodeFound` if non-simple list item is encountered.
|
||||
|
||||
Here 'simple' means a list item containing only a paragraph with a
|
||||
single reference in it.
|
||||
"""
|
||||
|
||||
def default_visit(self, node):
|
||||
raise nodes.NodeFound
|
||||
|
||||
def visit_bullet_list(self, node):
|
||||
pass
|
||||
|
||||
def visit_list_item(self, node):
|
||||
children = []
|
||||
for child in node.children:
|
||||
if not isinstance(child, nodes.Invisible):
|
||||
children.append(child)
|
||||
if len(children) != 1:
|
||||
raise nodes.NodeFound
|
||||
if not isinstance(children[0], nodes.paragraph):
|
||||
raise nodes.NodeFound
|
||||
para = children[0]
|
||||
if len(para) != 1:
|
||||
raise nodes.NodeFound
|
||||
if not isinstance(para[0], addnodes.pending_xref):
|
||||
raise nodes.NodeFound
|
||||
raise nodes.SkipChildren
|
||||
|
||||
def invisible_visit(self, node):
|
||||
"""Invisible nodes should be ignored."""
|
||||
pass
|
||||
|
||||
def check_refonly_list(node):
|
||||
"""Check for list with only references in it."""
|
||||
visitor = RefOnlyListChecker(doctree)
|
||||
try:
|
||||
node.walk(visitor)
|
||||
except nodes.NodeFound:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
for node in doctree.traverse(nodes.bullet_list):
|
||||
if check_refonly_list(node):
|
||||
for item in node.traverse(nodes.list_item):
|
||||
para = item[0]
|
||||
ref = para[0]
|
||||
compact_para = addnodes.compact_paragraph()
|
||||
compact_para += ref
|
||||
item.replace(para, compact_para)
|
||||
|
||||
def create_title_from(self, docname, document):
|
||||
"""Add a title node to the document (just copy the first section title),
|
||||
and store that title in the environment.
|
||||
|
16
sphinx/io.py
16
sphinx/io.py
@ -14,9 +14,13 @@ from docutils.writers import UnfilteredWriter
|
||||
from six import string_types, text_type
|
||||
|
||||
from sphinx.transforms import (
|
||||
ApplySourceWorkaround, ExtraTranslatableNodes, PreserveTranslatableMessages, Locale,
|
||||
CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
|
||||
AutoNumbering, AutoIndexUpgrader, SortIds, RemoveTranslatableInline
|
||||
ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences,
|
||||
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds,
|
||||
AutoNumbering, AutoIndexUpgrader, FilterSystemMessages,
|
||||
)
|
||||
from sphinx.transforms.compact_bullet_list import RefOnlyBulletListTransform
|
||||
from sphinx.transforms.i18n import (
|
||||
PreserveTranslatableMessages, Locale, RemoveTranslatableInline,
|
||||
)
|
||||
from sphinx.util import import_object, split_docinfo
|
||||
|
||||
@ -62,7 +66,8 @@ class SphinxStandaloneReader(SphinxBaseReader):
|
||||
transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, PreserveTranslatableMessages,
|
||||
Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets,
|
||||
HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds,
|
||||
RemoveTranslatableInline, PreserveTranslatableMessages]
|
||||
RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages,
|
||||
RefOnlyBulletListTransform]
|
||||
|
||||
|
||||
class SphinxI18nReader(SphinxBaseReader):
|
||||
@ -75,7 +80,8 @@ class SphinxI18nReader(SphinxBaseReader):
|
||||
|
||||
transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences,
|
||||
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
|
||||
AutoNumbering, SortIds, RemoveTranslatableInline]
|
||||
AutoNumbering, SortIds, RemoveTranslatableInline,
|
||||
FilterSystemMessages, RefOnlyBulletListTransform]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
SphinxBaseReader.__init__(self, *args, **kwargs)
|
||||
|
223
sphinx/transforms/__init__.py
Normal file
223
sphinx/transforms/__init__.py
Normal file
@ -0,0 +1,223 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.transforms
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Docutils transforms used by Sphinx when reading documents.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.transforms import Transform
|
||||
from docutils.transforms.parts import ContentsFilter
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.locale import _
|
||||
from sphinx.util.i18n import format_date
|
||||
from sphinx.util.nodes import apply_source_workaround
|
||||
|
||||
default_substitutions = set([
|
||||
'version',
|
||||
'release',
|
||||
'today',
|
||||
])
|
||||
|
||||
|
||||
class DefaultSubstitutions(Transform):
|
||||
"""
|
||||
Replace some substitutions if they aren't defined in the document.
|
||||
"""
|
||||
# run before the default Substitutions
|
||||
default_priority = 210
|
||||
|
||||
def apply(self):
|
||||
env = self.document.settings.env
|
||||
config = self.document.settings.env.config
|
||||
# only handle those not otherwise defined in the document
|
||||
to_handle = default_substitutions - set(self.document.substitution_defs)
|
||||
for ref in self.document.traverse(nodes.substitution_reference):
|
||||
refname = ref['refname']
|
||||
if refname in to_handle:
|
||||
text = config[refname]
|
||||
if refname == 'today' and not text:
|
||||
# special handling: can also specify a strftime format
|
||||
text = format_date(config.today_fmt or _('%b %d, %Y'),
|
||||
language=config.language, warn=env.warn)
|
||||
ref.replace_self(nodes.Text(text, text))
|
||||
|
||||
|
||||
class MoveModuleTargets(Transform):
|
||||
"""
|
||||
Move module targets that are the first thing in a section to the section
|
||||
title.
|
||||
|
||||
XXX Python specific
|
||||
"""
|
||||
default_priority = 210
|
||||
|
||||
def apply(self):
|
||||
for node in self.document.traverse(nodes.target):
|
||||
if not node['ids']:
|
||||
continue
|
||||
if ('ismod' in node and
|
||||
node.parent.__class__ is nodes.section and
|
||||
# index 0 is the section title node
|
||||
node.parent.index(node) == 1):
|
||||
node.parent['ids'][0:0] = node['ids']
|
||||
node.parent.remove(node)
|
||||
|
||||
|
||||
class HandleCodeBlocks(Transform):
|
||||
"""
|
||||
Several code block related transformations.
|
||||
"""
|
||||
default_priority = 210
|
||||
|
||||
def apply(self):
|
||||
# move doctest blocks out of blockquotes
|
||||
for node in self.document.traverse(nodes.block_quote):
|
||||
if all(isinstance(child, nodes.doctest_block) for child
|
||||
in node.children):
|
||||
node.replace_self(node.children)
|
||||
# combine successive doctest blocks
|
||||
# for node in self.document.traverse(nodes.doctest_block):
|
||||
# if node not in node.parent.children:
|
||||
# continue
|
||||
# parindex = node.parent.index(node)
|
||||
# while len(node.parent) > parindex+1 and \
|
||||
# isinstance(node.parent[parindex+1], nodes.doctest_block):
|
||||
# node[0] = nodes.Text(node[0] + '\n\n' +
|
||||
# node.parent[parindex+1][0])
|
||||
# del node.parent[parindex+1]
|
||||
|
||||
|
||||
class AutoNumbering(Transform):
|
||||
"""
|
||||
Register IDs of tables, figures and literal_blocks to assign numbers.
|
||||
"""
|
||||
default_priority = 210
|
||||
|
||||
def apply(self):
|
||||
domain = self.document.settings.env.domains['std']
|
||||
|
||||
for node in self.document.traverse(nodes.Element):
|
||||
if domain.is_enumerable_node(node) and domain.get_numfig_title(node) is not None:
|
||||
self.document.note_implicit_target(node)
|
||||
|
||||
|
||||
class SortIds(Transform):
|
||||
"""
|
||||
Sort secion IDs so that the "id[0-9]+" one comes last.
|
||||
"""
|
||||
default_priority = 261
|
||||
|
||||
def apply(self):
|
||||
for node in self.document.traverse(nodes.section):
|
||||
if len(node['ids']) > 1 and node['ids'][0].startswith('id'):
|
||||
node['ids'] = node['ids'][1:] + [node['ids'][0]]
|
||||
|
||||
|
||||
class CitationReferences(Transform):
|
||||
"""
|
||||
Replace citation references by pending_xref nodes before the default
|
||||
docutils transform tries to resolve them.
|
||||
"""
|
||||
default_priority = 619
|
||||
|
||||
def apply(self):
|
||||
for citnode in self.document.traverse(nodes.citation_reference):
|
||||
cittext = citnode.astext()
|
||||
refnode = addnodes.pending_xref(cittext, refdomain='std', reftype='citation',
|
||||
reftarget=cittext, refwarn=True,
|
||||
ids=citnode["ids"])
|
||||
refnode.source = citnode.source or citnode.parent.source
|
||||
refnode.line = citnode.line or citnode.parent.line
|
||||
refnode += nodes.Text('[' + cittext + ']')
|
||||
citnode.parent.replace(citnode, refnode)
|
||||
|
||||
|
||||
TRANSLATABLE_NODES = {
|
||||
'literal-block': nodes.literal_block,
|
||||
'doctest-block': nodes.doctest_block,
|
||||
'raw': nodes.raw,
|
||||
'index': addnodes.index,
|
||||
'image': nodes.image,
|
||||
}
|
||||
|
||||
|
||||
class ApplySourceWorkaround(Transform):
|
||||
"""
|
||||
update source and rawsource attributes
|
||||
"""
|
||||
default_priority = 10
|
||||
|
||||
def apply(self):
|
||||
for n in self.document.traverse():
|
||||
if isinstance(n, nodes.TextElement):
|
||||
apply_source_workaround(n)
|
||||
|
||||
|
||||
class AutoIndexUpgrader(Transform):
|
||||
"""
|
||||
Detect old style; 4 column based indices and automatically upgrade to new style.
|
||||
"""
|
||||
default_priority = 210
|
||||
|
||||
def apply(self):
|
||||
env = self.document.settings.env
|
||||
for node in self.document.traverse(addnodes.index):
|
||||
if 'entries' in node and any(len(entry) == 4 for entry in node['entries']):
|
||||
msg = ('4 column based index found. '
|
||||
'It might be a bug of extensions you use: %r' % node['entries'])
|
||||
env.warn_node(msg, node)
|
||||
for i, entry in enumerate(node['entries']):
|
||||
if len(entry) == 4:
|
||||
node['entries'][i] = entry + (None,)
|
||||
|
||||
|
||||
class ExtraTranslatableNodes(Transform):
|
||||
"""
|
||||
make nodes translatable
|
||||
"""
|
||||
default_priority = 10
|
||||
|
||||
def apply(self):
|
||||
targets = self.document.settings.env.config.gettext_additional_targets
|
||||
target_nodes = [v for k, v in TRANSLATABLE_NODES.items() if k in targets]
|
||||
if not target_nodes:
|
||||
return
|
||||
|
||||
def is_translatable_node(node):
|
||||
return isinstance(node, tuple(target_nodes))
|
||||
|
||||
for node in self.document.traverse(is_translatable_node):
|
||||
node['translatable'] = True
|
||||
|
||||
|
||||
class FilterSystemMessages(Transform):
|
||||
"""Filter system messages from a doctree."""
|
||||
default_priority = 999
|
||||
|
||||
def apply(self):
|
||||
env = self.document.settings.env
|
||||
filterlevel = env.config.keep_warnings and 2 or 5
|
||||
for node in self.document.traverse(nodes.system_message):
|
||||
if node['level'] < filterlevel:
|
||||
env.app.debug('%s [filtered system message]', node.astext())
|
||||
node.parent.remove(node)
|
||||
|
||||
|
||||
class SphinxContentsFilter(ContentsFilter):
|
||||
"""
|
||||
Used with BuildEnvironment.add_toc_from() to discard cross-file links
|
||||
within table-of-contents link nodes.
|
||||
"""
|
||||
def visit_pending_xref(self, node):
|
||||
text = node.astext()
|
||||
self.parent.append(nodes.literal(text, text))
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_image(self, node):
|
||||
raise nodes.SkipNode
|
82
sphinx/transforms/compact_bullet_list.py
Normal file
82
sphinx/transforms/compact_bullet_list.py
Normal file
@ -0,0 +1,82 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.transforms.compact_bullet_list
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Docutils transforms used by Sphinx when reading documents.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.transforms import Transform
|
||||
|
||||
from sphinx import addnodes
|
||||
|
||||
|
||||
class RefOnlyListChecker(nodes.GenericNodeVisitor):
|
||||
"""Raise `nodes.NodeFound` if non-simple list item is encountered.
|
||||
|
||||
Here 'simple' means a list item containing only a paragraph with a
|
||||
single reference in it.
|
||||
"""
|
||||
|
||||
def default_visit(self, node):
|
||||
raise nodes.NodeFound
|
||||
|
||||
def visit_bullet_list(self, node):
|
||||
pass
|
||||
|
||||
def visit_list_item(self, node):
|
||||
children = []
|
||||
for child in node.children:
|
||||
if not isinstance(child, nodes.Invisible):
|
||||
children.append(child)
|
||||
if len(children) != 1:
|
||||
raise nodes.NodeFound
|
||||
if not isinstance(children[0], nodes.paragraph):
|
||||
raise nodes.NodeFound
|
||||
para = children[0]
|
||||
if len(para) != 1:
|
||||
raise nodes.NodeFound
|
||||
if not isinstance(para[0], addnodes.pending_xref):
|
||||
raise nodes.NodeFound
|
||||
raise nodes.SkipChildren
|
||||
|
||||
def invisible_visit(self, node):
|
||||
"""Invisible nodes should be ignored."""
|
||||
pass
|
||||
|
||||
|
||||
class RefOnlyBulletListTransform(Transform):
|
||||
"""Change refonly bullet lists to use compact_paragraphs.
|
||||
|
||||
Specifically implemented for 'Indices and Tables' section, which looks
|
||||
odd when html_compact_lists is false.
|
||||
"""
|
||||
default_priority = 100
|
||||
|
||||
def apply(self):
|
||||
env = self.document.settings.env
|
||||
if env.config.html_compact_lists:
|
||||
return
|
||||
|
||||
def check_refonly_list(node):
|
||||
"""Check for list with only references in it."""
|
||||
visitor = RefOnlyListChecker(self.document)
|
||||
try:
|
||||
node.walk(visitor)
|
||||
except nodes.NodeFound:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
for node in self.document.traverse(nodes.bullet_list):
|
||||
if check_refonly_list(node):
|
||||
for item in node.traverse(nodes.list_item):
|
||||
para = item[0]
|
||||
ref = para[0]
|
||||
compact_para = addnodes.compact_paragraph()
|
||||
compact_para += ref
|
||||
item.replace(para, compact_para)
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.transforms
|
||||
~~~~~~~~~~~~~~~~~
|
||||
sphinx.transforms.i18n
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Docutils transforms used by Sphinx when reading documents.
|
||||
|
||||
@ -15,198 +15,19 @@ from docutils import nodes
|
||||
from docutils.io import StringInput
|
||||
from docutils.utils import relative_path
|
||||
from docutils.transforms import Transform
|
||||
from docutils.transforms.parts import ContentsFilter
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.locale import _, init as init_locale
|
||||
from sphinx.util import split_index_msg
|
||||
from sphinx.util.i18n import find_catalog
|
||||
from sphinx.util.nodes import (
|
||||
traverse_translatable_index, extract_messages, LITERAL_TYPE_NODES, IMAGE_TYPE_NODES,
|
||||
apply_source_workaround, is_pending_meta,
|
||||
LITERAL_TYPE_NODES, IMAGE_TYPE_NODES,
|
||||
extract_messages, is_pending_meta, traverse_translatable_index,
|
||||
)
|
||||
from sphinx.util.i18n import find_catalog, format_date
|
||||
from sphinx.util.pycompat import indent
|
||||
from sphinx.locale import init as init_locale
|
||||
from sphinx.domains.std import make_glossary_term, split_term_classifiers
|
||||
|
||||
|
||||
default_substitutions = set([
|
||||
'version',
|
||||
'release',
|
||||
'today',
|
||||
])
|
||||
|
||||
|
||||
class DefaultSubstitutions(Transform):
|
||||
"""
|
||||
Replace some substitutions if they aren't defined in the document.
|
||||
"""
|
||||
# run before the default Substitutions
|
||||
default_priority = 210
|
||||
|
||||
def apply(self):
|
||||
env = self.document.settings.env
|
||||
config = self.document.settings.env.config
|
||||
# only handle those not otherwise defined in the document
|
||||
to_handle = default_substitutions - set(self.document.substitution_defs)
|
||||
for ref in self.document.traverse(nodes.substitution_reference):
|
||||
refname = ref['refname']
|
||||
if refname in to_handle:
|
||||
text = config[refname]
|
||||
if refname == 'today' and not text:
|
||||
# special handling: can also specify a strftime format
|
||||
text = format_date(config.today_fmt or _('%b %d, %Y'),
|
||||
language=config.language, warn=env.warn)
|
||||
ref.replace_self(nodes.Text(text, text))
|
||||
|
||||
|
||||
class MoveModuleTargets(Transform):
|
||||
"""
|
||||
Move module targets that are the first thing in a section to the section
|
||||
title.
|
||||
|
||||
XXX Python specific
|
||||
"""
|
||||
default_priority = 210
|
||||
|
||||
def apply(self):
|
||||
for node in self.document.traverse(nodes.target):
|
||||
if not node['ids']:
|
||||
continue
|
||||
if ('ismod' in node and
|
||||
node.parent.__class__ is nodes.section and
|
||||
# index 0 is the section title node
|
||||
node.parent.index(node) == 1):
|
||||
node.parent['ids'][0:0] = node['ids']
|
||||
node.parent.remove(node)
|
||||
|
||||
|
||||
class HandleCodeBlocks(Transform):
|
||||
"""
|
||||
Several code block related transformations.
|
||||
"""
|
||||
default_priority = 210
|
||||
|
||||
def apply(self):
|
||||
# move doctest blocks out of blockquotes
|
||||
for node in self.document.traverse(nodes.block_quote):
|
||||
if all(isinstance(child, nodes.doctest_block) for child
|
||||
in node.children):
|
||||
node.replace_self(node.children)
|
||||
# combine successive doctest blocks
|
||||
# for node in self.document.traverse(nodes.doctest_block):
|
||||
# if node not in node.parent.children:
|
||||
# continue
|
||||
# parindex = node.parent.index(node)
|
||||
# while len(node.parent) > parindex+1 and \
|
||||
# isinstance(node.parent[parindex+1], nodes.doctest_block):
|
||||
# node[0] = nodes.Text(node[0] + '\n\n' +
|
||||
# node.parent[parindex+1][0])
|
||||
# del node.parent[parindex+1]
|
||||
|
||||
|
||||
class AutoNumbering(Transform):
|
||||
"""
|
||||
Register IDs of tables, figures and literal_blocks to assign numbers.
|
||||
"""
|
||||
default_priority = 210
|
||||
|
||||
def apply(self):
|
||||
domain = self.document.settings.env.domains['std']
|
||||
|
||||
for node in self.document.traverse(nodes.Element):
|
||||
if domain.is_enumerable_node(node) and domain.get_numfig_title(node) is not None:
|
||||
self.document.note_implicit_target(node)
|
||||
|
||||
|
||||
class SortIds(Transform):
|
||||
"""
|
||||
Sort secion IDs so that the "id[0-9]+" one comes last.
|
||||
"""
|
||||
default_priority = 261
|
||||
|
||||
def apply(self):
|
||||
for node in self.document.traverse(nodes.section):
|
||||
if len(node['ids']) > 1 and node['ids'][0].startswith('id'):
|
||||
node['ids'] = node['ids'][1:] + [node['ids'][0]]
|
||||
|
||||
|
||||
class CitationReferences(Transform):
|
||||
"""
|
||||
Replace citation references by pending_xref nodes before the default
|
||||
docutils transform tries to resolve them.
|
||||
"""
|
||||
default_priority = 619
|
||||
|
||||
def apply(self):
|
||||
for citnode in self.document.traverse(nodes.citation_reference):
|
||||
cittext = citnode.astext()
|
||||
refnode = addnodes.pending_xref(cittext, refdomain='std', reftype='citation',
|
||||
reftarget=cittext, refwarn=True,
|
||||
ids=citnode["ids"])
|
||||
refnode.source = citnode.source or citnode.parent.source
|
||||
refnode.line = citnode.line or citnode.parent.line
|
||||
refnode += nodes.Text('[' + cittext + ']')
|
||||
citnode.parent.replace(citnode, refnode)
|
||||
|
||||
|
||||
TRANSLATABLE_NODES = {
|
||||
'literal-block': nodes.literal_block,
|
||||
'doctest-block': nodes.doctest_block,
|
||||
'raw': nodes.raw,
|
||||
'index': addnodes.index,
|
||||
'image': nodes.image,
|
||||
}
|
||||
|
||||
|
||||
class ApplySourceWorkaround(Transform):
|
||||
"""
|
||||
update source and rawsource attributes
|
||||
"""
|
||||
default_priority = 10
|
||||
|
||||
def apply(self):
|
||||
for n in self.document.traverse():
|
||||
if isinstance(n, nodes.TextElement):
|
||||
apply_source_workaround(n)
|
||||
|
||||
|
||||
class AutoIndexUpgrader(Transform):
|
||||
"""
|
||||
Detect old style; 4 column based indices and automatically upgrade to new style.
|
||||
"""
|
||||
default_priority = 210
|
||||
|
||||
def apply(self):
|
||||
env = self.document.settings.env
|
||||
for node in self.document.traverse(addnodes.index):
|
||||
if 'entries' in node and any(len(entry) == 4 for entry in node['entries']):
|
||||
msg = ('4 column based index found. '
|
||||
'It might be a bug of extensions you use: %r' % node['entries'])
|
||||
env.warn_node(msg, node)
|
||||
for i, entry in enumerate(node['entries']):
|
||||
if len(entry) == 4:
|
||||
node['entries'][i] = entry + (None,)
|
||||
|
||||
|
||||
class ExtraTranslatableNodes(Transform):
|
||||
"""
|
||||
make nodes translatable
|
||||
"""
|
||||
default_priority = 10
|
||||
|
||||
def apply(self):
|
||||
targets = self.document.settings.env.config.gettext_additional_targets
|
||||
target_nodes = [v for k, v in TRANSLATABLE_NODES.items() if k in targets]
|
||||
if not target_nodes:
|
||||
return
|
||||
|
||||
def is_translatable_node(node):
|
||||
return isinstance(node, tuple(target_nodes))
|
||||
|
||||
for node in self.document.traverse(is_translatable_node):
|
||||
node['translatable'] = True
|
||||
|
||||
|
||||
def publish_msgstr(app, source, source_path, source_line, config, settings):
|
||||
"""Publish msgstr (single line) into docutils document
|
||||
|
||||
@ -595,17 +416,3 @@ class RemoveTranslatableInline(Transform):
|
||||
if 'translatable' in inline:
|
||||
inline.parent.remove(inline)
|
||||
inline.parent += inline.children
|
||||
|
||||
|
||||
class SphinxContentsFilter(ContentsFilter):
|
||||
"""
|
||||
Used with BuildEnvironment.add_toc_from() to discard cross-file links
|
||||
within table-of-contents link nodes.
|
||||
"""
|
||||
def visit_pending_xref(self, node):
|
||||
text = node.astext()
|
||||
self.parent.append(nodes.literal(text, text))
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_image(self, node):
|
||||
raise nodes.SkipNode
|
4
tests/roots/test-keep_warnings/conf.py
Normal file
4
tests/roots/test-keep_warnings/conf.py
Normal file
@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
master_doc = 'index'
|
||||
keep_warnings = True
|
2
tests/roots/test-keep_warnings/index.rst
Normal file
2
tests/roots/test-keep_warnings/index.rst
Normal file
@ -0,0 +1,2 @@
|
||||
keep_warnings
|
||||
=====
|
8
tests/roots/test-refonly_bullet_list/conf.py
Normal file
8
tests/roots/test-refonly_bullet_list/conf.py
Normal file
@ -0,0 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
master_doc = 'index'
|
||||
html_compact_lists = False
|
||||
|
||||
latex_documents = [
|
||||
(master_doc, 'test.tex', 'The basic Sphinx documentation for testing', 'Sphinx', 'report')
|
||||
]
|
14
tests/roots/test-refonly_bullet_list/index.rst
Normal file
14
tests/roots/test-refonly_bullet_list/index.rst
Normal file
@ -0,0 +1,14 @@
|
||||
test-refonly_bullet_list
|
||||
========================
|
||||
|
||||
List A:
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
List B:
|
||||
|
||||
* Hello
|
||||
* Sphinx
|
||||
* World
|
@ -15,6 +15,7 @@ import pickle
|
||||
from docutils import frontend, utils, nodes
|
||||
from docutils.parsers import rst
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.util import texescape
|
||||
from sphinx.writers.html import HTMLWriter, SmartyPantsHTMLTranslator
|
||||
from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator
|
||||
@ -170,3 +171,39 @@ def test_rst_prolog(app, status, warning):
|
||||
# rst_prolog & rst_epilog on exlucding reST parser
|
||||
assert not md.rawsource.startswith('*Hello world*.')
|
||||
assert not md.rawsource.endswith('*Good-bye world*.\n')
|
||||
|
||||
|
||||
@with_app(buildername='dummy', testroot='keep_warnings')
|
||||
def test_keep_warnings_is_True(app, status, warning):
|
||||
app.builder.build_all()
|
||||
doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes())
|
||||
assert_node(doctree[0], nodes.section)
|
||||
assert len(doctree[0]) == 2
|
||||
assert_node(doctree[0][1], nodes.system_message)
|
||||
|
||||
|
||||
@with_app(buildername='dummy', testroot='keep_warnings',
|
||||
confoverrides={'keep_warnings': False})
|
||||
def test_keep_warnings_is_False(app, status, warning):
|
||||
app.builder.build_all()
|
||||
doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes())
|
||||
assert_node(doctree[0], nodes.section)
|
||||
assert len(doctree[0]) == 1
|
||||
|
||||
|
||||
@with_app(buildername='dummy', testroot='refonly_bullet_list')
|
||||
def test_compact_refonly_bullet_list(app, status, warning):
|
||||
app.builder.build_all()
|
||||
doctree = pickle.loads((app.doctreedir / 'index.doctree').bytes())
|
||||
assert_node(doctree[0], nodes.section)
|
||||
assert len(doctree[0]) == 5
|
||||
|
||||
assert doctree[0][1].astext() == 'List A:'
|
||||
assert_node(doctree[0][2], nodes.bullet_list)
|
||||
assert_node(doctree[0][2][0][0], addnodes.compact_paragraph)
|
||||
assert doctree[0][2][0][0].astext() == 'genindex'
|
||||
|
||||
assert doctree[0][3].astext() == 'List B:'
|
||||
assert_node(doctree[0][4], nodes.bullet_list)
|
||||
assert_node(doctree[0][4][0][0], nodes.paragraph)
|
||||
assert doctree[0][4][0][0].astext() == 'Hello'
|
||||
|
Loading…
Reference in New Issue
Block a user