mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add the `:no-typesetting:
` option for only creating targets (#10478)
Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com>
This commit is contained in:
parent
05a14ff007
commit
97d2c5da2f
3
CHANGES
3
CHANGES
@ -29,6 +29,9 @@ Features added
|
|||||||
* #6319: viewcode: Add :confval:`viewcode_line_numbers` to control
|
* #6319: viewcode: Add :confval:`viewcode_line_numbers` to control
|
||||||
whether line numbers are added to rendered source code.
|
whether line numbers are added to rendered source code.
|
||||||
Patch by Ben Krikler.
|
Patch by Ben Krikler.
|
||||||
|
* #9662: Add the ``:no-typesetting:`` option to suppress textual output
|
||||||
|
and only create a linkable anchor.
|
||||||
|
Patch by Latosha Maltba.
|
||||||
|
|
||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
@ -54,6 +54,9 @@ can give the directive option flag ``:nocontentsentry:``.
|
|||||||
If you want to typeset an object description, without even making it available
|
If you want to typeset an object description, without even making it available
|
||||||
for cross-referencing, you can give the directive option flag ``:noindex:``
|
for cross-referencing, you can give the directive option flag ``:noindex:``
|
||||||
(which implies ``:noindexentry:``).
|
(which implies ``:noindexentry:``).
|
||||||
|
If you do not want to typeset anything, you can give the directive option flag
|
||||||
|
``:no-typesetting:``. This can for example be used to create only a target and
|
||||||
|
index entry for later reference.
|
||||||
Though, note that not every directive in every domain may support these
|
Though, note that not every directive in every domain may support these
|
||||||
options.
|
options.
|
||||||
|
|
||||||
@ -65,6 +68,10 @@ options.
|
|||||||
The directive option ``:nocontentsentry:`` in the Python, C, C++, Javascript,
|
The directive option ``:nocontentsentry:`` in the Python, C, C++, Javascript,
|
||||||
and reStructuredText domains.
|
and reStructuredText domains.
|
||||||
|
|
||||||
|
.. versionadded:: 7.2
|
||||||
|
The directive option ``no-typesetting`` in the Python, C, C++, Javascript,
|
||||||
|
and reStructuredText domains.
|
||||||
|
|
||||||
An example using a Python domain directive::
|
An example using a Python domain directive::
|
||||||
|
|
||||||
.. py:function:: spam(eggs)
|
.. py:function:: spam(eggs)
|
||||||
@ -91,6 +98,23 @@ you could say ::
|
|||||||
As you can see, both directive and role names contain the domain name and the
|
As you can see, both directive and role names contain the domain name and the
|
||||||
directive name.
|
directive name.
|
||||||
|
|
||||||
|
The directive option ``:no-typesetting:`` can be used to create a target
|
||||||
|
(and index entry) which can later be referenced
|
||||||
|
by the roles provided by the domain.
|
||||||
|
This is particularly useful for literate programming:
|
||||||
|
|
||||||
|
.. code-block:: rst
|
||||||
|
|
||||||
|
.. py:function:: spam(eggs)
|
||||||
|
:no-typesetting:
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
def spam(eggs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
The function :py:func:`spam` does nothing.
|
||||||
|
|
||||||
.. rubric:: Default Domain
|
.. rubric:: Default Domain
|
||||||
|
|
||||||
For documentation describing objects from solely one domain, authors will not
|
For documentation describing objects from solely one domain, authors will not
|
||||||
|
@ -57,6 +57,7 @@ class ObjectDescription(SphinxDirective, Generic[ObjDescT]):
|
|||||||
'noindex': directives.flag,
|
'noindex': directives.flag,
|
||||||
'noindexentry': directives.flag,
|
'noindexentry': directives.flag,
|
||||||
'nocontentsentry': directives.flag,
|
'nocontentsentry': directives.flag,
|
||||||
|
'no-typesetting': directives.flag,
|
||||||
}
|
}
|
||||||
|
|
||||||
# types of doc fields that this directive handles, see sphinx.util.docfields
|
# types of doc fields that this directive handles, see sphinx.util.docfields
|
||||||
@ -218,6 +219,7 @@ class ObjectDescription(SphinxDirective, Generic[ObjDescT]):
|
|||||||
node['noindex'] = noindex = ('noindex' in self.options)
|
node['noindex'] = noindex = ('noindex' in self.options)
|
||||||
node['noindexentry'] = ('noindexentry' in self.options)
|
node['noindexentry'] = ('noindexentry' in self.options)
|
||||||
node['nocontentsentry'] = ('nocontentsentry' in self.options)
|
node['nocontentsentry'] = ('nocontentsentry' in self.options)
|
||||||
|
node['no-typesetting'] = ('no-typesetting' in self.options)
|
||||||
if self.domain:
|
if self.domain:
|
||||||
node['classes'].append(self.domain)
|
node['classes'].append(self.domain)
|
||||||
node['classes'].append(node['objtype'])
|
node['classes'].append(node['objtype'])
|
||||||
@ -270,6 +272,19 @@ class ObjectDescription(SphinxDirective, Generic[ObjDescT]):
|
|||||||
DocFieldTransformer(self).transform_all(contentnode)
|
DocFieldTransformer(self).transform_all(contentnode)
|
||||||
self.env.temp_data['object'] = None
|
self.env.temp_data['object'] = None
|
||||||
self.after_content()
|
self.after_content()
|
||||||
|
|
||||||
|
if node['no-typesetting']:
|
||||||
|
# Attempt to return the index node, and a new target node
|
||||||
|
# containing all the ids of this node and its children.
|
||||||
|
# If ``:noindex:`` is set, or there are no ids on the node
|
||||||
|
# or any of its children, then just return the index node,
|
||||||
|
# as Docutils expects a target node to have at least one id.
|
||||||
|
if node_ids := [node_id for el in node.findall(nodes.Element)
|
||||||
|
for node_id in el.get('ids', ())]:
|
||||||
|
target_node = nodes.target(ids=node_ids)
|
||||||
|
self.set_source_info(target_node)
|
||||||
|
return [self.indexnode, target_node]
|
||||||
|
return [self.indexnode]
|
||||||
return [self.indexnode, node]
|
return [self.indexnode, node]
|
||||||
|
|
||||||
|
|
||||||
|
@ -3166,6 +3166,7 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
|||||||
option_spec: OptionSpec = {
|
option_spec: OptionSpec = {
|
||||||
'noindexentry': directives.flag,
|
'noindexentry': directives.flag,
|
||||||
'nocontentsentry': directives.flag,
|
'nocontentsentry': directives.flag,
|
||||||
|
'no-typesetting': directives.flag,
|
||||||
'single-line-parameter-list': directives.flag,
|
'single-line-parameter-list': directives.flag,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7214,6 +7214,7 @@ class CPPObject(ObjectDescription[ASTDeclaration]):
|
|||||||
option_spec: OptionSpec = {
|
option_spec: OptionSpec = {
|
||||||
'noindexentry': directives.flag,
|
'noindexentry': directives.flag,
|
||||||
'nocontentsentry': directives.flag,
|
'nocontentsentry': directives.flag,
|
||||||
|
'no-typesetting': directives.flag,
|
||||||
'tparam-line-spec': directives.flag,
|
'tparam-line-spec': directives.flag,
|
||||||
'single-line-parameter-list': directives.flag,
|
'single-line-parameter-list': directives.flag,
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ class JSObject(ObjectDescription[tuple[str, str]]):
|
|||||||
'noindex': directives.flag,
|
'noindex': directives.flag,
|
||||||
'noindexentry': directives.flag,
|
'noindexentry': directives.flag,
|
||||||
'nocontentsentry': directives.flag,
|
'nocontentsentry': directives.flag,
|
||||||
|
'no-typesetting': directives.flag,
|
||||||
'single-line-parameter-list': directives.flag,
|
'single-line-parameter-list': directives.flag,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,6 +294,7 @@ class JSModule(SphinxDirective):
|
|||||||
option_spec: OptionSpec = {
|
option_spec: OptionSpec = {
|
||||||
'noindex': directives.flag,
|
'noindex': directives.flag,
|
||||||
'nocontentsentry': directives.flag,
|
'nocontentsentry': directives.flag,
|
||||||
|
'no-typesetting': directives.flag,
|
||||||
}
|
}
|
||||||
|
|
||||||
def run(self) -> list[Node]:
|
def run(self) -> list[Node]:
|
||||||
@ -316,12 +318,13 @@ class JSModule(SphinxDirective):
|
|||||||
domain.note_object(mod_name, 'module', node_id,
|
domain.note_object(mod_name, 'module', node_id,
|
||||||
location=(self.env.docname, self.lineno))
|
location=(self.env.docname, self.lineno))
|
||||||
|
|
||||||
target = nodes.target('', '', ids=[node_id], ismod=True)
|
# The node order is: index node first, then target node
|
||||||
self.state.document.note_explicit_target(target)
|
|
||||||
ret.append(target)
|
|
||||||
indextext = _('%s (module)') % mod_name
|
indextext = _('%s (module)') % mod_name
|
||||||
inode = addnodes.index(entries=[('single', indextext, node_id, '', None)])
|
inode = addnodes.index(entries=[('single', indextext, node_id, '', None)])
|
||||||
ret.append(inode)
|
ret.append(inode)
|
||||||
|
target = nodes.target('', '', ids=[node_id], ismod=True)
|
||||||
|
self.state.document.note_explicit_target(target)
|
||||||
|
ret.append(target)
|
||||||
ret.extend(content_node.children)
|
ret.extend(content_node.children)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -662,6 +662,7 @@ class PyObject(ObjectDescription[tuple[str, str]]):
|
|||||||
'noindex': directives.flag,
|
'noindex': directives.flag,
|
||||||
'noindexentry': directives.flag,
|
'noindexentry': directives.flag,
|
||||||
'nocontentsentry': directives.flag,
|
'nocontentsentry': directives.flag,
|
||||||
|
'no-typesetting': directives.flag,
|
||||||
'single-line-parameter-list': directives.flag,
|
'single-line-parameter-list': directives.flag,
|
||||||
'single-line-type-parameter-list': directives.flag,
|
'single-line-type-parameter-list': directives.flag,
|
||||||
'module': directives.unchanged,
|
'module': directives.unchanged,
|
||||||
@ -1262,6 +1263,7 @@ class PyModule(SphinxDirective):
|
|||||||
'synopsis': lambda x: x,
|
'synopsis': lambda x: x,
|
||||||
'noindex': directives.flag,
|
'noindex': directives.flag,
|
||||||
'nocontentsentry': directives.flag,
|
'nocontentsentry': directives.flag,
|
||||||
|
'no-typesetting': directives.flag,
|
||||||
'deprecated': directives.flag,
|
'deprecated': directives.flag,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1294,10 +1296,11 @@ class PyModule(SphinxDirective):
|
|||||||
|
|
||||||
# the platform and synopsis aren't printed; in fact, they are only
|
# the platform and synopsis aren't printed; in fact, they are only
|
||||||
# used in the modindex currently
|
# used in the modindex currently
|
||||||
ret.append(target)
|
|
||||||
indextext = f'module; {modname}'
|
indextext = f'module; {modname}'
|
||||||
inode = addnodes.index(entries=[('pair', indextext, node_id, '', None)])
|
inode = addnodes.index(entries=[('pair', indextext, node_id, '', None)])
|
||||||
|
# The node order is: index node first, then target node.
|
||||||
ret.append(inode)
|
ret.append(inode)
|
||||||
|
ret.append(target)
|
||||||
ret.extend(content_node.children)
|
ret.extend(content_node.children)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ class ReSTMarkup(ObjectDescription[str]):
|
|||||||
'noindex': directives.flag,
|
'noindex': directives.flag,
|
||||||
'noindexentry': directives.flag,
|
'noindexentry': directives.flag,
|
||||||
'nocontentsentry': directives.flag,
|
'nocontentsentry': directives.flag,
|
||||||
|
'no-typesetting': directives.flag,
|
||||||
}
|
}
|
||||||
|
|
||||||
def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None:
|
def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None:
|
||||||
|
@ -414,6 +414,77 @@ class GlossarySorter(SphinxTransform):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ReorderConsecutiveTargetAndIndexNodes(SphinxTransform):
|
||||||
|
"""Index nodes interspersed between target nodes prevent other
|
||||||
|
Transformations from combining those target nodes,
|
||||||
|
e.g. ``PropagateTargets``. This transformation reorders them:
|
||||||
|
|
||||||
|
Given the following ``document`` as input::
|
||||||
|
|
||||||
|
<document>
|
||||||
|
<target ids="id1" ...>
|
||||||
|
<index entries="...1...">
|
||||||
|
<target ids="id2" ...>
|
||||||
|
<target ids="id3" ...>
|
||||||
|
<index entries="...2...">
|
||||||
|
<target ids="id4" ...>
|
||||||
|
|
||||||
|
The transformed result will be::
|
||||||
|
|
||||||
|
<document>
|
||||||
|
<index entries="...1...">
|
||||||
|
<index entries="...2...">
|
||||||
|
<target ids="id1" ...>
|
||||||
|
<target ids="id2" ...>
|
||||||
|
<target ids="id3" ...>
|
||||||
|
<target ids="id4" ...>
|
||||||
|
"""
|
||||||
|
|
||||||
|
# This transform MUST run before ``PropagateTargets``.
|
||||||
|
default_priority = 220
|
||||||
|
|
||||||
|
def apply(self, **kwargs: Any) -> None:
|
||||||
|
for target in self.document.findall(nodes.target):
|
||||||
|
_reorder_index_target_nodes(target)
|
||||||
|
|
||||||
|
|
||||||
|
def _reorder_index_target_nodes(start_node: nodes.target) -> None:
|
||||||
|
"""Sort target and index nodes.
|
||||||
|
|
||||||
|
Find all consecutive target and index nodes starting from ``start_node``,
|
||||||
|
and move all index nodes to before the first target node.
|
||||||
|
"""
|
||||||
|
nodes_to_reorder: list[nodes.target | addnodes.index] = []
|
||||||
|
|
||||||
|
# Note that we cannot use 'condition' to filter,
|
||||||
|
# as we want *consecutive* target & index nodes.
|
||||||
|
node: nodes.Node
|
||||||
|
for node in start_node.findall(descend=False, siblings=True):
|
||||||
|
if isinstance(node, (nodes.target, addnodes.index)):
|
||||||
|
nodes_to_reorder.append(node)
|
||||||
|
continue
|
||||||
|
break # must be a consecutive run of target or index nodes
|
||||||
|
|
||||||
|
if len(nodes_to_reorder) < 2:
|
||||||
|
return # Nothing to reorder
|
||||||
|
|
||||||
|
parent = nodes_to_reorder[0].parent
|
||||||
|
if parent == nodes_to_reorder[-1].parent:
|
||||||
|
first_idx = parent.index(nodes_to_reorder[0])
|
||||||
|
last_idx = parent.index(nodes_to_reorder[-1])
|
||||||
|
if first_idx + len(nodes_to_reorder) - 1 == last_idx:
|
||||||
|
parent[first_idx:last_idx + 1] = sorted(nodes_to_reorder, key=_sort_key)
|
||||||
|
|
||||||
|
|
||||||
|
def _sort_key(node: nodes.Node) -> int:
|
||||||
|
# Must be a stable sort.
|
||||||
|
if isinstance(node, addnodes.index):
|
||||||
|
return 0
|
||||||
|
if isinstance(node, nodes.target):
|
||||||
|
return 1
|
||||||
|
raise ValueError(f'_sort_key called with unexpected node type {type(node)!r}')
|
||||||
|
|
||||||
|
|
||||||
def setup(app: Sphinx) -> dict[str, Any]:
|
def setup(app: Sphinx) -> dict[str, Any]:
|
||||||
app.add_transform(ApplySourceWorkaround)
|
app.add_transform(ApplySourceWorkaround)
|
||||||
app.add_transform(ExtraTranslatableNodes)
|
app.add_transform(ExtraTranslatableNodes)
|
||||||
@ -430,6 +501,7 @@ def setup(app: Sphinx) -> dict[str, Any]:
|
|||||||
app.add_transform(DoctreeReadEvent)
|
app.add_transform(DoctreeReadEvent)
|
||||||
app.add_transform(ManpageLink)
|
app.add_transform(ManpageLink)
|
||||||
app.add_transform(GlossarySorter)
|
app.add_transform(GlossarySorter)
|
||||||
|
app.add_transform(ReorderConsecutiveTargetAndIndexNodes)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'version': 'builtin',
|
'version': 'builtin',
|
||||||
|
108
tests/test_directives_no_typesetting.py
Normal file
108
tests/test_directives_no_typesetting.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
"""Tests the directives"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from docutils import nodes
|
||||||
|
|
||||||
|
from sphinx import addnodes
|
||||||
|
from sphinx.testing import restructuredtext
|
||||||
|
from sphinx.testing.util import assert_node
|
||||||
|
|
||||||
|
DOMAINS = [
|
||||||
|
# directive, noindex, noindexentry, signature of f, signature of g, index entry of g
|
||||||
|
('c:function', False, True, 'void f()', 'void g()', ('single', 'g (C function)', 'c.g', '', None)),
|
||||||
|
('cpp:function', False, True, 'void f()', 'void g()', ('single', 'g (C++ function)', '_CPPv41gv', '', None)),
|
||||||
|
('js:function', True, True, 'f()', 'g()', ('single', 'g() (built-in function)', 'g', '', None)),
|
||||||
|
('py:function', True, True, 'f()', 'g()', ('pair', 'built-in function; g()', 'g', '', None)),
|
||||||
|
('rst:directive', True, False, 'f', 'g', ('single', 'g (directive)', 'directive-g', '', None)),
|
||||||
|
('cmdoption', True, False, 'f', 'g', ('pair', 'command line option; g', 'cmdoption-arg-g', '', None)),
|
||||||
|
('envvar', True, False, 'f', 'g', ('single', 'environment variable; g', 'envvar-g', '', None)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(('directive', 'noindex', 'noindexentry', 'sig_f', 'sig_g', 'index_g'), DOMAINS)
|
||||||
|
def test_object_description_no_typesetting(app, directive, noindex, noindexentry, sig_f, sig_g, index_g):
|
||||||
|
text = (f'.. {directive}:: {sig_f}\n'
|
||||||
|
f' :no-typesetting:\n')
|
||||||
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
assert_node(doctree, (addnodes.index, nodes.target))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(('directive', 'noindex', 'noindexentry', 'sig_f', 'sig_g', 'index_g'), DOMAINS)
|
||||||
|
def test_object_description_no_typesetting_twice(app, directive, noindex, noindexentry, sig_f, sig_g, index_g):
|
||||||
|
text = (f'.. {directive}:: {sig_f}\n'
|
||||||
|
f' :no-typesetting:\n'
|
||||||
|
f'.. {directive}:: {sig_g}\n'
|
||||||
|
f' :no-typesetting:\n')
|
||||||
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
# Note that all index nodes come before the target nodes
|
||||||
|
assert_node(doctree, (addnodes.index, addnodes.index, nodes.target, nodes.target))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(('directive', 'noindex', 'noindexentry', 'sig_f', 'sig_g', 'index_g'), DOMAINS)
|
||||||
|
def test_object_description_no_typesetting_noindex_orig(app, directive, noindex, noindexentry, sig_f, sig_g, index_g):
|
||||||
|
if not noindex:
|
||||||
|
pytest.skip(f'{directive} does not support :noindex: option')
|
||||||
|
text = (f'.. {directive}:: {sig_f}\n'
|
||||||
|
f' :noindex:\n'
|
||||||
|
f'.. {directive}:: {sig_g}\n')
|
||||||
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
assert_node(doctree, (addnodes.index, addnodes.desc, addnodes.index, addnodes.desc))
|
||||||
|
assert_node(doctree[2], addnodes.index, entries=[index_g])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(('directive', 'noindex', 'noindexentry', 'sig_f', 'sig_g', 'index_g'), DOMAINS)
|
||||||
|
def test_object_description_no_typesetting_noindex(app, directive, noindex, noindexentry, sig_f, sig_g, index_g):
|
||||||
|
if not noindex:
|
||||||
|
pytest.skip(f'{directive} does not support :noindex: option')
|
||||||
|
text = (f'.. {directive}:: {sig_f}\n'
|
||||||
|
f' :noindex:\n'
|
||||||
|
f' :no-typesetting:\n'
|
||||||
|
f'.. {directive}:: {sig_g}\n'
|
||||||
|
f' :no-typesetting:\n')
|
||||||
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
assert_node(doctree, (addnodes.index, addnodes.index, nodes.target))
|
||||||
|
assert_node(doctree[0], addnodes.index, entries=[])
|
||||||
|
assert_node(doctree[1], addnodes.index, entries=[index_g])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(('directive', 'noindex', 'noindexentry', 'sig_f', 'sig_g', 'index_g'), DOMAINS)
|
||||||
|
def test_object_description_no_typesetting_noindexentry(app, directive, noindex, noindexentry, sig_f, sig_g, index_g):
|
||||||
|
if not noindexentry:
|
||||||
|
pytest.skip(f'{directive} does not support :noindexentry: option')
|
||||||
|
text = (f'.. {directive}:: {sig_f}\n'
|
||||||
|
f' :noindexentry:\n'
|
||||||
|
f' :no-typesetting:\n'
|
||||||
|
f'.. {directive}:: {sig_g}\n'
|
||||||
|
f' :no-typesetting:\n')
|
||||||
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
assert_node(doctree, (addnodes.index, addnodes.index, nodes.target, nodes.target))
|
||||||
|
assert_node(doctree[0], addnodes.index, entries=[])
|
||||||
|
assert_node(doctree[1], addnodes.index, entries=[index_g])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(('directive', 'noindex', 'noindexentry', 'sig_f', 'sig_g', 'index_g'), DOMAINS)
|
||||||
|
def test_object_description_no_typesetting_code(app, directive, noindex, noindexentry, sig_f, sig_g, index_g):
|
||||||
|
text = (f'.. {directive}:: {sig_f}\n'
|
||||||
|
f' :no-typesetting:\n'
|
||||||
|
f'.. {directive}:: {sig_g}\n'
|
||||||
|
f' :no-typesetting:\n'
|
||||||
|
f'.. code::\n'
|
||||||
|
f'\n'
|
||||||
|
f' code\n')
|
||||||
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
# Note that all index nodes come before the targets
|
||||||
|
assert_node(doctree, (addnodes.index, addnodes.index, nodes.target, nodes.target, nodes.literal_block))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(('directive', 'noindex', 'noindexentry', 'sig_f', 'sig_g', 'index_g'), DOMAINS)
|
||||||
|
def test_object_description_no_typesetting_heading(app, directive, noindex, noindexentry, sig_f, sig_g, index_g):
|
||||||
|
text = (f'.. {directive}:: {sig_f}\n'
|
||||||
|
f' :no-typesetting:\n'
|
||||||
|
f'.. {directive}:: {sig_g}\n'
|
||||||
|
f' :no-typesetting:\n'
|
||||||
|
f'\n'
|
||||||
|
f'Heading\n'
|
||||||
|
f'=======\n')
|
||||||
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
# Note that all index nodes come before the targets and the heading is floated before those.
|
||||||
|
assert_node(doctree, (nodes.title, addnodes.index, addnodes.index, nodes.target, nodes.target))
|
@ -177,11 +177,11 @@ def test_get_full_qualified_name():
|
|||||||
def test_js_module(app):
|
def test_js_module(app):
|
||||||
text = ".. js:module:: sphinx"
|
text = ".. js:module:: sphinx"
|
||||||
doctree = restructuredtext.parse(app, text)
|
doctree = restructuredtext.parse(app, text)
|
||||||
assert_node(doctree, (nodes.target,
|
assert_node(doctree, (addnodes.index,
|
||||||
addnodes.index))
|
nodes.target))
|
||||||
assert_node(doctree[0], nodes.target, ids=["module-sphinx"])
|
assert_node(doctree[0], addnodes.index,
|
||||||
assert_node(doctree[1], addnodes.index,
|
|
||||||
entries=[("single", "sphinx (module)", "module-sphinx", "", None)])
|
entries=[("single", "sphinx (module)", "module-sphinx", "", None)])
|
||||||
|
assert_node(doctree[1], nodes.target, ids=["module-sphinx"])
|
||||||
|
|
||||||
|
|
||||||
def test_js_function(app):
|
def test_js_function(app):
|
||||||
|
@ -660,9 +660,9 @@ def test_pydata(app):
|
|||||||
" :type: int\n")
|
" :type: int\n")
|
||||||
domain = app.env.get_domain('py')
|
domain = app.env.get_domain('py')
|
||||||
doctree = restructuredtext.parse(app, text)
|
doctree = restructuredtext.parse(app, text)
|
||||||
assert_node(doctree, (nodes.target,
|
assert_node(doctree, (addnodes.index,
|
||||||
addnodes.index,
|
|
||||||
addnodes.index,
|
addnodes.index,
|
||||||
|
nodes.target,
|
||||||
[desc, ([desc_signature, ([desc_addname, "example."],
|
[desc, ([desc_signature, ([desc_addname, "example."],
|
||||||
[desc_name, "var"],
|
[desc_name, "var"],
|
||||||
[desc_annotation, ([desc_sig_punctuation, ':'],
|
[desc_annotation, ([desc_sig_punctuation, ':'],
|
||||||
@ -685,9 +685,9 @@ def test_pyfunction(app):
|
|||||||
[desc, ([desc_signature, ([desc_name, "func1"],
|
[desc, ([desc_signature, ([desc_name, "func1"],
|
||||||
[desc_parameterlist, ()])],
|
[desc_parameterlist, ()])],
|
||||||
[desc_content, ()])],
|
[desc_content, ()])],
|
||||||
|
addnodes.index,
|
||||||
|
addnodes.index,
|
||||||
nodes.target,
|
nodes.target,
|
||||||
addnodes.index,
|
|
||||||
addnodes.index,
|
|
||||||
[desc, ([desc_signature, ([desc_annotation, ([desc_sig_keyword, 'async'],
|
[desc, ([desc_signature, ([desc_annotation, ([desc_sig_keyword, 'async'],
|
||||||
desc_sig_space)],
|
desc_sig_space)],
|
||||||
[desc_addname, "example."],
|
[desc_addname, "example."],
|
||||||
@ -696,9 +696,9 @@ def test_pyfunction(app):
|
|||||||
[desc_content, ()])]))
|
[desc_content, ()])]))
|
||||||
assert_node(doctree[0], addnodes.index,
|
assert_node(doctree[0], addnodes.index,
|
||||||
entries=[('pair', 'built-in function; func1()', 'func1', '', None)])
|
entries=[('pair', 'built-in function; func1()', 'func1', '', None)])
|
||||||
assert_node(doctree[3], addnodes.index,
|
assert_node(doctree[2], addnodes.index,
|
||||||
entries=[('pair', 'module; example', 'module-example', '', None)])
|
entries=[('pair', 'module; example', 'module-example', '', None)])
|
||||||
assert_node(doctree[4], addnodes.index,
|
assert_node(doctree[3], addnodes.index,
|
||||||
entries=[('single', 'func2() (in module example)', 'example.func2', '', None)])
|
entries=[('single', 'func2() (in module example)', 'example.func2', '', None)])
|
||||||
|
|
||||||
assert 'func1' in domain.objects
|
assert 'func1' in domain.objects
|
||||||
@ -1043,9 +1043,9 @@ def test_info_field_list(app):
|
|||||||
doctree = restructuredtext.parse(app, text)
|
doctree = restructuredtext.parse(app, text)
|
||||||
print(doctree)
|
print(doctree)
|
||||||
|
|
||||||
assert_node(doctree, (nodes.target,
|
assert_node(doctree, (addnodes.index,
|
||||||
addnodes.index,
|
|
||||||
addnodes.index,
|
addnodes.index,
|
||||||
|
nodes.target,
|
||||||
[desc, ([desc_signature, ([desc_annotation, ("class", desc_sig_space)],
|
[desc, ([desc_signature, ([desc_annotation, ("class", desc_sig_space)],
|
||||||
[desc_addname, "example."],
|
[desc_addname, "example."],
|
||||||
[desc_name, "Class"])],
|
[desc_name, "Class"])],
|
||||||
@ -1134,9 +1134,9 @@ def test_info_field_list_piped_type(app):
|
|||||||
doctree = restructuredtext.parse(app, text)
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
|
||||||
assert_node(doctree,
|
assert_node(doctree,
|
||||||
(nodes.target,
|
(addnodes.index,
|
||||||
addnodes.index,
|
|
||||||
addnodes.index,
|
addnodes.index,
|
||||||
|
nodes.target,
|
||||||
[desc, ([desc_signature, ([desc_annotation, ("class", desc_sig_space)],
|
[desc, ([desc_signature, ([desc_annotation, ("class", desc_sig_space)],
|
||||||
[desc_addname, "example."],
|
[desc_addname, "example."],
|
||||||
[desc_name, "Class"])],
|
[desc_name, "Class"])],
|
||||||
@ -1168,9 +1168,9 @@ def test_info_field_list_Literal(app):
|
|||||||
doctree = restructuredtext.parse(app, text)
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
|
||||||
assert_node(doctree,
|
assert_node(doctree,
|
||||||
(nodes.target,
|
(addnodes.index,
|
||||||
addnodes.index,
|
|
||||||
addnodes.index,
|
addnodes.index,
|
||||||
|
nodes.target,
|
||||||
[desc, ([desc_signature, ([desc_annotation, ("class", desc_sig_space)],
|
[desc, ([desc_signature, ([desc_annotation, ("class", desc_sig_space)],
|
||||||
[desc_addname, "example."],
|
[desc_addname, "example."],
|
||||||
[desc_name, "Class"])],
|
[desc_name, "Class"])],
|
||||||
|
96
tests/test_transforms_reorder_nodes.py
Normal file
96
tests/test_transforms_reorder_nodes.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
"""Tests the transformations"""
|
||||||
|
|
||||||
|
from docutils import nodes
|
||||||
|
|
||||||
|
from sphinx import addnodes
|
||||||
|
from sphinx.testing import restructuredtext
|
||||||
|
from sphinx.testing.util import assert_node
|
||||||
|
|
||||||
|
|
||||||
|
def test_transforms_reorder_consecutive_target_and_index_nodes_preserve_order(app):
|
||||||
|
text = ('.. index:: abc\n'
|
||||||
|
'.. index:: def\n'
|
||||||
|
'.. index:: ghi\n'
|
||||||
|
'.. index:: jkl\n'
|
||||||
|
'\n'
|
||||||
|
'text\n')
|
||||||
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
assert_node(doctree, (addnodes.index,
|
||||||
|
addnodes.index,
|
||||||
|
addnodes.index,
|
||||||
|
addnodes.index,
|
||||||
|
nodes.target,
|
||||||
|
nodes.target,
|
||||||
|
nodes.target,
|
||||||
|
nodes.target,
|
||||||
|
nodes.paragraph))
|
||||||
|
assert_node(doctree[0], addnodes.index, entries=[('single', 'abc', 'index-0', '', None)])
|
||||||
|
assert_node(doctree[1], addnodes.index, entries=[('single', 'def', 'index-1', '', None)])
|
||||||
|
assert_node(doctree[2], addnodes.index, entries=[('single', 'ghi', 'index-2', '', None)])
|
||||||
|
assert_node(doctree[3], addnodes.index, entries=[('single', 'jkl', 'index-3', '', None)])
|
||||||
|
assert_node(doctree[4], nodes.target, refid='index-0')
|
||||||
|
assert_node(doctree[5], nodes.target, refid='index-1')
|
||||||
|
assert_node(doctree[6], nodes.target, refid='index-2')
|
||||||
|
assert_node(doctree[7], nodes.target, refid='index-3')
|
||||||
|
# assert_node(doctree[8], nodes.paragraph)
|
||||||
|
|
||||||
|
|
||||||
|
def test_transforms_reorder_consecutive_target_and_index_nodes_no_merge_across_other_nodes(app):
|
||||||
|
text = ('.. index:: abc\n'
|
||||||
|
'.. index:: def\n'
|
||||||
|
'\n'
|
||||||
|
'text\n'
|
||||||
|
'\n'
|
||||||
|
'.. index:: ghi\n'
|
||||||
|
'.. index:: jkl\n'
|
||||||
|
'\n'
|
||||||
|
'text\n')
|
||||||
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
assert_node(doctree, (addnodes.index,
|
||||||
|
addnodes.index,
|
||||||
|
nodes.target,
|
||||||
|
nodes.target,
|
||||||
|
nodes.paragraph,
|
||||||
|
addnodes.index,
|
||||||
|
addnodes.index,
|
||||||
|
nodes.target,
|
||||||
|
nodes.target,
|
||||||
|
nodes.paragraph))
|
||||||
|
assert_node(doctree[0], addnodes.index, entries=[('single', 'abc', 'index-0', '', None)])
|
||||||
|
assert_node(doctree[1], addnodes.index, entries=[('single', 'def', 'index-1', '', None)])
|
||||||
|
assert_node(doctree[2], nodes.target, refid='index-0')
|
||||||
|
assert_node(doctree[3], nodes.target, refid='index-1')
|
||||||
|
# assert_node(doctree[4], nodes.paragraph)
|
||||||
|
assert_node(doctree[5], addnodes.index, entries=[('single', 'ghi', 'index-2', '', None)])
|
||||||
|
assert_node(doctree[6], addnodes.index, entries=[('single', 'jkl', 'index-3', '', None)])
|
||||||
|
assert_node(doctree[7], nodes.target, refid='index-2')
|
||||||
|
assert_node(doctree[8], nodes.target, refid='index-3')
|
||||||
|
# assert_node(doctree[9], nodes.paragraph)
|
||||||
|
|
||||||
|
|
||||||
|
def test_transforms_reorder_consecutive_target_and_index_nodes_merge_with_labels(app):
|
||||||
|
text = ('.. _abc:\n'
|
||||||
|
'.. index:: def\n'
|
||||||
|
'.. _ghi:\n'
|
||||||
|
'.. index:: jkl\n'
|
||||||
|
'.. _mno:\n'
|
||||||
|
'\n'
|
||||||
|
'Heading\n'
|
||||||
|
'=======\n')
|
||||||
|
doctree = restructuredtext.parse(app, text)
|
||||||
|
assert_node(doctree, (nodes.title,
|
||||||
|
addnodes.index,
|
||||||
|
addnodes.index,
|
||||||
|
nodes.target,
|
||||||
|
nodes.target,
|
||||||
|
nodes.target,
|
||||||
|
nodes.target,
|
||||||
|
nodes.target))
|
||||||
|
# assert_node(doctree[8], nodes.title)
|
||||||
|
assert_node(doctree[1], addnodes.index, entries=[('single', 'def', 'index-0', '', None)])
|
||||||
|
assert_node(doctree[2], addnodes.index, entries=[('single', 'jkl', 'index-1', '', None)])
|
||||||
|
assert_node(doctree[3], nodes.target, refid='abc')
|
||||||
|
assert_node(doctree[4], nodes.target, refid='index-0')
|
||||||
|
assert_node(doctree[5], nodes.target, refid='ghi')
|
||||||
|
assert_node(doctree[6], nodes.target, refid='index-1')
|
||||||
|
assert_node(doctree[7], nodes.target, refid='mno')
|
Loading…
Reference in New Issue
Block a user