mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Separate sphinx.transforms to multiple files
This commit is contained in:
parent
d281a32b3b
commit
7c99bd5d18
10
sphinx/io.py
10
sphinx/io.py
@ -14,10 +14,12 @@ from docutils.writers import UnfilteredWriter
|
|||||||
from six import string_types, text_type
|
from six import string_types, text_type
|
||||||
|
|
||||||
from sphinx.transforms import (
|
from sphinx.transforms import (
|
||||||
ApplySourceWorkaround, ExtraTranslatableNodes, PreserveTranslatableMessages, Locale,
|
ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences,
|
||||||
CitationReferences, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
|
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds,
|
||||||
AutoNumbering, AutoIndexUpgrader, SortIds, RemoveTranslatableInline,
|
AutoNumbering, AutoIndexUpgrader, FilterSystemMessages,
|
||||||
FilterSystemMessages
|
)
|
||||||
|
from sphinx.transforms.i18n import (
|
||||||
|
PreserveTranslatableMessages, Locale, RemoveTranslatableInline,
|
||||||
)
|
)
|
||||||
from sphinx.util import import_object, split_docinfo
|
from sphinx.util import import_object, split_docinfo
|
||||||
|
|
||||||
|
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
|
@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
sphinx.transforms
|
sphinx.transforms.i18n
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Docutils transforms used by Sphinx when reading documents.
|
Docutils transforms used by Sphinx when reading documents.
|
||||||
|
|
||||||
@ -15,198 +15,19 @@ from docutils import nodes
|
|||||||
from docutils.io import StringInput
|
from docutils.io import StringInput
|
||||||
from docutils.utils import relative_path
|
from docutils.utils import relative_path
|
||||||
from docutils.transforms import Transform
|
from docutils.transforms import Transform
|
||||||
from docutils.transforms.parts import ContentsFilter
|
|
||||||
|
|
||||||
from sphinx import addnodes
|
from sphinx import addnodes
|
||||||
from sphinx.locale import _, init as init_locale
|
|
||||||
from sphinx.util import split_index_msg
|
from sphinx.util import split_index_msg
|
||||||
|
from sphinx.util.i18n import find_catalog
|
||||||
from sphinx.util.nodes import (
|
from sphinx.util.nodes import (
|
||||||
traverse_translatable_index, extract_messages, LITERAL_TYPE_NODES, IMAGE_TYPE_NODES,
|
LITERAL_TYPE_NODES, IMAGE_TYPE_NODES,
|
||||||
apply_source_workaround, is_pending_meta,
|
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.util.pycompat import indent
|
||||||
|
from sphinx.locale import init as init_locale
|
||||||
from sphinx.domains.std import make_glossary_term, split_term_classifiers
|
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):
|
def publish_msgstr(app, source, source_path, source_line, config, settings):
|
||||||
"""Publish msgstr (single line) into docutils document
|
"""Publish msgstr (single line) into docutils document
|
||||||
|
|
||||||
@ -249,19 +70,6 @@ class PreserveTranslatableMessages(Transform):
|
|||||||
node.preserve_original_messages()
|
node.preserve_original_messages()
|
||||||
|
|
||||||
|
|
||||||
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 Locale(Transform):
|
class Locale(Transform):
|
||||||
"""
|
"""
|
||||||
Replace translatable nodes with their translated doctree.
|
Replace translatable nodes with their translated doctree.
|
||||||
@ -608,17 +416,3 @@ class RemoveTranslatableInline(Transform):
|
|||||||
if 'translatable' in inline:
|
if 'translatable' in inline:
|
||||||
inline.parent.remove(inline)
|
inline.parent.remove(inline)
|
||||||
inline.parent += inline.children
|
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
|
|
Loading…
Reference in New Issue
Block a user