Fix #9240: Unknown node error for pending_xref_condition is raised

Unknown node error for pending_xref_condition is raised if an extension
that does not support the node installs a missing-reference handler.
This commit is contained in:
Takeshi KOMIYA 2021-05-18 01:09:42 +09:00
parent 630e5bd15f
commit 2d3d668856
5 changed files with 85 additions and 9 deletions

View File

@ -10,6 +10,8 @@ Incompatible changes
* #9222: Update Underscore.js to 1.13.1
* #9217: manpage: Stop creating a section directory on build manpage by default
(see :confval:`man_make_section_directory`)
* #9240: Unknown node error for pending_xref_condition is raised if an extension
that does not support the node installs a missing-reference handler
Deprecated
----------

View File

@ -8,10 +8,10 @@
:license: BSD, see LICENSE for details.
"""
from typing import Any, Dict, List, Optional, Tuple, Type, cast
from typing import Any, Dict, List, Optional, Sequence, Tuple, Type, cast
from docutils import nodes
from docutils.nodes import Element
from docutils.nodes import Element, Node
from sphinx import addnodes
from sphinx.addnodes import pending_xref
@ -26,10 +26,6 @@ from sphinx.util.nodes import find_pending_xref_condition, process_only_nodes
logger = logging.getLogger(__name__)
if False:
# For type annotation
from docutils.nodes import Node
class SphinxPostTransform(SphinxTransform):
"""A base class of post-transforms.
@ -71,7 +67,12 @@ class ReferencesResolver(SphinxPostTransform):
def run(self, **kwargs: Any) -> None:
for node in self.document.traverse(addnodes.pending_xref):
contnode = cast(nodes.TextElement, node[0].deepcopy())
content = self.find_pending_xref_condition(node, ("resolved", "*"))
if content:
contnode = cast(Element, content[0].deepcopy())
else:
contnode = cast(Element, node[0].deepcopy())
newnode = None
typ = node['reftype']
@ -108,9 +109,9 @@ class ReferencesResolver(SphinxPostTransform):
else:
newnodes = [contnode]
if newnode is None and isinstance(node[0], addnodes.pending_xref_condition):
matched = find_pending_xref_condition(node, "*")
matched = self.find_pending_xref_condition(node, ("*",))
if matched:
newnodes = matched.children
newnodes = matched
else:
logger.warning(__('Could not determine the fallback text for the '
'cross-reference. Might be a bug.'), location=node)
@ -193,6 +194,15 @@ class ReferencesResolver(SphinxPostTransform):
msg = __('%r reference target not found: %s') % (typ, target)
logger.warning(msg, location=node, type='ref', subtype=typ)
def find_pending_xref_condition(self, node: pending_xref, conditions: Sequence[str]
) -> Optional[List[Node]]:
for condition in conditions:
matched = find_pending_xref_condition(node, condition)
if matched:
return matched.children
else:
return None
class OnlyNodeTransform(SphinxPostTransform):
default_priority = 50

View File

@ -0,0 +1 @@
nitpicky = True

View File

@ -0,0 +1,5 @@
transforms-post_transforms-missing-reference
============================================
:class:`io.StringIO`

View File

@ -0,0 +1,58 @@
"""
test_transforms_post_transforms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tests the post_transforms
:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import pytest
from docutils import nodes
@pytest.mark.sphinx('html', testroot='transforms-post_transforms-missing-reference')
def test_nitpicky_warning(app, status, warning):
app.build()
assert ('index.rst:4: WARNING: py:class reference target '
'not found: io.StringIO' in warning.getvalue())
content = (app.outdir / 'index.html').read_text()
assert ('<p><code class="xref py py-class docutils literal notranslate"><span class="pre">'
'io.StringIO</span></code></p>' in content)
@pytest.mark.sphinx('html', testroot='transforms-post_transforms-missing-reference',
freshenv=True)
def test_missing_reference(app, status, warning):
def missing_reference(app, env, node, contnode):
assert app is app
assert env is app.env
assert node['reftarget'] == 'io.StringIO'
assert contnode.astext() == 'io.StringIO'
return nodes.inline('', 'missing-reference.StringIO')
warning.truncate(0)
app.connect('missing-reference', missing_reference)
app.build()
assert warning.getvalue() == ''
content = (app.outdir / 'index.html').read_text()
assert '<p><span>missing-reference.StringIO</span></p>' in content
@pytest.mark.sphinx('html', testroot='domain-py-python_use_unqualified_type_names',
freshenv=True)
def test_missing_reference_conditional_pending_xref(app, status, warning):
def missing_reference(app, env, node, contnode):
return contnode
warning.truncate(0)
app.connect('missing-reference', missing_reference)
app.build()
assert warning.getvalue() == ''
content = (app.outdir / 'index.html').read_text()
assert '<span class="n"><span class="pre">Age</span></span>' in content